Skip to content

Commit 32dcfe3

Browse files
authored
[SharedUX] Clean up share draft mode callout component override logic (#240958)
Closes #238877 ## Summary - Cleaned up `DraftModeCallout` component override logic which allowed for any ReactNode element to be rendered inside the share modal as part of the effort to unify the callout's UI across Kibana. - Updated Dashboards `show_share_modal` logic to use the new types and props. These changes had originally been reviewed as part of this PR #236719 but were removed to avoid conflicts with #233552 ### Testing | Before | After | | --- | --- | | <img width="532" height="480" alt="Screenshot 2025-10-28 at 11 25 24" src="https://github.com/user-attachments/assets/f8c4fa36-3c49-4ec8-be01-45e0dd5e9962" /> | <img width="535" height="488" alt="Screenshot 2025-10-28 at 11 20 34" src="https://github.com/user-attachments/assets/130aa891-08bc-45e1-b950-379a27e9892f" /> | | <img width="530" height="570" alt="Screenshot 2025-10-28 at 11 26 24" src="https://github.com/user-attachments/assets/0f23a89e-7af6-4ae1-afc0-7fdca5bbdd8b" /> | <img width="521" height="561" alt="Screenshot 2025-10-28 at 11 22 33" src="https://github.com/user-attachments/assets/e8d166a0-b789-4a15-aad0-097f4d26b590" /> | | <img width="502" height="759" alt="Screenshot 2025-10-28 at 11 25 46" src="https://github.com/user-attachments/assets/0bb614ba-8ce9-47bb-92e4-8b3ef10c5752" /> | <img width="510" height="792" alt="Screenshot 2025-10-28 at 11 20 51" src="https://github.com/user-attachments/assets/b6375be5-e50b-4ea1-b3af-9d951395137a" /> |
1 parent b44202b commit 32dcfe3

9 files changed

Lines changed: 27 additions & 136 deletions

File tree

src/platform/plugins/shared/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx

Lines changed: 17 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ import moment from 'moment';
1212
import type { ReactElement } from 'react';
1313
import React, { useState } from 'react';
1414

15-
import { EuiCallOut, EuiCheckboxGroup } from '@elastic/eui';
15+
import { EuiCheckboxGroup } from '@elastic/eui';
1616
import type { Capabilities } from '@kbn/core/public';
1717
import type { QueryState } from '@kbn/data-plugin/common';
1818
import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics';
1919
import { i18n } from '@kbn/i18n';
20-
import { FormattedMessage } from '@kbn/i18n-react';
2120
import { getStateFromKbnUrl, setStateToKbnUrl, unhashUrl } from '@kbn/kibana-utils-plugin/public';
2221
import type { LocatorPublic } from '@kbn/share-plugin/common';
2322

@@ -164,42 +163,22 @@ export function ShowShareModal({
164163
}),
165164
config: {
166165
link: {
167-
draftModeCallOut: (
168-
<EuiCallOut
169-
color="warning"
170-
data-test-subj="DashboardDraftModeCopyLinkCallOut"
171-
title={
172-
<FormattedMessage
173-
id="dashboard.share.shareModal.draftModeCallout.title"
174-
defaultMessage="Unsaved changes"
175-
/>
176-
}
177-
>
178-
{hasPanelChanges
179-
? allowShortUrl
180-
? shareModalStrings.getDraftSharePanelChangesWarning()
181-
: shareModalStrings.getSnapshotShareWarning()
182-
: shareModalStrings.getDraftShareWarning('link')}
183-
</EuiCallOut>
184-
),
166+
draftModeCallOut: {
167+
message: hasPanelChanges
168+
? allowShortUrl
169+
? shareModalStrings.getDraftSharePanelChangesWarning()
170+
: shareModalStrings.getSnapshotShareWarning()
171+
: shareModalStrings.getDraftShareWarning('link'),
172+
'data-test-subj': 'DashboardDraftModeCopyLinkCallOut',
173+
},
185174
},
186175
embed: {
187-
draftModeCallOut: (
188-
<EuiCallOut
189-
color="warning"
190-
data-test-subj="DashboardDraftModeEmbedCallOut"
191-
title={
192-
<FormattedMessage
193-
id="dashboard.share.shareModal.draftModeCallout.title"
194-
defaultMessage="Unsaved changes"
195-
/>
196-
}
197-
>
198-
{hasPanelChanges
199-
? shareModalStrings.getEmbedSharePanelChangesWarning()
200-
: shareModalStrings.getDraftShareWarning('embed')}
201-
</EuiCallOut>
202-
),
176+
draftModeCallOut: {
177+
message: hasPanelChanges
178+
? shareModalStrings.getEmbedSharePanelChangesWarning()
179+
: shareModalStrings.getDraftShareWarning('embed'),
180+
'data-test-subj': 'DashboardDraftModeEmbedCallOut',
181+
},
203182
embedUrlParamExtensions: [
204183
{
205184
paramName: 'embed',
@@ -211,42 +190,10 @@ export function ShowShareModal({
211190
integration: {
212191
export: {
213192
pdfReports: {
214-
draftModeCallOut: (
215-
<EuiCallOut
216-
color="warning"
217-
iconType="warning"
218-
title={
219-
<FormattedMessage
220-
id="dashboard.exports.pdfReports.warning.title"
221-
defaultMessage="Unsaved changes"
222-
/>
223-
}
224-
>
225-
<FormattedMessage
226-
id="dashboard.exports.pdfReports.postURLWatcherMessage.unsavedChanges"
227-
defaultMessage="URL may change if you upgrade Kibana."
228-
/>
229-
</EuiCallOut>
230-
),
193+
draftModeCallOut: true,
231194
},
232195
imageReports: {
233-
draftModeCallOut: (
234-
<EuiCallOut
235-
color="warning"
236-
iconType="warning"
237-
title={
238-
<FormattedMessage
239-
id="dashboard.exports.imageReports.warning.title"
240-
defaultMessage="Unsaved changes"
241-
/>
242-
}
243-
>
244-
<FormattedMessage
245-
id="dashboard.exports.imageReports.postURLWatcherMessage.unsavedChanges"
246-
defaultMessage="URL may change if you upgrade Kibana."
247-
/>
248-
</EuiCallOut>
249-
),
196+
draftModeCallOut: true,
250197
},
251198
},
252199
},

src/platform/plugins/shared/share/public/components/common/draft_mode_callout/__snapshots__/draft_mode_callout.test.tsx.snap

Lines changed: 0 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/platform/plugins/shared/share/public/components/common/draft_mode_callout/draft_mode_callout.test.tsx

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,6 @@ describe('DraftModeCallout', () => {
3131
});
3232
});
3333

34-
describe('Node override case', () => {
35-
it('renders a component override when a node prop is provided', () => {
36-
render(
37-
<DraftModeCallout
38-
node={<p data-test-subj="overriddenDraftModeCallOut">Component override</p>}
39-
/>
40-
);
41-
const callout = screen.getByTestId('overriddenDraftModeCallOut');
42-
expect(screen.getByText('Component override')).toBeInTheDocument();
43-
expect(callout).toMatchSnapshot();
44-
});
45-
});
46-
4734
describe('Save button case', () => {
4835
it('renders a save button when onSave is present', () => {
4936
render(<DraftModeCallout saveButtonProps={{ onSave: jest.fn() }} />);

src/platform/plugins/shared/share/public/components/common/draft_mode_callout/draft_mode_callout.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,18 @@
77
* License v3.0 only", or the "Server Side Public License, v 1".
88
*/
99

10-
import React, { type ReactNode } from 'react';
10+
import React from 'react';
1111
import { i18n } from '@kbn/i18n';
1212
import type { CommonProps } from '@elastic/eui';
1313
import { EuiButton, EuiCallOut, EuiText } from '@elastic/eui';
1414

1515
export interface SaveButtonProps extends CommonProps {
16-
onSave: () => Promise<void | object>;
16+
onSave: () => Promise<void>;
1717
label?: string;
1818
isSaving?: boolean;
1919
}
2020
export interface DraftModeCalloutProps extends CommonProps {
2121
message?: string;
22-
node?: ReactNode;
2322
saveButtonProps?: SaveButtonProps;
2423
}
2524

@@ -36,14 +35,11 @@ const saveButtonText = i18n.translate('share.draftModeCallout.saveButtonText', {
3635
* A warning callout to indicate the user has unsaved changes.
3736
*/
3837
export const DraftModeCallout = ({
39-
node,
4038
message = defaultCalloutMessage,
4139
['data-test-subj']: dataTestSubj = 'unsavedChangesDraftModeCallOut',
4240
saveButtonProps,
4341
}: DraftModeCalloutProps) => {
44-
return node ? (
45-
node
46-
) : (
42+
return (
4743
<EuiCallOut
4844
announceOnMount
4945
data-test-subj={dataTestSubj}

src/platform/plugins/shared/share/public/components/context/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const ShareProvider = ({
4747
const value: IShareContext = {
4848
...shareContext,
4949
isDirty: isStateful ? internalIsDirty : shareContext.isDirty,
50-
isSaving: isStateful ? isSaving : undefined,
50+
isSaving,
5151
onSave: isStateful ? handleSave : undefined,
5252
};
5353

src/platform/plugins/shared/share/public/components/export_integrations/export_integrations.tsx

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import {
4040
useShareContext,
4141
} from '../context';
4242
import type { ExportShareConfig, ExportShareDerivativesConfig } from '../../types';
43-
import type { DraftModeCalloutProps } from '../common/draft_mode_callout';
4443
import { DraftModeCallout } from '../common/draft_mode_callout';
4544

4645
export const ExportMenu: FC<{ shareContext: IShareContext }> = ({ shareContext }) => {
@@ -71,7 +70,7 @@ interface ManagedFlyoutProps {
7170
shareObjectTypeMeta: ReturnType<
7271
typeof useShareTypeContext<'integration', 'export'>
7372
>['objectTypeMeta'];
74-
onSave?: () => Promise<void | object>;
73+
onSave?: () => Promise<void>;
7574
isSaving?: boolean;
7675
}
7776

@@ -154,16 +153,7 @@ function ManagedFlyout({
154153
}, [exportIntegration.config, intl, onCloseFlyout, usePrintLayout]);
155154

156155
const draftModeCallout = shareObjectTypeMeta.config?.[exportIntegration.id]?.draftModeCallOut;
157-
// TODO Remove node override logic https://github.com/elastic/kibana/issues/238877
158-
const isValidCalloutOverride = React.isValidElement(draftModeCallout);
159-
const draftModeCalloutContent = isValidCalloutOverride
160-
? // Retro-compatible case
161-
{ node: draftModeCallout }
162-
: typeof draftModeCallout === 'object'
163-
? // Custom content callout
164-
(draftModeCallout as DraftModeCalloutProps)
165-
: // Default content callout
166-
{};
156+
const draftModeCalloutContent = typeof draftModeCallout === 'object' ? draftModeCallout : {};
167157

168158
return (
169159
<React.Fragment>

src/platform/plugins/shared/share/public/components/tabs/embed/embed_content.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import type { AnonymousAccessState } from '../../../../common';
2929

3030
import { useShareContext, type IShareContext } from '../../context';
3131
import type { EmbedShareConfig, EmbedShareUIConfig } from '../../../types';
32-
import type { DraftModeCalloutProps } from '../../common/draft_mode_callout';
3332
import { DraftModeCallout } from '../../common/draft_mode_callout';
3433

3534
type EmbedProps = Pick<
@@ -84,16 +83,7 @@ export const EmbedContent = ({
8483
computeAnonymousCapabilities,
8584
embedUrlParamExtensions: urlParamExtensions,
8685
} = objectConfig;
87-
// TODO Remove node override logic https://github.com/elastic/kibana/issues/238877
88-
const isValidCalloutOverride = React.isValidElement(draftModeCallOut);
89-
const draftModeCalloutContent = isValidCalloutOverride
90-
? // Retro-compatible case
91-
{ node: draftModeCallOut }
92-
: typeof draftModeCallOut === 'object'
93-
? // Custom content callout
94-
(draftModeCallOut as DraftModeCalloutProps)
95-
: // Default content callout
96-
{};
86+
const draftModeCalloutContent = typeof draftModeCallOut === 'object' ? draftModeCallOut : {};
9787

9888
useEffect(() => {
9989
if (computeAnonymousCapabilities && anonymousAccess) {

src/platform/plugins/shared/share/public/components/tabs/link/link_content.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import React, { useCallback, useState, useRef, useEffect } from 'react';
2323
import { TimeTypeSection } from './time_type_section';
2424
import { useShareContext, type IShareContext } from '../../context';
2525
import type { LinkShareConfig, LinkShareUIConfig } from '../../../types';
26-
import type { DraftModeCalloutProps } from '../../common/draft_mode_callout';
2726
import { DraftModeCallout } from '../../common/draft_mode_callout';
2827

2928
type LinkProps = Pick<
@@ -65,16 +64,7 @@ export const LinkContent = ({
6564
const timeRange = shareableUrlLocatorParams?.params?.timeRange;
6665

6766
const { delegatedShareUrlHandler, draftModeCallOut } = objectConfig;
68-
// TODO Remove node override logic https://github.com/elastic/kibana/issues/238877
69-
const isValidCalloutOverride = React.isValidElement(draftModeCallOut);
70-
const draftModeCalloutContent = isValidCalloutOverride
71-
? // Retro-compatible case
72-
{ node: draftModeCallOut }
73-
: typeof draftModeCallOut === 'object'
74-
? // Custom content callout
75-
(draftModeCallOut as DraftModeCalloutProps)
76-
: // Default content callout
77-
{};
67+
const draftModeCalloutContent = typeof draftModeCallOut === 'object' ? draftModeCallOut : {};
7868

7969
const getUrlWithUpdatedParams = useCallback((tempUrl: string): string => {
8070
const urlWithUpdatedParams = urlParamsRef.current

src/platform/plugins/shared/share/public/types.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ type ShareActionUserInputBase<E extends Record<string, unknown> = Record<string,
4343
* - `message`: callout message custom content
4444
*/
4545

46-
// TODO Remove ReactNode type https://github.com/elastic/kibana/issues/238877
47-
draftModeCallOut?: boolean | DraftModeCalloutProps | ReactNode;
46+
draftModeCallOut?: boolean | DraftModeCalloutProps;
4847
helpText?: ReactNode;
4948
CTAButtonConfig?: {
5049
id: string;
@@ -397,7 +396,7 @@ export interface ShowShareMenuOptions extends Omit<ShareContext, 'onClose'> {
397396
allowShortUrl: boolean;
398397
onClose?: () => void;
399398
publicAPIEnabled?: boolean;
400-
onSave?: () => Promise<void | object>;
399+
onSave?: () => Promise<void>;
401400
}
402401

403402
export interface ClientConfigType {

0 commit comments

Comments
 (0)