Skip to content

Commit

Permalink
[ui_actions] replace subscribeToCompatibilityChanges with getCompatib…
Browse files Browse the repository at this point in the history
…ilityChangesSubject (elastic#210693)

Closes elastic#206104

PR replaces `action.subscribeToCompatibilityChanges` with
`action.getCompatibilityChangesSubject`

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Devon Thomson <devon.thomson@elastic.co>
  • Loading branch information
4 people authored Feb 20, 2025
1 parent ce42a8c commit 0fb26ea
Show file tree
Hide file tree
Showing 19 changed files with 177 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { Action } from '@kbn/ui-actions-plugin/public';
import { apiHasVisualizeConfig, HasVisualizeConfig } from '@kbn/visualizations-plugin/public';

import { map } from 'rxjs';
import { INPUT_CONTROL_VIS_TYPE } from './input_control_vis_type';

const ACTION_DEPRECATION_BADGE = 'ACTION_INPUT_CONTROL_DEPRECATION_BADGE';
Expand Down Expand Up @@ -66,14 +67,10 @@ export class InputControlDeprecationBadge implements Action<EmbeddableApiContext
return isApiCompatible(embeddable) && embeddable.getVis().type.name === INPUT_CONTROL_VIS_TYPE;
}

public subscribeToCompatibilityChanges(
{ embeddable }: EmbeddableApiContext,
onChange: (isCompatible: boolean, action: Action<EmbeddableApiContext>) => void
) {
if (!isApiCompatible(embeddable)) return;
return getViewModeSubject(embeddable)?.subscribe(() => {
onChange(compatibilityCheck(embeddable), this);
});
public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) {
return isApiCompatible(embeddable)
? getViewModeSubject(embeddable)?.pipe(map(() => undefined))
: undefined;
}

public async execute() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import { Filter, TimeRange, type AggregateQuery, type Query } from '@kbn/es-query';

import { PublishesUnifiedSearch } from '@kbn/presentation-publishing';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, take } from 'rxjs';
import { CustomTimeRangeBadge } from './custom_time_range_badge';

const mockTimeRange: TimeRange = { from: 'now-17m', to: 'now' };
Expand Down Expand Up @@ -45,11 +45,12 @@ describe('custom time range badge action', () => {
expect(await action.isCompatible(emptyContext)).toBe(false);
});

