Skip to content

Commit eab9065

Browse files
authored
Set up plugin boilerplate & placeholder pages (#3)
Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com>
1 parent 5d10dcb commit eab9065

26 files changed

+546
-0
lines changed

common/constants.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
export const PLUGIN_ID = 'aiFlowDashboards';
6+
7+
export const BASE_NODE_API_PATH = '/api/ai_flow';

common/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export * from './constants';

opensearch_dashboards.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"id": "aiFlowDashboards",
3+
"version": "3.0.0.0",
4+
"opensearchDashboardsVersion": "3.0.0",
5+
"server": true,
6+
"ui": true,
7+
"requiredPlugins": ["navigation"],
8+
"optionalPlugins": []
9+
}

package.json

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "ai-flow-dashboards",
3+
"version": "3.0.0.0",
4+
"description": "OpenSearch AI Flow Dashboards Plugin",
5+
"main": "index.js",
6+
"config": {
7+
"plugin_version": "3.0.0.0",
8+
"plugin_name": "aiFlowDashboards",
9+
"plugin_zip_name": "ai-flow-dashboards"
10+
},
11+
"private": true,
12+
"scripts": {
13+
"plugin-helpers": "../../scripts/use_node ../../scripts/plugin_helpers",
14+
"osd": "../../scripts/use_node ../../scripts/osd",
15+
"opensearch": "node ../../scripts/opensearch",
16+
"lint": "node ../../scripts/eslint .",
17+
"build": "yarn plugin-helpers build && echo Renaming artifact to $npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip && mv ./build/$npm_package_config_plugin_name*.zip ./build/$npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip"
18+
},
19+
"lint-staged": {
20+
"*.{ts,tsx,js,jsx,json,css,md}": [
21+
"prettier --write",
22+
"git add"
23+
]
24+
},
25+
"devDependencies": {},
26+
"dependencies": {},
27+
"resolutions": {}
28+
}

public/app.tsx

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import React from 'react';
7+
import { I18nProvider } from '@osd/i18n/react';
8+
import { Route, RouteComponentProps, Switch } from 'react-router-dom';
9+
import { EuiPageSideBar, EuiSideNav, EuiPageTemplate } from '@elastic/eui';
10+
import { CoreStart } from '../../../src/core/public';
11+
import { Navigation, APP_PATH } from './utils';
12+
import { Overview, UseCases, Workflows } from './pages';
13+
import { CoreServicesConsumer } from './core_services';
14+
15+
interface Props extends RouteComponentProps {}
16+
17+
export const AiFlowDashboardsApp = (props: Props) => {
18+
const sidebar = (
19+
<EuiPageSideBar style={{ minWidth: 190 }} hidden={false}>
20+
<EuiSideNav
21+
style={{ width: 190 }}
22+
items={[
23+
{
24+
name: Navigation.AiApplicationBuilder,
25+
id: 0,
26+
items: [
27+
{
28+
name: Navigation.UseCases,
29+
id: 1,
30+
href: `#${APP_PATH.USE_CASES}`,
31+
isSelected: props.location.pathname === APP_PATH.USE_CASES,
32+
},
33+
{
34+
name: Navigation.Workflows,
35+
id: 2,
36+
href: `#${APP_PATH.WORKFLOWS}`,
37+
isSelected: props.location.pathname === APP_PATH.WORKFLOWS,
38+
},
39+
],
40+
},
41+
]}
42+
/>
43+
</EuiPageSideBar>
44+
);
45+
46+
// Render the application DOM.
47+
return (
48+
<CoreServicesConsumer>
49+
{(core: CoreStart | null) =>
50+
core && (
51+
<I18nProvider>
52+
<>
53+
<EuiPageTemplate
54+
template="empty"
55+
pageContentProps={{ paddingSize: 'm' }}
56+
pageSideBar={sidebar}
57+
>
58+
<Switch>
59+
<Route
60+
path={APP_PATH.USE_CASES}
61+
render={(props: RouteComponentProps) => <UseCases />}
62+
/>
63+
<Route
64+
path={APP_PATH.WORKFLOWS}
65+
render={(props: RouteComponentProps) => <Workflows />}
66+
/>
67+
{/* Defaulting to Overview page */}
68+
<Route
69+
path={`${APP_PATH.HOME}`}
70+
render={(props: RouteComponentProps) => <Overview />}
71+
/>
72+
</Switch>
73+
</EuiPageTemplate>
74+
</>
75+
</I18nProvider>
76+
)
77+
}
78+
</CoreServicesConsumer>
79+
);
80+
};

