Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Doc] Documentation of content management plugin #7575

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/7575.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
doc:
- Add documentation for dynamic page creation ([#7575](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7575))
237 changes: 237 additions & 0 deletions src/plugins/content_management/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
# Plugin for managing dynamic page creation in OSD
Use this plugin to create pages that multiple plugins can contribute to. A typical use case is the OSD homepage,
which can have contents contributed by different plugins, see the screenshot:

![image](https://github.com/user-attachments/assets/501c2433-38c5-4b53-9974-de6f63eab94d)

## Getting started
### Step 1: Add `contentManagement` to `requiredPlugins`
Ensure `contentManagement` is listed in the `requiredPlugins` array of your plugin's manifest file.
```json
{
"requiredPlugins": ["contentManagement"]
}
```

### Step 2: Create a page with defined sections
A section is typically a container on the page, and a page could have multiple sections. Using the homepage as an example:
```typescript
export const HOME_PAGE_ID = 'osd_homepage';
export enum SECTIONS {
GET_STARTED = `get_started`,
SERVICE_CARDS = `service_cards`,
RECENTLY_VIEWED = `recently_viewed`,
}

export class MyPlugin implements Plugin {
public setup(core, { contentManagement }) {
contentManagement.registerPage({
id: HOME_PAGE_ID,
title: 'Home',
sections: [
ruanyl marked this conversation as resolved.
Show resolved Hide resolved
{
id: SECTIONS.SERVICE_CARDS,
order: 3000,
kind: 'dashboard',
},
{
id: SECTIONS.RECENTLY_VIEWED,
order: 2000,
title: 'Recently viewed',
kind: 'custom',
render: (contents) => (
<>
{contents.map((content) => content.kind === 'custom' ? content.render() : null)}
</>
),
},
{
id: SECTIONS.GET_STARTED,
order: 1000,
title: 'Define your path forward with OpenSearch',
kind: 'card',
},
],
});
}
}
```
Here we defined a page with three different kinds of sections: `dashboard`, `custom` and `card`, the sections will be sorted by `order` in ascending order.
Each type of section serves a different purpose:

#### `card` section
A `card` section is one of the pre-defined section type that renders a horizontal list of OuiCard components, to add
contents to a `card` section, call `contentManagement.registerContentProvider` with a `title` and `description`, and the content
will be sorted by its `order` in ascending order.
```typescript
export class MyPlugin implements Plugin {
public start(core, { contentManagement }) {
contentManagement.registerContentProvider({
ruanyl marked this conversation as resolved.
Show resolved Hide resolved
id: `home_get_start`, // id for the content provider, could be any unique string
getTargetArea: () => `${HOME_PAGE_ID}/${SECTIONS.GET_STARTED}`, // target area follow the convention: {page_id}/{section_id}
getContent: () => ({
id: 'card_content_id', // id for the content, could be any unique string
kind: 'card',
order: 1000,
description: 'Card description',
title: 'Card title'
}),
});
}
}
```

#### `dashboard` section
A `dashboard` section is typically a dashboard embeddable container, it can render visualization or dashboard by their id,
or it can render arbitrary React components.

Add a saved visualization to a `dashboard` section **statically**
```typescript
export class MyPlugin implements Plugin {
public start(core, { contentManagement }) {
contentManagement.registerContentProvider({
id: `visualization_content_provider`,
getTargetArea: () => `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`,
getContent: () => ({
id: 'visualization_content_id', // id for the content, could be any unique string
kind: 'visualization',
order: 1000,
input: {
kind: 'static',
id: 'c0ba29f0-eb8f-11ed-8e00-17d7d50cd7b2' // the visualization id
}
}),
});
}
}
```

Add a saved visualization to a `dashboard` section **dynamically**
```diff
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Today I learnt that you can do this. Nice!

export class MyPlugin implements Plugin {
public start(core, { contentManagement }) {
contentManagement.registerContentProvider({
id: `visualization_content_provider`,
getTargetArea: () => `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`,
getContent: () => ({
id: 'visualization_content_id',
kind: 'visualization', // with `visualization` kind
order: 1000,
input: {
- kind: 'static',
- id: 'c0ba29f0-eb8f-11ed-8e00-17d7d50cd7b2' // the visualization id
+ kind: 'dynamic',
+ get: () => Promise.resolve('c0ba29f0-eb8f-11ed-8e00-17d7d50cd7b2') // the visualization id
}
}),
});
}
}
```

Add a saved dashboard to a `dashboard` section **statically**
```typescript
export class MyPlugin implements Plugin {
public start(core, { contentManagement }) {
contentManagement.registerContentProvider({
id: `dashboard_content_provider`,
getTargetArea: () => `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`,
getContent: () => ({
id: 'dashboard_content_id',
kind: 'dashboard', // with `dashboard` kind
order: 1000,
input: {
kind: 'static',
id: 'c39012d0-eb7a-11ed-8e00-17d7d50cd7b2' // the saved dashboard id
}
}),
});
}
}
```

Similarly, you can add a saved dashboard to a `dashboard` section **dynamically**
```diff
export class MyPlugin implements Plugin {
public start(core, { contentManagement }) {
contentManagement.registerContentProvider({
id: `dashboard_content_provider`,
getTargetArea: () => `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`,
getContent: () => ({
id: 'dashboard_content_id',
kind: 'dashboard', // with `dashboard` kind
order: 1000,
input: {
- kind: 'static',
- id: 'c39012d0-eb7a-11ed-8e00-17d7d50cd7b2' // the saved dashboard id
+ kind: 'dynamic',
+ get: () => Promise.resolve('c39012d0-eb7a-11ed-8e00-17d7d50cd7b2') // the saved dashboard id
}
}),
});
}
}
```

You can also add custom components to a `dashboard` section
```typescript
export class MyPlugin implements Plugin {
public start(core, { contentManagement }) {
contentManagement.registerContentProvider({
id: `custom_content_provider`,
getTargetArea: () => `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`,
getContent: () => ({
id: 'custom_content_id',
kind: 'custom', // with `dashboard` kind
order: 1000,
render: () => <MyComponent />
}),
});
}
}
```

#### `custom` section
If the existing pre-defined sections do not meet your needs, you could use `custom` section to customize the rendering of the contents,
a custom section is typically defined with `kind: 'custom'` and a `render` function:
```typescript
{
id: SECTIONS.RECENTLY_VIEWED,
order: 2000,
title: 'Recently viewed',
kind: 'custom',
render: (contents) => (
<>
{contents.map((content) => content.kind === 'custom' ? content.render() : null)}
</>
),
ruanyl marked this conversation as resolved.
Show resolved Hide resolved
}
```

Now adds content to a `custom` section
```typescript
export class MyPlugin implements Plugin {
public start(core, { contentManagement }) {
contentManagement.registerContentProvider({
id: 'recent_provider_id',
getContent: () => {
return {
order: 1,
id: 'recent_content_id',
kind: 'custom',
render: () => <RecentWork />,
};
},
getTargetArea: () => `${HOME_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`,
});
}
}
```

### Step 3: Render the page
Finally, render the page in your application:
```typescript
<Route exact path="/">
{contentManagement.renderPage(HOME_PAGE_ID)}
</Route>
```
Loading