it('calls onChange when time range changes', () => {
const onChange = jest.fn();
it('getCompatibilityChangesSubject emits when time range changes', (done) => {
updateTimeRange(mockTimeRange);
action.subscribeToCompatibilityChanges(context, onChange);
const subject = action.getCompatibilityChangesSubject(context);
subject?.pipe(take(1)).subscribe(() => {
done();
});
updateTimeRange(undefined);
expect(onChange).toHaveBeenCalledWith(false, action);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import React from 'react';

import { UI_SETTINGS } from '@kbn/data-plugin/common';
import { apiPublishesTimeRange, EmbeddableApiContext } from '@kbn/presentation-publishing';
import { map } from 'rxjs';
import { ACTION_CUSTOMIZE_PANEL, CUSTOM_TIME_RANGE_BADGE } from './constants';
import { core, uiActions } from '../../kibana_services';

Expand Down Expand Up @@ -58,14 +59,10 @@ export class CustomTimeRangeBadge
return apiPublishesTimeRange(embeddable);
}

public subscribeToCompatibilityChanges(
{ embeddable }: EmbeddableApiContext,
onChange: (isCompatible: boolean, action: CustomTimeRangeBadge) => void
) {
if (!apiPublishesTimeRange(embeddable)) return;
return embeddable.timeRange$.subscribe((timeRange) => {
onChange(Boolean(timeRange), this);
});
public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) {
return apiPublishesTimeRange(embeddable)
? embeddable.timeRange$.pipe(map(() => undefined))
: undefined;
}

public async execute(context: ActionExecutionMeta & EmbeddableApiContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import { PublishesViewMode, ViewMode } from '@kbn/presentation-publishing';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, take } from 'rxjs';
import { EditPanelAction, EditPanelActionApi } from './edit_panel_action';

describe('Edit panel action', () => {
Expand Down Expand Up @@ -63,10 +63,11 @@ describe('Edit panel action', () => {
expect(await action.getHref(context)).toBe(href);
});

it('calls onChange when view mode changes', () => {
const onChange = jest.fn();
action.subscribeToCompatibilityChanges(context, onChange);
it('getCompatibilityChangesSubject emits when view mode changes', (done) => {
const subject = action.getCompatibilityChangesSubject(context);
subject?.pipe(take(1)).subscribe(() => {
done();
});
setViewMode('view');
expect(onChange).toHaveBeenCalledWith(false, action);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
FrequentCompatibilityChangeAction,
IncompatibleActionError,
} from '@kbn/ui-actions-plugin/public';
import { map } from 'rxjs';
import { ACTION_EDIT_PANEL } from './constants';

export type EditPanelActionApi = CanAccessViewMode & HasEditCapabilities;
Expand Down Expand Up @@ -50,18 +51,10 @@ export class EditPanelAction
});
}

public subscribeToCompatibilityChanges(
{ embeddable }: EmbeddableApiContext,
onChange: (isCompatible: boolean, action: Action<EmbeddableApiContext>) => void
) {
if (!isApiCompatible(embeddable)) return;
return getViewModeSubject(embeddable)?.subscribe((viewMode) => {
if (viewMode === 'edit' && isApiCompatible(embeddable) && embeddable.isEditingEnabled()) {
onChange(true, this);
return;
}
onChange(false, this);
});
public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) {
return isApiCompatible(embeddable)
? getViewModeSubject(embeddable)?.pipe(map(() => undefined))
: undefined;
}

public couldBecomeCompatible({ embeddable }: EmbeddableApiContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {
ViewMode,
} from '@kbn/presentation-publishing';
import { ActionWithContext } from '@kbn/ui-actions-plugin/public/context_menu/build_eui_context_menu_panels';
import { Subscription } from 'rxjs';
import { Subscription, switchMap } from 'rxjs';
import { uiActions } from '../../kibana_services';
import {
CONTEXT_MENU_TRIGGER,
Expand Down Expand Up @@ -188,17 +188,24 @@ export const PresentationPanelHoverActions = ({

for (const frequentlyChangingAction of frequentlyChangingActions) {
if ((quickActionIds as readonly string[]).includes(frequentlyChangingAction.id)) {
subscriptions.add(
frequentlyChangingAction.subscribeToCompatibilityChanges(
apiContext,
(isCompatible, action) =>
handleActionCompatibilityChange(
'quickActions',
isCompatible,
action as AnyApiAction
)
const compatibilitySubscription = frequentlyChangingAction
.getCompatibilityChangesSubject(apiContext)
?.pipe(
switchMap(async () => {
return await frequentlyChangingAction.isCompatible({
...apiContext,
trigger: contextMenuTrigger,
});
})
)
);
.subscribe(async (isCompatible) => {
handleActionCompatibilityChange(
'quickActions',
isCompatible,
frequentlyChangingAction as AnyApiAction
);
});
subscriptions.add(compatibilitySubscription);
}
}

Expand All @@ -214,17 +221,24 @@ export const PresentationPanelHoverActions = ({
if (
(ALLOWED_NOTIFICATIONS as readonly string[]).includes(frequentlyChangingNotification.id)
) {
subscriptions.add(
frequentlyChangingNotification.subscribeToCompatibilityChanges(
apiContext,
(isCompatible, action) =>
handleActionCompatibilityChange(
'notifications',
isCompatible,
action as AnyApiAction
)
const compatibilitySubscription = frequentlyChangingNotification
.getCompatibilityChangesSubject(apiContext)
?.pipe(
switchMap(async () => {
return await frequentlyChangingNotification.isCompatible({
...apiContext,
trigger: panelNotificationTrigger,
});
})
)
);
.subscribe(async (isCompatible) => {
handleActionCompatibilityChange(
'notifications',
isCompatible,
frequentlyChangingNotification as AnyApiAction
);
});
subscriptions.add(compatibilitySubscription);
}
}
})();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import { EuiBadge, EuiNotificationBadge, EuiToolTip, useEuiTheme } from '@elastic/eui';
import React, { useEffect, useMemo, useState } from 'react';
import { Subscription } from 'rxjs';
import { Subscription, switchMap } from 'rxjs';

import { uiActions } from '../../kibana_services';
import {
Expand Down Expand Up @@ -86,11 +86,20 @@ export const usePresentationPanelHeaderActions = <
);
if (canceled) return;
for (const badge of frequentlyChangingBadges) {
subscriptions.add(
badge.subscribeToCompatibilityChanges(apiContext, (isCompatible, action) =>
handleActionCompatibilityChange('badge', isCompatible, action as AnyApiAction)
const compatibilitySubject = badge
.getCompatibilityChangesSubject(apiContext)
?.pipe(
switchMap(async () => {
return await badge.isCompatible({
...apiContext,
trigger: panelBadgeTrigger,
});
})
)
);
.subscribe(async (isCompatible) => {
handleActionCompatibilityChange('badge', isCompatible, badge as AnyApiAction);
});
subscriptions.add(compatibilitySubject);
}

// subscribe to any frequently changing notification actions
Expand All @@ -101,12 +110,26 @@ export const usePresentationPanelHeaderActions = <
);
if (canceled) return;
for (const notification of frequentlyChangingNotifications) {
if (!disabledNotifications.includes(notification.id))
subscriptions.add(
notification.subscribeToCompatibilityChanges(apiContext, (isCompatible, action) =>
handleActionCompatibilityChange('notification', isCompatible, action as AnyApiAction)
if (!disabledNotifications.includes(notification.id)) {
const compatibilitySubject = notification
.getCompatibilityChangesSubject(apiContext)
?.pipe(
switchMap(async () => {
return await notification.isCompatible({
...apiContext,
trigger: panelNotificationTrigger,
});
})
)
);
.subscribe(async (isCompatible) => {
handleActionCompatibilityChange(
'notification',
isCompatible,
notification as AnyApiAction
);
});
subscriptions.add(compatibilitySubject);
}
}
})();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { ErrorLike } from '@kbn/expressions-plugin/common';
import { EmbeddableApiContext, useStateFromPublishingSubject } from '@kbn/presentation-publishing';
import { renderSearchError } from '@kbn/search-errors';
import { Markdown } from '@kbn/shared-ux-markdown';
import { Subscription } from 'rxjs';
import { Subscription, switchMap } from 'rxjs';
import { i18n } from '@kbn/i18n';
import { useErrorTextStyle } from '@kbn/react-hooks';
import { ActionExecutionMeta } from '@kbn/ui-actions-plugin/public';
Expand Down Expand Up @@ -80,20 +80,26 @@ export const PresentationPanelErrorInternal = ({ api, error }: PresentationPanel
const subscription = new Subscription();
(async () => {
const editPanelAction = await uiActions.getAction(ACTION_EDIT_PANEL);
if (canceled || !editPanelAction?.couldBecomeCompatible?.({ embeddable: api })) return;

const initiallyCompatible = await editPanelAction?.isCompatible({
const context = {
embeddable: api,
trigger: { id: CONTEXT_MENU_TRIGGER },
} as EmbeddableApiContext & ActionExecutionMeta);
};
if (canceled || !editPanelAction?.couldBecomeCompatible?.(context)) return;

const initiallyCompatible = await editPanelAction?.isCompatible(context);
if (canceled) return;
setIsEditable(initiallyCompatible);

subscription.add(
editPanelAction?.subscribeToCompatibilityChanges?.({ embeddable: api }, (isCompatible) => {
const compatibilitySubscription = editPanelAction
?.getCompatibilityChangesSubject?.(context)
?.pipe(
switchMap(async () => {
return await editPanelAction.isCompatible(context);
})
)
.subscribe(async (isCompatible) => {
if (!canceled) setIsEditable(isCompatible);
})
);
});
subscription.add(compatibilitySubscription);
})();

return () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, take } from 'rxjs';
import { getMockedControlGroupApi } from '../controls/mocks/control_mocks';
import { ClearControlAction } from './clear_control_action';

Expand Down Expand Up @@ -46,13 +46,12 @@ describe('ClearControlAction', () => {
}).rejects.toThrow(Error);
});

test('should call onChange when isCompatible changes', () => {
const onChange = jest.fn();

test('should call onChange when isCompatible changes', (done) => {
const subject = clearControlAction.getCompatibilityChangesSubject({ embeddable: controlApi });
subject?.pipe(take(1)).subscribe(() => {
done();
});
hasSelections$.next(true);
clearControlAction.subscribeToCompatibilityChanges({ embeddable: controlApi }, onChange);

expect(onChange).toHaveBeenCalledWith(true, clearControlAction);
});

describe('Clear control button compatibility', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
type Action,
} from '@kbn/ui-actions-plugin/public';
import { PresentationContainer, apiIsPresentationContainer } from '@kbn/presentation-containers';
import { map } from 'rxjs';
import { CONTROL_GROUP_TYPE } from '../../common';
import { CanClearSelections, isClearableControl } from '../types';

Expand Down Expand Up @@ -89,15 +90,10 @@ export class ClearControlAction
return isClearableControl(embeddable);
}

public subscribeToCompatibilityChanges(
{ embeddable }: EmbeddableApiContext,
onChange: (isCompatible: boolean, action: ClearControlAction) => void
) {
if (!isClearableControl(embeddable)) return;

return embeddable.hasSelections$.subscribe((selection) => {
onChange(Boolean(selection), this);
});
public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) {
return isClearableControl(embeddable)
? embeddable.hasSelections$.pipe(map(() => undefined))
: undefined;
}

public async isCompatible({ embeddable }: EmbeddableApiContext) {
Expand Down
Loading

0 comments on commit 0fb26ea

Please sign in to comment.