Skip to content

Commit

Permalink
Integrate saved object plugin into maps plugin
Browse files Browse the repository at this point in the history
Signed-off-by: Junqiu Lei <[email protected]>
  • Loading branch information
junqiu-lei committed Oct 28, 2022
1 parent c71a068 commit d7270dc
Show file tree
Hide file tree
Showing 17 changed files with 327 additions and 106 deletions.
25 changes: 25 additions & 0 deletions maps_dashboards/common/map_saved_object_attributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { SavedObjectAttributes } from 'opensearch-dashboards/server';

export interface MapSavedObjectAttributes extends SavedObjectAttributes {
/** Title of the map */
title: string;
/** Description of the map */
description?: string;
/** State of the map, which could include current zoom level, lat, lng etc. */
mapState?: string;
/** Maps-dashboards layers of the map */
layerList?: string;
/** UI state of the map */
uiState?: string;
/** Version is used to track version differences in saved object mapping */
version: number;
/** SearchSourceFields is used to reference other saved objects */
searchSourceFields?: {
index?: string;
};
}
2 changes: 1 addition & 1 deletion maps_dashboards/opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"opensearchDashboardsVersion": "3.0.0",
"server": true,
"ui": true,
"requiredPlugins": ["navigation", "opensearchDashboardsReact"],
"requiredPlugins": ["navigation", "opensearchDashboardsReact", "savedObjects"],
"optionalPlugins": []
}
20 changes: 7 additions & 13 deletions maps_dashboards/public/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,16 @@

import React from 'react';
import ReactDOM from 'react-dom';
import { AppMountParameters, CoreStart } from '../../../src/core/public';
import { AppPluginStartDependencies } from './types';
import { AppMountParameters } from '../../../src/core/public';
import { MapServices } from './types';
import { MapsDashboardsApp } from './components/app';
import { OpenSearchDashboardsContextProvider } from '../../../src/plugins/opensearch_dashboards_react/public';

