Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
stacey-gammon committed Feb 29, 2020
1 parent 3f1930a commit 223a9d3
Show file tree
Hide file tree
Showing 49 changed files with 461 additions and 309 deletions.
8 changes: 6 additions & 2 deletions examples/ui_action_examples/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import { Plugin, CoreSetup } from '../../../src/core/public';
import { UiActionsSetup } from '../../../src/plugins/ui_actions/public';
import { createHelloWorldAction } from './hello_world_action';
import { createHelloWorldAction, HELLO_WORLD_ACTION_TYPE } from './hello_world_action';
import { helloWorldTrigger, HELLO_WORLD_TRIGGER_ID } from './hello_world_trigger';

interface UiActionExamplesSetupDependencies {
Expand All @@ -30,6 +30,10 @@ declare module '../../../src/plugins/ui_actions/public' {
export interface TriggerContextMapping {
[HELLO_WORLD_TRIGGER_ID]: undefined;
}

export interface ActionContextMapping {
[HELLO_WORLD_ACTION_TYPE]: undefined;
}
}

export class UiActionExamplesPlugin
Expand All @@ -42,7 +46,7 @@ export class UiActionExamplesPlugin
}));

uiActions.registerAction(helloWorldAction);
uiActions.attachAction(helloWorldTrigger.id, helloWorldAction.id);
uiActions.attachAction(helloWorldTrigger.id, helloWorldAction);
}

public start() {}
Expand Down
17 changes: 7 additions & 10 deletions examples/ui_actions_explorer/public/actions/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,32 @@ export const EDIT_USER_ACTION = 'EDIT_USER_ACTION';
export const PHONE_USER_ACTION = 'PHONE_USER_ACTION';
export const SHOWCASE_PLUGGABILITY_ACTION = 'SHOWCASE_PLUGGABILITY_ACTION';