public/core_services.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { createContext } from 'react';
7+
import { CoreStart } from '../../../src/core/public';
8+
9+
const CoreServicesContext = createContext<CoreStart | null>(null);
10+
11+
const CoreServicesConsumer = CoreServicesContext.Consumer;
12+
13+
export { CoreServicesContext, CoreServicesConsumer };

public/index.scss

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/* stylelint-disable no-empty-source */

public/index.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import './index.scss';
7+
8+
import { AiFlowDashboardsPlugin } from './plugin';
9+
10+
// This exports static code and TypeScript types,
11+
// as well as, OpenSearch Dashboards Platform `plugin()` initializer.
12+
export function plugin() {
13+
return new AiFlowDashboardsPlugin();
14+
}
15+
export {
16+
AiFlowDashboardsPluginSetup,
17+
AiFlowDashboardsPluginStart,
18+
} from './types';
19+
20+
export * from './core_services';

public/pages/index.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export * from './use_cases';
7+
export * from './workflows';
8+
export * from './overview';

public/pages/overview/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export { Overview } from './overview';

public/pages/overview/overview.tsx

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import React, { useEffect } from 'react';
7+
import { EuiPageHeader, EuiText } from '@elastic/eui';
8+
import { CoreServicesContext } from '../../core_services';
9+
import { CoreStart } from '../../../../../src/core/public';
10+
import { BREADCRUMBS } from '../../utils';
11+
12+
export function Overview() {
13+
const core = React.useContext(CoreServicesContext) as CoreStart;
14+
useEffect(() => {
15+
core.chrome.setBreadcrumbs([BREADCRUMBS.AI_APPLICATION_BUILDER]);
16+
});
17+
18+
return (
19+
<EuiPageHeader>
20+
<EuiText>Welcome to the AI Application Builder!</EuiText>
21+
</EuiPageHeader>
22+
);
23+
}

public/pages/use_cases/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export { UseCases } from './use_cases';

public/pages/use_cases/use_cases.tsx

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import React, { useEffect } from 'react';
7+
import { EuiPageHeader, EuiText } from '@elastic/eui';
8+
import { CoreServicesContext } from '../../core_services';
9+
import { CoreStart } from '../../../../../src/core/public';
10+
import { BREADCRUMBS } from '../../utils';
11+
12+
export function UseCases() {
13+
const core = React.useContext(CoreServicesContext) as CoreStart;
14+
useEffect(() => {
15+
core.chrome.setBreadcrumbs([
16+
BREADCRUMBS.AI_APPLICATION_BUILDER,
17+
BREADCRUMBS.USE_CASES,
18+
]);
19+
});
20+
21+
return (
22+
<EuiPageHeader>
23+
<EuiText>Use cases page placeholder...</EuiText>
24+
</EuiPageHeader>
25+
);
26+
}

public/pages/workflows/index.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export { Workflows } from './workflows';

public/pages/workflows/workflows.tsx

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import React, { useEffect } from 'react';
7+
import { EuiPageHeader, EuiText } from '@elastic/eui';
8+
import { CoreServicesContext } from '../../core_services';
9+
import { CoreStart } from '../../../../../src/core/public';
10+
import { BREADCRUMBS } from '../../utils';
11+
12+
export function Workflows() {
13+
const core = React.useContext(CoreServicesContext) as CoreStart;
14+
useEffect(() => {
15+
core.chrome.setBreadcrumbs([
16+
BREADCRUMBS.AI_APPLICATION_BUILDER,
17+
BREADCRUMBS.WORKFLOWS,
18+
]);
19+
});
20+
21+
return (
22+
<EuiPageHeader>
23+
<EuiText>Workflows page placeholder...</EuiText>
24+
</EuiPageHeader>
25+
);
26+
}