export const renderApp = (
{ notifications, http }: CoreStart,
{ navigation }: AppPluginStartDependencies,
{ appBasePath, element }: AppMountParameters
) => {
export const renderApp = ({ element }: AppMountParameters, services: MapServices) => {
ReactDOM.render(
<MapsDashboardsApp
basename={appBasePath}
notifications={notifications}
http={http}
navigation={navigation}
/>,
<OpenSearchDashboardsContextProvider services={services}>
<MapsDashboardsApp />
</OpenSearchDashboardsContextProvider>,
element
);

Expand Down
32 changes: 12 additions & 20 deletions maps_dashboards/public/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,26 @@
*/

import React from 'react';
import { HashRouter as Router, Route, Switch } from 'react-router-dom';
import { Router, Route, Switch } from 'react-router-dom';
import { I18nProvider } from '@osd/i18n/react';
import { MapsList } from './maps_list';
import { MapContainer } from './map_container';
import { CoreStart } from '../../../../src/core/public';
import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public';
import { APP_PATH } from '../../common/index';
import { MapPage } from './map_page';
import { APP_PATH } from '../../common';
import { useOpenSearchDashboards } from '../../../../src/plugins/opensearch_dashboards_react/public';
import { MapServices } from '../types';

interface MapsDashboardsAppDeps {
basename: string;
notifications: CoreStart['notifications'];
http: CoreStart['http'];
navigation: NavigationPublicPluginStart;
}

export const MapsDashboardsApp = ({ basename, notifications, http }: MapsDashboardsAppDeps) => {
export const MapsDashboardsApp = () => {
const {
services: { appBasePath },
} = useOpenSearchDashboards<MapServices>();
// Render the application DOM.
return (
<Router basename={basename}>
<Router history={appBasePath}>
<I18nProvider>
<div>
<Switch>
<Route path={APP_PATH.CREATE_MAP} render={(props) => <MapContainer />} />
<Route
exact
path="/"
render={() => <MapsList http={http} notifications={notifications} />}
/>
<Route path={APP_PATH.CREATE_MAP} render={() => <MapPage />} />
<Route exact path="/" render={() => <MapsList />} />
</Switch>
</div>
</I18nProvider>
Expand Down
6 changes: 6 additions & 0 deletions maps_dashboards/public/components/map_page/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export { MapPage } from './map_page';
17 changes: 17 additions & 0 deletions maps_dashboards/public/components/map_page/map_page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { MapContainer } from '../map_container';
import { MapTopNavMenu } from '../map_top_nav';

export const MapPage = () => {
return (
<div>
<MapTopNavMenu />
<MapContainer />
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { i18n } from '@osd/i18n';
import { TopNavMenuData } from '../../../../../src/plugins/navigation/public';
import {
OnSaveProps,
SavedObjectSaveModalOrigin,
showSaveModal,
} from '../../../../../src/plugins/saved_objects/public';
import { useOpenSearchDashboards } from '../../../../../src/plugins/opensearch_dashboards_react/public';
import { MapServices } from '../../types';

export const getTopNavConfig = () => {
const {
services: {
notifications: { toasts },
i18n: { Context: I18nContext },
savedObjects: { client: savedObjectsClient },
},
// eslint-disable-next-line react-hooks/rules-of-hooks
} = useOpenSearchDashboards<MapServices>();
const topNavConfig: TopNavMenuData[] = [
{
iconType: 'save',
emphasize: true,
id: 'save',
label: i18n.translate('maps.topNav.saveMapButtonLabel', {
defaultMessage: `Save`,
}),
run: (_anchorElement) => {
const onModalSave = async (onSaveProps: OnSaveProps) => {
const savedMap = await savedObjectsClient.create('map', {
title: onSaveProps.newTitle,
description: onSaveProps.newDescription,
// TODO: Integrate other attributes to saved object
});
const id = savedMap.id;
if (id) {
toasts.addSuccess({
title: i18n.translate('map.topNavMenu.saveMap.successNotificationText', {
defaultMessage: `Saved ${onSaveProps.newTitle}`,
values: {
visTitle: savedMap.attributes.title,
},
}),
});
}
return { id };
};

const documentInfo = {
title: '',
description: '',
};
const saveModal = (
<SavedObjectSaveModalOrigin
documentInfo={documentInfo}
onSave={onModalSave}
objectType={'map'}
onClose={() => {}}
/>
);
showSaveModal(saveModal, I18nContext);
},
},
];
return topNavConfig;
};
6 changes: 6 additions & 0 deletions maps_dashboards/public/components/map_top_nav/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export { MapTopNavMenu } from './top_nav_menu';
28 changes: 28 additions & 0 deletions maps_dashboards/public/components/map_top_nav/top_nav_menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { PLUGIN_ID } from '../../../common';
import { getTopNavConfig } from './get_top_nav_config';
import { useOpenSearchDashboards } from '../../../../../src/plugins/opensearch_dashboards_react/public';
import { MapServices } from '../../types';

export const MapTopNavMenu = () => {
const {
services: {
setHeaderActionMenu,
navigation: {
ui: { TopNavMenu },
},
},
} = useOpenSearchDashboards<MapServices>();
return (
<TopNavMenu
appName={PLUGIN_ID}
config={getTopNavConfig()}
setMenuMountPoint={setHeaderActionMenu}
/>
);
};
79 changes: 51 additions & 28 deletions maps_dashboards/public/components/maps_list/maps_list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,71 @@ import { i18n } from '@osd/i18n';
import React, { useCallback } from 'react';
import { I18nProvider } from '@osd/i18n/react';
import { EuiPage, EuiPageBody, EuiPageContentBody } from '@elastic/eui';
import { CoreStart } from 'opensearch-dashboards/public';
import { TableListView } from '../../../../../src/plugins/opensearch_dashboards_react/public';

export const MapsList = (props: {
notifications: CoreStart['notifications'];
http: CoreStart['http'];
}) => {
const { http } = props;
const find = async (num: number) => {
const res = await http.post('/api/maps-dashboards/example');
return {
total: num,
hits: res.hits,
};
};
import {
TableListView,
useOpenSearchDashboards,
} from '../../../../../src/plugins/opensearch_dashboards_react/public';
import { MapSavedObjectAttributes } from '../../../common/map_saved_object_attributes';
import { MapServices } from '../../types';

export const MapsList = () => {
const {
services: {
notifications: { toasts },
http: { basePath },
savedObjects: { client: savedObjectsClient },
application: { navigateToUrl },
},
} = useOpenSearchDashboards<MapServices>();
const tableColumns = [
{
field: 'title',
field: 'attributes.title',
name: i18n.translate('maps.listing.table.titleColumnName', {
defaultMessage: 'Title',
}),
sortable: true,
},
{
field: 'description',
field: 'attributes.description',
name: i18n.translate('maps.listing.table.descriptionColumnName', {
defaultMessage: 'Description',
}),
sortable: true,
},
];

const createItem = useCallback(() => {
window.location.href = http.basePath.prepend('/app/maps-dashboards/#/create-map');
}, [http.basePath]);
const createMap = () => {
navigateToUrl(basePath.prepend('/app/maps-dashboards/create-map'));
};

const findItem = find.bind(null, 3);
const fetchMaps = useCallback(async (): Promise<{
total: number;
hits: object[];
}> => {
const res = await savedObjectsClient.find<MapSavedObjectAttributes>({
type: 'map',
fields: ['description', 'title'],
});
return {
total: res.total,
hits: res.savedObjects,
};
}, [savedObjectsClient]);

const deleteItems = async () => {
await Promise.all([]);
};
const deleteMaps = useCallback(
async (selectedItems: object[]) => {
await Promise.all(
selectedItems.map((item: any) => savedObjectsClient.delete(item.type, item.id))
).catch((error) => {
toasts.addError(error, {
title: i18n.translate('map.mapListingDeleteErrorTitle', {
defaultMessage: 'Error deleting map',
}),
});
});
},
[savedObjectsClient, toasts]
);

const editItem = useCallback(() => {}, []);

Expand All @@ -61,9 +84,9 @@ export const MapsList = (props: {
<EuiPageContentBody>
<TableListView
headingId="mapsListingHeading"
createItem={createItem}
findItems={findItem}
deleteItems={deleteItems}
createItem={createMap}
findItems={fetchMaps}
deleteItems={deleteMaps}
editItem={editItem}
tableColumns={tableColumns}
listingLimit={10}
Expand All @@ -79,7 +102,7 @@ export const MapsList = (props: {
tableListTitle={i18n.translate('maps.listing.table.listTitle', {
defaultMessage: 'Maps',
})}
toastNotifications={props.notifications.toasts}
toastNotifications={toasts}
/>
</EuiPageContentBody>
</EuiPageBody>
Expand Down
12 changes: 11 additions & 1 deletion maps_dashboards/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
MapsDashboardsPluginSetup,
MapsDashboardsPluginStart,
AppPluginStartDependencies,
MapServices,
} from './types';
import { PLUGIN_NAME, PLUGIN_ID } from '../common';

Expand All @@ -31,8 +32,17 @@ export class MapsDashboardsPlugin
const { renderApp } = await import('./application');
// Get start services as specified in opensearch_dashboards.json
const [coreStart, depsStart] = await core.getStartServices();
const { navigation } = depsStart as AppPluginStartDependencies;
const services: MapServices = {
...coreStart,
setHeaderActionMenu: params.setHeaderActionMenu,
appBasePath: params.history,
element: params.element,
navigation,
toastNotifications: coreStart.notifications.toasts,
};
// Render the application
return renderApp(coreStart, depsStart as AppPluginStartDependencies, params);
return renderApp(params, services);
},
});

Expand Down
Loading

0 comments on commit d7270dc

Please sign in to comment.