From 30d06a269452b2a7d3c567cb448825eefaf100dc Mon Sep 17 00:00:00 2001
From: Jusheng Huang <117657272+viajes7@users.noreply.github.com>
Date: Thu, 3 Oct 2024 08:24:46 +0800
Subject: [PATCH] [Dashboard] Fix share dashboard iframe embed code incorrectly
(#194366)
## Summary
Fixes [#192980](https://github.com/elastic/kibana/issues/193447)
Maybe related pr: #179037
After fix it, having an URL that is like this:
```
?embed=true&_g=(refreshInterval%3A(pause%3A!t%2Cvalue%3A60000)%2Ctime%3A(from%3Anow-15m%2Cto%3Anow))&hide-filter-bar=true
```
**Screenshot**
---------
Co-authored-by: Elastic Machine
Co-authored-by: Tim Sullivan
(cherry picked from commit e4ff3bb44874f77a63c24de998fde2f6d7ac9404)
---
.../share/public/components/context/index.tsx | 1 -
.../public/components/share_tabs.test.tsx | 1 -
.../tabs/embed/embed_content.test.tsx | 56 +++++++++++++++++++
.../components/tabs/embed/embed_content.tsx | 22 +++++---
.../public/components/tabs/embed/index.tsx | 11 +---
.../public/services/share_menu_manager.tsx | 1 -
6 files changed, 73 insertions(+), 19 deletions(-)
create mode 100644 src/plugins/share/public/components/tabs/embed/embed_content.test.tsx
diff --git a/src/plugins/share/public/components/context/index.tsx b/src/plugins/share/public/components/context/index.tsx
index 430c440311871..7d858bf0665fa 100644
--- a/src/plugins/share/public/components/context/index.tsx
+++ b/src/plugins/share/public/components/context/index.tsx
@@ -29,7 +29,6 @@ export interface IShareContext extends ShareContext {
anonymousAccess?: AnonymousAccessServiceContract;
urlService: BrowserUrlService;
snapshotShareWarning?: string;
- isEmbedded: boolean;
theme: ThemeServiceSetup;
i18n: I18nStart;
publicAPIEnabled?: boolean;
diff --git a/src/plugins/share/public/components/share_tabs.test.tsx b/src/plugins/share/public/components/share_tabs.test.tsx
index 30ba660168e90..52e73d7f1b5d3 100644
--- a/src/plugins/share/public/components/share_tabs.test.tsx
+++ b/src/plugins/share/public/components/share_tabs.test.tsx
@@ -53,7 +53,6 @@ const mockShareContext = {
allowShortUrl: true,
anonymousAccess: { getCapabilities: jest.fn(), getState: jest.fn() },
urlService: service,
- isEmbedded: true,
theme: themeServiceMock.createStartContract(),
objectTypeMeta: { title: 'title' },
objectType: 'type',
diff --git a/src/plugins/share/public/components/tabs/embed/embed_content.test.tsx b/src/plugins/share/public/components/tabs/embed/embed_content.test.tsx
new file mode 100644
index 0000000000000..be3d8c941b8ea
--- /dev/null
+++ b/src/plugins/share/public/components/tabs/embed/embed_content.test.tsx
@@ -0,0 +1,56 @@
+/*
+ * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+import { mountWithIntl } from '@kbn/test-jest-helpers';
+import { EmbedContent } from './embed_content';
+import React from 'react';
+import { ReactWrapper } from 'enzyme';
+
+describe('Share modal embed content tab', () => {
+ describe('share url embedded', () => {
+ let component: ReactWrapper;
+
+ beforeEach(() => {
+ component = mountWithIntl(
+ jest.fn()}
+ shareableUrl="/home#/"
+ />
+ );
+ });
+
+ it('works for simple url', async () => {
+ component.setProps({ shareableUrl: 'http://localhost:5601/app/home#/' });
+ component.update();
+
+ const shareUrl = component
+ .find('button[data-test-subj="copyEmbedUrlButton"]')
+ .prop('data-share-url');
+ expect(shareUrl).toBe(
+ ''
+ );
+ });
+
+ it('works if the url has a query string', async () => {
+ component.setProps({
+ shareableUrl:
+ 'http://localhost:5601/app/dashboards#/create?_g=(refreshInterval%3A(pause%3A!t%2Cvalue%3A60000)%2Ctime%3A(from%3Anow-15m%2Cto%3Anow))',
+ });
+ component.update();
+
+ const shareUrl = component
+ .find('button[data-test-subj="copyEmbedUrlButton"]')
+ .prop('data-share-url');
+ expect(shareUrl).toBe(
+ ''
+ );
+ });
+ });
+});
diff --git a/src/plugins/share/public/components/tabs/embed/embed_content.tsx b/src/plugins/share/public/components/tabs/embed/embed_content.tsx
index adc239b11140d..557a499a38021 100644
--- a/src/plugins/share/public/components/tabs/embed/embed_content.tsx
+++ b/src/plugins/share/public/components/tabs/embed/embed_content.tsx
@@ -30,7 +30,6 @@ type EmbedProps = Pick<
| 'shareableUrlLocatorParams'
| 'shareableUrlForSavedObject'
| 'shareableUrl'
- | 'isEmbedded'
| 'embedUrlParamExtensions'
| 'objectType'
> & {
@@ -52,7 +51,6 @@ export const EmbedContent = ({
embedUrlParamExtensions: urlParamExtensions,
shareableUrlForSavedObject,
shareableUrl,
- isEmbedded,
objectType,
setIsNotSaved,
}: EmbedProps) => {
@@ -69,6 +67,17 @@ export const EmbedContent = ({
if (objectType !== 'dashboard') setIsNotSaved();
}, [url, setIsNotSaved, objectType]);
+ const makeUrlEmbeddable = useCallback((tempUrl: string): string => {
+ const embedParam = '?embed=true';
+ const urlHasQueryString = tempUrl.indexOf('?') !== -1;
+
+ if (urlHasQueryString) {
+ return tempUrl.replace('?', `${embedParam}&`);
+ }
+
+ return `${tempUrl}${embedParam}`;
+ }, []);
+
const getUrlParamExtensions = useCallback(
(tempUrl: string): string => {
return urlParams
@@ -90,10 +99,11 @@ export const EmbedContent = ({
const updateUrlParams = useCallback(
(tempUrl: string) => {
+ tempUrl = makeUrlEmbeddable(tempUrl);
tempUrl = urlParams ? getUrlParamExtensions(tempUrl) : tempUrl;
return tempUrl;
},
- [getUrlParamExtensions, urlParams]
+ [makeUrlEmbeddable, getUrlParamExtensions, urlParams]
);
const getSnapshotUrl = useCallback(
@@ -180,16 +190,14 @@ export const EmbedContent = ({
tempUrl = addUrlAnonymousAccessParameters(tempUrl!);
}
- if (isEmbedded) {
- tempUrl = makeIframeTag(tempUrl!);
- }
+ tempUrl = makeIframeTag(tempUrl!);
+
setUrl(tempUrl!);
}, [
addUrlAnonymousAccessParameters,
exportUrlAs,
getSavedObjectUrl,
getSnapshotUrl,
- isEmbedded,
shortUrlCache,
useShortUrl,
]);
diff --git a/src/plugins/share/public/components/tabs/embed/index.tsx b/src/plugins/share/public/components/tabs/embed/index.tsx
index 2a81e42518180..3c66b48f21c8c 100644
--- a/src/plugins/share/public/components/tabs/embed/index.tsx
+++ b/src/plugins/share/public/components/tabs/embed/index.tsx
@@ -38,14 +38,8 @@ const embedTabReducer: IEmbedTab['reducer'] = (state = { url: '', isNotSaved: fa
};
const EmbedTabContent: NonNullable = ({ state, dispatch }) => {
- const {
- embedUrlParamExtensions,
- shareableUrlForSavedObject,
- shareableUrl,
- isEmbedded,
- objectType,
- isDirty,
- } = useShareTabsContext()!;
+ const { embedUrlParamExtensions, shareableUrlForSavedObject, shareableUrl, objectType, isDirty } =
+ useShareTabsContext()!;
const setIsNotSaved = useCallback(() => {
dispatch({
@@ -60,7 +54,6 @@ const EmbedTabContent: NonNullable = ({ state, dispatch })
embedUrlParamExtensions,
shareableUrlForSavedObject,
shareableUrl,
- isEmbedded,
objectType,
isNotSaved: state?.isNotSaved,
setIsNotSaved,
diff --git a/src/plugins/share/public/services/share_menu_manager.tsx b/src/plugins/share/public/services/share_menu_manager.tsx
index 05ec372d51143..6f7a90bd9aa5e 100644
--- a/src/plugins/share/public/services/share_menu_manager.tsx
+++ b/src/plugins/share/public/services/share_menu_manager.tsx
@@ -129,7 +129,6 @@ export class ShareMenuManager {
snapshotShareWarning,
disabledShareUrl,
isDirty,
- isEmbedded: allowEmbed,
shareMenuItems: menuItems,
toasts,
onClose: () => {