Add overview section to actions and triggers example (#175152)

PR updates actions and triggers example with an "Overview" section
better explaining the top level concepts. PR also re-works the hello
world example to have a better explaination of what it does and simplify
the example

### before
<img width="800" alt="Screenshot 2024-01-18 at 12 08 44 PM"
src="5969b35e-a307-402a-aba4-a5b4ffa9920b">

### after
<img width="800" alt="Screenshot 2024-01-18 at 12 06 46 PM"
src="e2eb416e-c7a0-4a04-83e8-2383fbe12dae">

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2024-01-22 09:05:13 -07:00 committed by GitHub
parent e404798a15
commit 33077eaa99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 168 additions and 76 deletions

View file

@ -33,7 +33,6 @@ export class UiActionExamplesPlugin
openModal: (await core.getStartServices())[0].overlays.openModal,
}));
uiActions.registerAction(helloWorldAction);
uiActions.addTriggerAction(helloWorldTrigger.id, helloWorldAction);
}

View file

@ -6,104 +6,50 @@
* Side Public License, v 1.
*/
import React, { useState } from 'react';
import React from 'react';
import ReactDOM from 'react-dom';
import {
EuiPage,
EuiButton,
EuiPageBody,
EuiPageTemplate,
EuiPageSection,
EuiSpacer,
EuiText,
EuiFieldText,
EuiCallOut,
EuiPageHeader,
EuiModalBody,
} from '@elastic/eui';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { UiActionsStart, createAction } from '@kbn/ui-actions-plugin/public';
import { UiActionsStart } from '@kbn/ui-actions-plugin/public';
import { AppMountParameters, OverlayStart } from '@kbn/core/public';
import { HELLO_WORLD_TRIGGER_ID, ACTION_HELLO_WORLD } from '@kbn/ui-actions-examples-plugin/public';
import { TriggerContextExample } from './trigger_context_example';
import { ContextMenuExamples } from './context_menu_examples';
import { Overview } from './overview';
import { HelloWorldExample } from './hello_world_example';
interface Props {
uiActionsApi: UiActionsStart;
uiActionsStartService: UiActionsStart;
openModal: OverlayStart['openModal'];
}
const ActionsExplorer = ({ uiActionsApi, openModal }: Props) => {
const [name, setName] = useState('Waldo');
const [confirmationText, setConfirmationText] = useState('');
const ActionsExplorer = ({ uiActionsStartService, openModal }: Props) => {
return (
<EuiPage>
<EuiPageBody>
<EuiPageSection>
<EuiPageHeader pageTitle={'Ui Actions Explorer'} />
<EuiPageHeader pageTitle="Actions and Triggers" />
</EuiPageSection>
<EuiPageTemplate.Section>
<EuiPageSection>
<EuiText>
<p>
By default there is a single action attached to the `HELLO_WORLD_TRIGGER`. Clicking
this button will cause it to be executed immediately.
</p>
</EuiText>
<EuiButton
data-test-subj="emitHelloWorldTrigger"
onClick={() => uiActionsApi.executeTriggerActions(HELLO_WORLD_TRIGGER_ID, {})}
>
Say hello world!
</EuiButton>
<EuiText>
<p>
Lets dynamically add new actions to this trigger. After you click this button, click
the above button again. This time it should offer you multiple options to choose
from. Using the UI Action and Trigger API makes your plugin extensible by other
plugins. Any actions attached to the `HELLO_WORLD_TRIGGER_ID` will show up here!
</p>
<EuiFieldText prepend="Name" value={name} onChange={(e) => setName(e.target.value)} />
<EuiButton
data-test-subj="addDynamicAction"
onClick={() => {
const dynamicAction = createAction({
id: `${ACTION_HELLO_WORLD}-${name}`,
type: ACTION_HELLO_WORLD,
getDisplayName: () => `Say hello to ${name}`,
execute: async () => {
const overlay = openModal(
toMountPoint(
<EuiModalBody>
<EuiText data-test-subj="dynamicHelloWorldActionText">
{`Hello ${name}`}
</EuiText>{' '}
<EuiButton data-test-subj="closeModal" onClick={() => overlay.close()}>
Close
</EuiButton>
</EuiModalBody>
)
);
},
});
uiActionsApi.addTriggerAction(HELLO_WORLD_TRIGGER_ID, dynamicAction);
setConfirmationText(
`You've successfully added a new action: ${dynamicAction.getDisplayName({
trigger: uiActionsApi.getTrigger(HELLO_WORLD_TRIGGER_ID),
})}. Refresh the page to reset state. It's up to the user of the system to persist state like this.`
);
}}
>
Say hello to me!
</EuiButton>
{confirmationText !== '' ? <EuiCallOut>{confirmationText}</EuiCallOut> : undefined}
</EuiText>
<Overview />
<EuiSpacer />
<TriggerContextExample uiActionsApi={uiActionsApi} />
<HelloWorldExample
uiActionsStartService={uiActionsStartService}
openModal={openModal}
/>
<EuiSpacer />
<TriggerContextExample uiActionsApi={uiActionsStartService} />
<EuiSpacer />

View file

@ -0,0 +1,94 @@
/*
* 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 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 or the Server
* Side Public License, v 1.
*/
import React, { useState } from 'react';
import { EuiButton, EuiSpacer, EuiText, EuiModalBody, EuiLink, EuiSwitch } from '@elastic/eui';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import { UiActionsStart, createAction } from '@kbn/ui-actions-plugin/public';
import { OverlayStart } from '@kbn/core/public';
import { HELLO_WORLD_TRIGGER_ID, ACTION_HELLO_WORLD } from '@kbn/ui-actions-examples-plugin/public';
const DYNAMIC_ACTION_ID = `${ACTION_HELLO_WORLD}-Waldo`;
interface Props {
uiActionsStartService: UiActionsStart;
openModal: OverlayStart['openModal'];
}
export const HelloWorldExample = ({ uiActionsStartService, openModal }: Props) => {
const [isChecked, setIsChecked] = useState(false);
const actionsMessage = isChecked ? '2 actions attached' : '1 action attached';
return (
<>
<EuiText>
<h1>Hello world example</h1>
<p>
The{' '}
<EuiLink
href="https://github.com/elastic/kibana/tree/main/examples/ui_action_examples"
target="_blank"
>
ui_action_example plugin
</EuiLink>{' '}
registers the <em>HELLO_WORLD_TRIGGER_ID</em> trigger and attaches the{' '}
<em>ACTION_HELLO_WORLD</em> action to the trigger. The <em>ACTION_HELLO_WORLD</em> opens a
modal when executed. Fire the &quot;Hello world&quot; event by clicking the button below.
</p>
</EuiText>
<EuiButton
data-test-subj="emitHelloWorldTrigger"
onClick={() => uiActionsStartService.getTrigger(HELLO_WORLD_TRIGGER_ID).exec({})}
>
Click me to fire &quot;Hello world&quot; event ({actionsMessage})
</EuiButton>
<EuiSpacer />
<EuiText>
<p>
You can dynamically add a new action to a trigger. Click the switch below to attach a
second action to <em>HELLO_WORLD_TRIGGER_ID</em> trigger. What do you think will happen
when you click the button and the trigger has multiple actions?
</p>
<EuiSwitch
data-test-subj="addDynamicAction"
label={'Attach second action to "Hello world" event'}
checked={isChecked}
onChange={(e) => {
setIsChecked(e.target.checked);
if (e.target.checked) {
const dynamicAction = createAction({
id: DYNAMIC_ACTION_ID,
type: ACTION_HELLO_WORLD,
getDisplayName: () => 'Say hello to Waldo',
execute: async () => {
const overlay = openModal(
toMountPoint(
<EuiModalBody>
<EuiText data-test-subj="dynamicHelloWorldActionText">Hello Waldo</EuiText>{' '}
<EuiButton data-test-subj="closeModal" onClick={() => overlay.close()}>
Close
</EuiButton>
</EuiModalBody>
)
);
},
});
uiActionsStartService.addTriggerAction(HELLO_WORLD_TRIGGER_ID, dynamicAction);
} else {
uiActionsStartService.detachAction(HELLO_WORLD_TRIGGER_ID, DYNAMIC_ACTION_ID);
}
}}
/>
</EuiText>
</>
);
};

View file

@ -0,0 +1,55 @@
/*
* 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 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 or the Server
* Side Public License, v 1.
*/
import React from 'react';
import { EuiText, EuiLink } from '@elastic/eui';
export const Overview = () => {
return (
<EuiText>
<h1>Overview</h1>
<p>
Actions and triggers are an event system abstraction that decouples firing an event and
responding to an event.
</p>
Key concepts:
<ul>
<li>
<strong>Trigger</strong> is an id that represents an event type, for example
<em>PANEL_CLICK</em>.
</li>
<li>
<strong>Action</strong> is a{' '}
<EuiLink
href="https://github.com/elastic/kibana/blob/main/src/plugins/ui_actions/public/actions/action.ts"
target="_blank"
>
class
</EuiLink>{' '}
that responds to an event. Multiple actions can be registered to an event type. Actions
can respond to multiple event types.
</li>
<li>
<strong>Context</strong> is runtime state passed between an event and the responder of an
event.
</li>
</ul>
<p>
The purpose for the event system abstraction is to make event handling extensible, allowing
plugins to register their own event types and responses and register responses to existing
event types.
</p>
<p>
Use triggers to make your plugin extensible. For example, your plugin could register a
trigger. Then, other plugins can extend your plugin by registering new actions for the
trigger. Finally, when the trigger is fired, all attached actions are available.
</p>
</EuiText>
);
};

View file

@ -69,7 +69,7 @@ export class UiActionsExplorerPlugin implements Plugin<void, void, {}, StartDeps
const [coreStart, depsStart] = await core.getStartServices();
const { renderApp } = await import('./app');
return renderApp(
{ uiActionsApi: depsStart.uiActions, openModal: coreStart.overlays.openModal },
{ uiActionsStartService: depsStart.uiActions, openModal: coreStart.overlays.openModal },
params
);
},
@ -77,10 +77,8 @@ export class UiActionsExplorerPlugin implements Plugin<void, void, {}, StartDeps
deps.developerExamples.register({
appId: 'uiActionsExplorer',
title: 'Ui Actions & Triggers',
description: `Ui Actions can be used to make any part of your UI extensible. It has built in support for
context menus, but you can also render all actions attached to a given trigger however you like, just how
panel badges and panel notifications does.`,
title: 'Actions & Triggers',
description: `Learn how to extent Kibana's UI event system with actions and triggers. In the screen shot, plugins extend dashboard panels by attaching new actions to PANEL_BADGE_TRIGGER and CONTEXT_MENU_TRIGGER triggers.`,
image,
links: [
{