public/plugin.ts

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import {
7+
AppMountParameters,
8+
CoreSetup,
9+
CoreStart,
10+
Plugin,
11+
} from '../../../src/core/public';
12+
import {
13+
AiFlowDashboardsPluginSetup,
14+
AiFlowDashboardsPluginStart,
15+
} from './types';
16+
import { PLUGIN_ID } from '../common';
17+
18+
export class AiFlowDashboardsPlugin
19+
implements Plugin<AiFlowDashboardsPluginSetup, AiFlowDashboardsPluginStart> {
20+
public setup(core: CoreSetup): AiFlowDashboardsPluginSetup {
21+
// Register the plugin in the side navigation
22+
core.application.register({
23+
id: PLUGIN_ID,
24+
title: 'AI Application Builder',
25+
category: {
26+
id: 'opensearch',
27+
label: 'OpenSearch plugins',
28+
order: 2000,
29+
},
30+
// TODO: can i remove this below order
31+
order: 5000,
32+
async mount(params: AppMountParameters) {
33+
const { renderApp } = await import('./render_app');
34+
const [coreStart] = await core.getStartServices();
35+
return renderApp(coreStart, params);
36+
},
37+
});
38+
return {};
39+
}
40+
41+
public start(core: CoreStart): AiFlowDashboardsPluginStart {
42+
return {};
43+
}
44+
45+
public stop() {}
46+
}

public/render_app.tsx

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import React from 'react';
7+
import ReactDOM from 'react-dom';
8+
import { BrowserRouter as Router, Route } from 'react-router-dom';
9+
import { AppMountParameters, CoreStart } from '../../../src/core/public';
10+
import { AiFlowDashboardsApp } from './app';
11+
import { CoreServicesContext } from './core_services';
12+
13+
export const renderApp = (
14+
coreStart: CoreStart,
15+
{ appBasePath, element }: AppMountParameters
16+
) => {
17+
ReactDOM.render(
18+
<Router basename={appBasePath + '#/'}>
19+
<Route
20+
render={(props) => (
21+
<CoreServicesContext.Provider value={coreStart}>
22+
<AiFlowDashboardsApp {...props} />
23+
</CoreServicesContext.Provider>
24+
)}
25+
></Route>
26+
</Router>,
27+
element
28+
);
29+
30+
return () => ReactDOM.unmountComponentAtNode(element);
31+
};

public/types.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { NavigationPublicPluginStart } from '../../../src/plugins/navigation/public';
7+
8+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
9+
export interface AiFlowDashboardsPluginSetup {}
10+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
11+
export interface AiFlowDashboardsPluginStart {}
12+
13+
export interface AppPluginStartDependencies {
14+
navigation: NavigationPublicPluginStart;
15+
}

public/utils/constants.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export enum Navigation {
7+
AiApplicationBuilder = 'AI Application Builder',
8+
UseCases = 'Use Cases',
9+
Workflows = 'Workflows',
10+
}
11+
12+
export enum APP_PATH {
13+
HOME = '/',
14+
USE_CASES = '/use-cases',
15+
WORKSPACE = '/workspace',
16+
WORKFLOWS = '/workflows',
17+
WORKFLOW_DETAIL = '/workflows/:workflowId/',
18+
}
19+
20+
export const BREADCRUMBS = Object.freeze({
21+
AI_APPLICATION_BUILDER: { text: 'AI application builder', href: '#/' },
22+
USE_CASES: { text: 'Use cases', href: `#${APP_PATH.USE_CASES}` },
23+
WORKFLOWS: { text: 'Workflows', href: `#${APP_PATH.WORKFLOWS}` },
24+
});

0 commit comments

Comments
 (0)