diff --git a/CHANGELOG.md b/CHANGELOG.md
index b9734f3d1de6..05422def4ac4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -66,6 +66,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Make build scripts find and use the latest version of Node.js that satisfies `engines.node` ([#3467](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/3467))
- [Multiple DataSource] Refactor test connection to support SigV4 auth type ([#3456](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/3456))
- [Darwin] Add support for Darwin for running OpenSearch snapshots with `yarn opensearch snapshot` ([#3537](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3537))
+- [Point in TIme] Add management plugin shell and empty state ([#2813](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2813))
### 🐛 Bug Fixes
diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/opensearch-dashboards-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/opensearch-dashboards-docker
index de9ec4e4b5de..f46482d3ca2f 100755
--- a/src/dev/build/tasks/os_packages/docker_generator/resources/bin/opensearch-dashboards-docker
+++ b/src/dev/build/tasks/os_packages/docker_generator/resources/bin/opensearch-dashboards-docker
@@ -161,6 +161,7 @@ opensearch_dashboards_vars=(
data_source.audit.appender.layout.kind
data_source.audit.appender.layout.highlight
data_source.audit.appender.layout.pattern
+ pit.enabled
)
longopts=''
diff --git a/src/plugins/point_in_time_management/opensearch_dashboards.json b/src/plugins/point_in_time_management/opensearch_dashboards.json
new file mode 100644
index 000000000000..1757278f19a6
--- /dev/null
+++ b/src/plugins/point_in_time_management/opensearch_dashboards.json
@@ -0,0 +1,10 @@
+{
+ "id": "pit",
+ "version": "1.0.0",
+ "opensearchDashboardsVersion": "opensearchDashboards",
+ "server": true,
+ "ui": true,
+ "requiredPlugins": ["navigation", "management"],
+ "optionalPlugins": [],
+ "requiredBundles": ["opensearchDashboardsReact"]
+}
diff --git a/src/plugins/point_in_time_management/public/components/empty_state/__snapshots__/empty_state.test.tsx.snap b/src/plugins/point_in_time_management/public/components/empty_state/__snapshots__/empty_state.test.tsx.snap
new file mode 100644
index 000000000000..cc1ee347208f
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/components/empty_state/__snapshots__/empty_state.test.tsx.snap
@@ -0,0 +1,84 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`EmptyState should render normally 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No point in time objects have been created yet.
+
+
+
+
+
+
+
+
+
+`;
diff --git a/src/plugins/point_in_time_management/public/components/empty_state/empty_state.test.tsx b/src/plugins/point_in_time_management/public/components/empty_state/empty_state.test.tsx
new file mode 100644
index 000000000000..82393e830152
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/components/empty_state/empty_state.test.tsx
@@ -0,0 +1,16 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EmptyState } from './empty_state';
+import { shallow } from 'enzyme';
+
+describe('EmptyState', () => {
+ it('should render normally', () => {
+ const component = shallow();
+
+ expect(component).toMatchSnapshot();
+ });
+});
diff --git a/src/plugins/point_in_time_management/public/components/empty_state/empty_state.tsx b/src/plugins/point_in_time_management/public/components/empty_state/empty_state.tsx
new file mode 100644
index 000000000000..650c742c6744
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/components/empty_state/empty_state.tsx
@@ -0,0 +1,78 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { FormattedMessage } from '@osd/i18n/react';
+import {
+ EuiPageContentHeader,
+ EuiPageContentHeaderSection,
+ EuiTitle,
+ EuiPageContent,
+ EuiSpacer,
+ EuiText,
+ EuiPageContentBody,
+ EuiFlexItem,
+ EuiFlexGroup,
+ EuiButton,
+} from '@elastic/eui';
+
+export const EmptyState = () => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No point in time objects have been created yet.
+
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/src/plugins/point_in_time_management/public/components/empty_state/index.ts b/src/plugins/point_in_time_management/public/components/empty_state/index.ts
new file mode 100644
index 000000000000..c903066cdbb0
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/components/empty_state/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { EmptyState } from './empty_state';
diff --git a/src/plugins/point_in_time_management/public/components/index.ts b/src/plugins/point_in_time_management/public/components/index.ts
new file mode 100644
index 000000000000..c903066cdbb0
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/components/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { EmptyState } from './empty_state';
diff --git a/src/plugins/point_in_time_management/public/index.ts b/src/plugins/point_in_time_management/public/index.ts
new file mode 100644
index 000000000000..2c2ecadca2e3
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/index.ts
@@ -0,0 +1,12 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { PointInTimeManagementPlugin } from './plugin';
+
+export function plugin() {
+ return new PointInTimeManagementPlugin();
+}
+
+export { PointInTimeManagementPluginSetup, PointInTimeManagementPluginStart } from './types';
diff --git a/src/plugins/point_in_time_management/public/management_app/index.ts b/src/plugins/point_in_time_management/public/management_app/index.ts
new file mode 100644
index 000000000000..414bc60e89cc
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/management_app/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { mountManagementSection } from './mount_management_section';
diff --git a/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx b/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx
new file mode 100644
index 000000000000..96c87fc73538
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/management_app/mount_management_section.tsx
@@ -0,0 +1,38 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { I18nProvider } from '@osd/i18n/react';
+import { ManagementAppMountParams } from '../../../management/public';
+import { PointInTimeManagementStartDependencies } from '../plugin';
+import { StartServicesAccessor } from '../../../../core/public';
+import { PointInTimeManagementContext } from '../types';
+import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public';
+import { EmptyState } from '../components';
+
+export async function mountManagementSection(
+ getStartServices: StartServicesAccessor,
+ params: ManagementAppMountParams
+) {
+ const [{ chrome, application }] = await getStartServices();
+ const deps: PointInTimeManagementContext = {
+ chrome,
+ application,
+ };
+ ReactDOM.render(
+
+
+
+
+ ,
+ params.element
+ );
+
+ return () => {
+ chrome.docTitle.reset();
+ ReactDOM.unmountComponentAtNode(params.element);
+ };
+}
diff --git a/src/plugins/point_in_time_management/public/plugin.ts b/src/plugins/point_in_time_management/public/plugin.ts
new file mode 100644
index 000000000000..53a1421926e4
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/plugin.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { i18n } from '@osd/i18n';
+import { CoreSetup, CoreStart, Plugin } from '../../../core/public';
+import { PointInTimeManagementPluginSetup, PointInTimeManagementPluginStart } from './types';
+import { ManagementSetup } from '../../management/public';
+
+export interface PointInTimeManagementSetupDependencies {
+ management: ManagementSetup;
+}
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface PointInTimeManagementStartDependencies {}
+
+const sectionsHeader = i18n.translate('pointInTimeManagement.pointInTime.sectionsHeader', {
+ defaultMessage: 'Point In Time',
+});
+
+const PITM_APP_ID = 'pointInTime';
+
+export class PointInTimeManagementPlugin
+ implements
+ Plugin<
+ PointInTimeManagementPluginSetup,
+ PointInTimeManagementPluginStart,
+ PointInTimeManagementSetupDependencies,
+ PointInTimeManagementStartDependencies
+ > {
+ public setup(
+ core: CoreSetup,
+ { management }: PointInTimeManagementSetupDependencies
+ ): PointInTimeManagementPluginSetup {
+ const opensearchDashboardsSection = management.sections.section.opensearchDashboards;
+
+ if (!opensearchDashboardsSection) {
+ throw new Error('`opensearchDashboards` management section not found.');
+ }
+
+ opensearchDashboardsSection.registerApp({
+ id: PITM_APP_ID,
+ title: sectionsHeader,
+ order: 1,
+ mount: async (mountParams) => {
+ const { mountManagementSection } = await import('./management_app');
+ return mountManagementSection(core.getStartServices, mountParams);
+ },
+ });
+
+ return {};
+ }
+
+ public start(core: CoreStart): PointInTimeManagementPluginStart {
+ return {};
+ }
+
+ public stop() {}
+}
diff --git a/src/plugins/point_in_time_management/public/types.ts b/src/plugins/point_in_time_management/public/types.ts
new file mode 100644
index 000000000000..fc0c5b7038c8
--- /dev/null
+++ b/src/plugins/point_in_time_management/public/types.ts
@@ -0,0 +1,27 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { ApplicationStart, ChromeStart } from 'opensearch-dashboards/public';
+import { NavigationPublicPluginStart } from '../../navigation/public';
+import { ManagementSetup } from '../../management/public';
+
+export interface PointInTimeManagementContext {
+ chrome: ChromeStart;
+ application: ApplicationStart;
+}
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface PointInTimeManagementPluginSetup {}
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface PointInTimeManagementPluginStart {}
+
+export interface AppPluginStartDependencies {
+ navigation: NavigationPublicPluginStart;
+}
+
+export interface SetupDependencies {
+ management: ManagementSetup;
+}
diff --git a/src/plugins/point_in_time_management/server/index.ts b/src/plugins/point_in_time_management/server/index.ts
new file mode 100644
index 000000000000..bcc35da781c8
--- /dev/null
+++ b/src/plugins/point_in_time_management/server/index.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { schema } from '@osd/config-schema';
+import { PluginInitializerContext } from '../../../core/server';
+import { PointInTimeManagementPlugin } from './plugin';
+
+export const config = {
+ schema: schema.object({ enabled: schema.boolean({ defaultValue: false }) }),
+};
+
+// This exports static code and TypeScript types,
+// as well as the OpenSearch Dashboards Platform `plugin()` initializer.
+
+export function plugin(initializerContext: PluginInitializerContext) {
+ return new PointInTimeManagementPlugin(initializerContext);
+}
+
+export { PointInTimeManagementPluginSetup, PointInTimeManagementPluginStart } from './types';
diff --git a/src/plugins/point_in_time_management/server/plugin.ts b/src/plugins/point_in_time_management/server/plugin.ts
new file mode 100644
index 000000000000..876e4271d432
--- /dev/null
+++ b/src/plugins/point_in_time_management/server/plugin.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {
+ PluginInitializerContext,
+ CoreSetup,
+ CoreStart,
+ Plugin,
+ Logger,
+} from '../../../core/server';
+
+import { PointInTimeManagementPluginSetup, PointInTimeManagementPluginStart } from './types';
+import { defineRoutes } from './routes';
+
+export class PointInTimeManagementPlugin
+ implements Plugin {
+ private readonly logger: Logger;
+
+ constructor(initializerContext: PluginInitializerContext) {
+ this.logger = initializerContext.logger.get();
+ }
+
+ public setup(core: CoreSetup) {
+ this.logger.debug('pointInTimeManagement: Setup');
+ const router = core.http.createRouter();
+
+ defineRoutes(router);
+
+ return {};
+ }
+
+ public start(core: CoreStart) {
+ this.logger.debug('pointInTimeManagement: Started');
+ return {};
+ }
+
+ public stop() {}
+}
diff --git a/src/plugins/point_in_time_management/server/routes/index.ts b/src/plugins/point_in_time_management/server/routes/index.ts
new file mode 100644
index 000000000000..b56d1871d7dd
--- /dev/null
+++ b/src/plugins/point_in_time_management/server/routes/index.ts
@@ -0,0 +1,22 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { IRouter } from '../../../../core/server';
+
+export function defineRoutes(router: IRouter) {
+ router.get(
+ {
+ path: '/api/point_in_time_management/test',
+ validate: false,
+ },
+ async (context, request, response) => {
+ return response.ok({
+ body: {
+ time: new Date().toISOString(),
+ },
+ });
+ }
+ );
+}
diff --git a/src/plugins/point_in_time_management/server/types.ts b/src/plugins/point_in_time_management/server/types.ts
new file mode 100644
index 000000000000..d9c957b4edc3
--- /dev/null
+++ b/src/plugins/point_in_time_management/server/types.ts
@@ -0,0 +1,9 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface PointInTimeManagementPluginSetup {}
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface PointInTimeManagementPluginStart {}