export const showcasePluggability = createAction({
export const showcasePluggability = createAction<typeof SHOWCASE_PLUGGABILITY_ACTION>({
type: SHOWCASE_PLUGGABILITY_ACTION,
getDisplayName: () => 'This is pluggable! Any plugin can inject their actions here.',
execute: async () => alert("Isn't that cool?!"),
});

export type PhoneContext = string;

export const makePhoneCallAction = createAction<PhoneContext>({
export const makePhoneCallAction = createAction<typeof CALL_PHONE_NUMBER_ACTION>({
type: CALL_PHONE_NUMBER_ACTION,
getDisplayName: () => 'Call phone number',
execute: async phone => alert(`Pretend calling ${phone}...`),
});

export const lookUpWeatherAction = createAction<{ country: string }>({
export const lookUpWeatherAction = createAction<typeof TRAVEL_GUIDE_ACTION>({
type: TRAVEL_GUIDE_ACTION,
getIconType: () => 'popout',
getDisplayName: () => 'View travel guide',
execute: async ({ country }) => {
execute: async country => {
window.open(`https://www.worldtravelguide.net/?s=${country},`, '_blank');
},
});

export type CountryContext = string;

export const viewInMapsAction = createAction<CountryContext>({
export const viewInMapsAction = createAction<typeof VIEW_IN_MAPS_ACTION>({
type: VIEW_IN_MAPS_ACTION,
getIconType: () => 'popout',
getDisplayName: () => 'View in maps',
Expand Down Expand Up @@ -100,10 +100,7 @@ function EditUserModal({
}

export const createEditUserAction = (getOpenModal: () => Promise<OverlayStart['openModal']>) =>
createAction<{
user: User;
update: (user: User) => void;
}>({
createAction<typeof EDIT_USER_ACTION>({
type: EDIT_USER_ACTION,
getIconType: () => 'pencil',
getDisplayName: () => 'Edit user',
Expand All @@ -120,7 +117,7 @@ export interface UserContext {
}

export const createPhoneUserAction = (getUiActionsApi: () => Promise<UiActionsStart>) =>
createAction<UserContext>({
createAction<typeof PHONE_USER_ACTION>({
type: PHONE_USER_ACTION,
getDisplayName: () => 'Call phone number',
isCompatible: async ({ user }) => user.phone !== undefined,
Expand Down
9 changes: 5 additions & 4 deletions examples/ui_actions_explorer/public/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ const ActionsExplorer = ({ uiActionsApi, openModal }: Props) => {
<EuiButton
data-test-subj="addDynamicAction"
onClick={() => {
const dynamicAction = createAction<{}>({
type: `${HELLO_WORLD_ACTION_TYPE}-${name}`,
const dynamicAction = createAction<typeof HELLO_WORLD_ACTION_TYPE>({
id: `${HELLO_WORLD_ACTION_TYPE}-${name}`,
type: HELLO_WORLD_ACTION_TYPE,
getDisplayName: () => `Say hello to ${name}`,
execute: async () => {
const overlay = openModal(
Expand All @@ -95,10 +96,10 @@ const ActionsExplorer = ({ uiActionsApi, openModal }: Props) => {
},
});
uiActionsApi.registerAction(dynamicAction);
uiActionsApi.attachAction(HELLO_WORLD_TRIGGER_ID, dynamicAction.type);
uiActionsApi.attachAction(HELLO_WORLD_TRIGGER_ID, dynamicAction);
setConfirmationText(
`You've successfully added a new action: ${dynamicAction.getDisplayName(
{}
undefined
)}. Refresh the page to reset state. It's up to the user of the system to persist state like this.`
);
}}
Expand Down
46 changes: 26 additions & 20 deletions examples/ui_actions_explorer/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ import {
lookUpWeatherAction,
viewInMapsAction,
createEditUserAction,
CALL_PHONE_NUMBER_ACTION,
VIEW_IN_MAPS_ACTION,
TRAVEL_GUIDE_ACTION,
PHONE_USER_ACTION,
EDIT_USER_ACTION,
makePhoneCallAction,
showcasePluggability,
SHOWCASE_PLUGGABILITY_ACTION,
UserContext,
CountryContext,
PhoneContext,
EDIT_USER_ACTION,
SHOWCASE_PLUGGABILITY_ACTION,
CALL_PHONE_NUMBER_ACTION,
TRAVEL_GUIDE_ACTION,
VIEW_IN_MAPS_ACTION,
PHONE_USER_ACTION,
} from './actions/actions';

interface StartDeps {
Expand All @@ -54,6 +54,15 @@ declare module '../../../src/plugins/ui_actions/public' {
[COUNTRY_TRIGGER]: CountryContext;
[PHONE_TRIGGER]: PhoneContext;
}

export interface ActionContextMapping {
[EDIT_USER_ACTION]: UserContext;
[SHOWCASE_PLUGGABILITY_ACTION]: undefined;
[CALL_PHONE_NUMBER_ACTION]: PhoneContext;
[TRAVEL_GUIDE_ACTION]: CountryContext;
[VIEW_IN_MAPS_ACTION]: CountryContext;
[PHONE_USER_ACTION]: UserContext;
}
}

export class UiActionsExplorerPlugin implements Plugin<void, void, {}, StartDeps> {
Expand All @@ -67,29 +76,26 @@ export class UiActionsExplorerPlugin implements Plugin<void, void, {}, StartDeps
deps.uiActions.registerTrigger({
id: USER_TRIGGER,
});
deps.uiActions.registerAction(lookUpWeatherAction);
deps.uiActions.registerAction(viewInMapsAction);
deps.uiActions.registerAction(makePhoneCallAction);
deps.uiActions.registerAction(showcasePluggability);

const startServices = core.getStartServices();
deps.uiActions.registerAction(

deps.uiActions.attachAction(
USER_TRIGGER,
createPhoneUserAction(async () => (await startServices)[1].uiActions)
);
deps.uiActions.registerAction(
deps.uiActions.attachAction(
USER_TRIGGER,
createEditUserAction(async () => (await startServices)[0].overlays.openModal)
);
deps.uiActions.attachAction(USER_TRIGGER, PHONE_USER_ACTION);
deps.uiActions.attachAction(USER_TRIGGER, EDIT_USER_ACTION);

// What's missing here is type analysis to ensure the context emitted by the trigger
// is the same context that the action requires.
deps.uiActions.attachAction(COUNTRY_TRIGGER, VIEW_IN_MAPS_ACTION);
deps.uiActions.attachAction(COUNTRY_TRIGGER, TRAVEL_GUIDE_ACTION);
deps.uiActions.attachAction(COUNTRY_TRIGGER, SHOWCASE_PLUGGABILITY_ACTION);
deps.uiActions.attachAction(PHONE_TRIGGER, CALL_PHONE_NUMBER_ACTION);
deps.uiActions.attachAction(PHONE_TRIGGER, SHOWCASE_PLUGGABILITY_ACTION);
deps.uiActions.attachAction(USER_TRIGGER, SHOWCASE_PLUGGABILITY_ACTION);
deps.uiActions.attachAction(COUNTRY_TRIGGER, viewInMapsAction);
deps.uiActions.attachAction(COUNTRY_TRIGGER, lookUpWeatherAction);
deps.uiActions.attachAction(COUNTRY_TRIGGER, showcasePluggability);
deps.uiActions.attachAction(PHONE_TRIGGER, makePhoneCallAction);
deps.uiActions.attachAction(PHONE_TRIGGER, showcasePluggability);
deps.uiActions.attachAction(USER_TRIGGER, showcasePluggability);

core.application.register({
id: 'uiActionsExplorer',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@

import { i18n } from '@kbn/i18n';
import {
Action,
createAction,
IncompatibleActionError,
ActionByType,
} from '../../../../../plugins/ui_actions/public';
import { onBrushEvent } from './filters/brush_event';
import { FilterManager, TimefilterContract, esFilters } from '../../../../../plugins/data/public';

export const SELECT_RANGE_ACTION = 'SELECT_RANGE_ACTION';

interface ActionContext {
export interface SelectRangeActionContext {
data: any;
timeFieldName: string;
}

async function isCompatible(context: ActionContext) {
async function isCompatible(context: SelectRangeActionContext) {
try {
return Boolean(await onBrushEvent(context.data));
} catch {
Expand All @@ -44,8 +44,8 @@ async function isCompatible(context: ActionContext) {
export function selectRangeAction(
filterManager: FilterManager,
timeFilter: TimefilterContract
): Action<ActionContext> {
return createAction<ActionContext>({
): ActionByType<typeof SELECT_RANGE_ACTION> {
return createAction<typeof SELECT_RANGE_ACTION>({
type: SELECT_RANGE_ACTION,
id: SELECT_RANGE_ACTION,
getDisplayName: () => {
Expand All @@ -54,7 +54,7 @@ export function selectRangeAction(
});
},
isCompatible,
execute: async ({ timeFieldName, data }: ActionContext) => {
execute: async ({ timeFieldName, data }: SelectRangeActionContext) => {
if (!(await isCompatible({ timeFieldName, data }))) {
throw new IncompatibleActionError();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import { i18n } from '@kbn/i18n';
import { toMountPoint } from '../../../../../plugins/kibana_react/public';
import {
Action,
ActionByType,
createAction,
IncompatibleActionError,
} from '../../../../../plugins/ui_actions/public';
Expand All @@ -39,12 +39,12 @@ import {

export const VALUE_CLICK_ACTION = 'VALUE_CLICK_ACTION';

interface ActionContext {
export interface ValueClickActionContext {
data: any;
timeFieldName: string;
}

async function isCompatible(context: ActionContext) {
async function isCompatible(context: ValueClickActionContext) {
try {
const filters: Filter[] = (await createFiltersFromEvent(context.data)) || [];
return filters.length > 0;
Expand All @@ -56,8 +56,8 @@ async function isCompatible(context: ActionContext) {
export function valueClickAction(
filterManager: FilterManager,
timeFilter: TimefilterContract
): Action<ActionContext> {
return createAction<ActionContext>({
): ActionByType<typeof VALUE_CLICK_ACTION> {
return createAction<typeof VALUE_CLICK_ACTION>({
type: VALUE_CLICK_ACTION,
id: VALUE_CLICK_ACTION,
getDisplayName: () => {
Expand All @@ -66,7 +66,7 @@ export function valueClickAction(
});
},
isCompatible,
execute: async ({ timeFieldName, data }: ActionContext) => {
execute: async ({ timeFieldName, data }: ValueClickActionContext) => {
if (!(await isCompatible({ timeFieldName, data }))) {
throw new IncompatibleActionError();
}
Expand Down
28 changes: 21 additions & 7 deletions src/legacy/core_plugins/data/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,16 @@ import {
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
} from '../../../../plugins/data/public/services';
import { setSearchServiceShim } from './services';
import { SELECT_RANGE_ACTION, selectRangeAction } from './actions/select_range_action';
import { VALUE_CLICK_ACTION, valueClickAction } from './actions/value_click_action';
import {
selectRangeAction,
SelectRangeActionContext,
SELECT_RANGE_ACTION,
} from './actions/select_range_action';
import {
valueClickAction,
VALUE_CLICK_ACTION,
ValueClickActionContext,
} from './actions/value_click_action';
import {
SELECT_RANGE_TRIGGER,
VALUE_CLICK_TRIGGER,
Expand Down Expand Up @@ -76,6 +84,12 @@ export interface DataSetup {
export interface DataStart {
search: SearchStart;
}
declare module '../../../../plugins/ui_actions/public' {
export interface ActionContextMapping {
[SELECT_RANGE_ACTION]: SelectRangeActionContext;
[VALUE_CLICK_ACTION]: ValueClickActionContext;
}
}

/**
* Data Plugin - public
Expand All @@ -100,10 +114,13 @@ export class DataPlugin
// This is to be deprecated once we switch to the new search service fully
addSearchStrategy(defaultSearchStrategy);

uiActions.registerAction(
uiActions.attachAction(
SELECT_RANGE_TRIGGER,
selectRangeAction(data.query.filterManager, data.query.timefilter.timefilter)
);
uiActions.registerAction(

uiActions.attachAction(
VALUE_CLICK_TRIGGER,
valueClickAction(data.query.filterManager, data.query.timefilter.timefilter)
);

Expand All @@ -123,9 +140,6 @@ export class DataPlugin
setSearchService(data.search);
setOverlays(core.overlays);

uiActions.attachAction(SELECT_RANGE_TRIGGER, SELECT_RANGE_ACTION);
uiActions.attachAction(VALUE_CLICK_TRIGGER, VALUE_CLICK_ACTION);

return {
search,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import { i18n } from '@kbn/i18n';
import { IEmbeddable } from '../embeddable_plugin';
import { Action, IncompatibleActionError } from '../ui_actions_plugin';
import { ActionByType, IncompatibleActionError } from '../ui_actions_plugin';
import { DASHBOARD_CONTAINER_TYPE, DashboardContainer } from '../embeddable';

export const EXPAND_PANEL_ACTION = 'togglePanel';
Expand All @@ -36,18 +36,18 @@ function isExpanded(embeddable: IEmbeddable) {
return embeddable.id === embeddable.parent.getInput().expandedPanelId;
}

interface ActionContext {
export interface ExpandPanelActionContext {
embeddable: IEmbeddable;
}

export class ExpandPanelAction implements Action<ActionContext> {
export class ExpandPanelAction implements ActionByType<typeof EXPAND_PANEL_ACTION> {
public readonly type = EXPAND_PANEL_ACTION;
public readonly id = EXPAND_PANEL_ACTION;
public order = 7;

constructor() {}

public getDisplayName({ embeddable }: ActionContext) {
public getDisplayName({ embeddable }: ExpandPanelActionContext) {
if (!embeddable.parent || !isDashboard(embeddable.parent)) {
throw new IncompatibleActionError();
}
Expand All @@ -67,19 +67,19 @@ export class ExpandPanelAction implements Action<ActionContext> {
);
}

public getIconType({ embeddable }: ActionContext) {
public getIconType({ embeddable }: ExpandPanelActionContext) {
if (!embeddable.parent || !isDashboard(embeddable.parent)) {
throw new IncompatibleActionError();
}
// TODO: use 'minimize' when an eui-icon of such is available.
return isExpanded(embeddable) ? 'expand' : 'expand';
}

public async isCompatible({ embeddable }: ActionContext) {
public async isCompatible({ embeddable }: ExpandPanelActionContext) {
return Boolean(embeddable.parent && isDashboard(embeddable.parent));
}

public async execute({ embeddable }: ActionContext) {
public async execute({ embeddable }: ExpandPanelActionContext) {
if (!embeddable.parent || !isDashboard(embeddable.parent)) {
throw new IncompatibleActionError();
}
Expand Down
Loading

0 comments on commit 223a9d3

Please sign in to comment.