diff --git a/changelogs/fragments/7802.yml b/changelogs/fragments/7802.yml
new file mode 100644
index 000000000000..2937e55931ae
--- /dev/null
+++ b/changelogs/fragments/7802.yml
@@ -0,0 +1,2 @@
+feat:
+- Add home icon in left bottom ([#7802](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7802))
\ No newline at end of file
diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap
index 95e501650f08..7f896674faac 100644
--- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap
+++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap
@@ -236,7 +236,7 @@ exports[` should render correctly 1`] = `
class="euiHorizontalRule euiHorizontalRule--full"
/>
@@ -260,7 +260,7 @@ exports[` should render correctly 2`] = `
class="euiHorizontalRule euiHorizontalRule--full"
/>
@@ -333,7 +333,7 @@ exports[` should show all use case by default and
class="euiHorizontalRule euiHorizontalRule--full"
/>
@@ -406,7 +406,7 @@ exports[` should show all use case when current na
class="euiHorizontalRule euiHorizontalRule--full"
/>
diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss
index 39978cc2eff6..978ed743a24b 100644
--- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss
+++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss
@@ -62,6 +62,7 @@
.bottom-container {
padding: 0 $euiSize;
display: flex;
+ -ms-overflow-style: -ms-autohiding-scrollbar;
&.bottom-container-collapsed {
flex-direction: column;
diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx
index af67974ecb9d..d196e760e43b 100644
--- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx
+++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx
@@ -435,6 +435,7 @@ export function CollapsibleNavGroupEnabled({
', () => {
+ it('should call chrome.navGroup.setCurrentNavGroup and application.navigateToApp methods from core service when click', () => {
+ const coreStartMock = coreMock.createStart();
+ const { container } = render();
+ const component = container.children[0];
+ fireEvent.click(component);
+ expect(coreStartMock.application.navigateToApp).toBeCalledWith('foo');
+ });
+});
diff --git a/src/plugins/home/public/application/components/home_icon.tsx b/src/plugins/home/public/application/components/home_icon.tsx
new file mode 100644
index 000000000000..705b89df9bab
--- /dev/null
+++ b/src/plugins/home/public/application/components/home_icon.tsx
@@ -0,0 +1,20 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { EuiButtonIcon } from '@elastic/eui';
+import { CoreStart } from 'opensearch-dashboards/public';
+
+export function HomeIcon({ core, appId }: { core: CoreStart; appId: string }) {
+ return (
+ {
+ core.application.navigateToApp(appId);
+ }}
+ />
+ );
+}
diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts
index fe1099a8e635..cf499c19ddb9 100644
--- a/src/plugins/home/public/plugin.ts
+++ b/src/plugins/home/public/plugin.ts
@@ -37,6 +37,7 @@ import {
} from 'opensearch-dashboards/public';
import { i18n } from '@osd/i18n';
import { first } from 'rxjs/operators';
+import React from 'react';
import { Branding } from 'src/core/types';
import {
@@ -70,6 +71,8 @@ import {
ContentManagementPluginStart,
} from '../../content_management/public';
import { initHome, setupHome } from './application/home_render';
+import { toMountPoint } from '../../opensearch_dashboards_react/public';
+import { HomeIcon } from './application/components/home_icon';
export interface HomePluginStartDependencies {
data: DataPublicPluginStart;
@@ -151,9 +154,7 @@ export class HomePublicPlugin
core.application.register({
id: PLUGIN_ID,
title: 'Home',
- navLinkStatus: core.chrome.navGroup.getNavGroupEnabled()
- ? undefined
- : AppNavLinkStatus.hidden,
+ navLinkStatus: AppNavLinkStatus.hidden,
mount: async (params: AppMountParameters) => {
const [coreStart] = await core.getStartServices();
setCommonService();
@@ -166,13 +167,6 @@ export class HomePublicPlugin
workspaceAvailability: WorkspaceAvailability.outsideWorkspace,
});
- core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [
- {
- id: PLUGIN_ID,
- title: 'Home',
- },
- ]);
-
// Register import sample data as a standalone app so that it is available inside workspace.
core.application.register({
id: IMPORT_SAMPLE_DATA_APP_ID,
@@ -255,6 +249,18 @@ export class HomePublicPlugin
});
}
+ if (core.chrome.navGroup.getNavGroupEnabled()) {
+ core.chrome.navControls.registerLeftBottom({
+ order: 0,
+ mount: toMountPoint(
+ React.createElement(HomeIcon, {
+ core,
+ appId: PLUGIN_ID,
+ })
+ ),
+ });
+ }
+
return {
featureCatalogue: this.featuresCatalogueRegistry,
getSavedHomepageLoader: () => this.sectionTypeService.getSavedHomepageLoader(),
diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts
index 2f69c1587c65..104507f028e2 100644
--- a/src/plugins/saved_objects_management/public/plugin.ts
+++ b/src/plugins/saved_objects_management/public/plugin.ts
@@ -198,7 +198,7 @@ export class SavedObjectsManagementPlugin
core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [
{
id: APP_ID,
- order: 300,
+ order: 400,
},
]);
diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts
index 311fc20ed85d..835bfb306796 100644
--- a/src/plugins/visualize/public/plugin.ts
+++ b/src/plugins/visualize/public/plugin.ts
@@ -228,11 +228,16 @@ export class VisualizePlugin
},
});
+ const titleInLeftNav = i18n.translate('visualize.leftNav.visualizeTitle', {
+ defaultMessage: 'Visualizations',
+ });
+
core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [
{
id: visualizeAppId,
category: DEFAULT_APP_CATEGORIES.visualizeAndReport,
order: 200,
+ title: titleInLeftNav,
},
]);
core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [
@@ -240,13 +245,15 @@ export class VisualizePlugin
id: visualizeAppId,
category: DEFAULT_APP_CATEGORIES.visualizeAndReport,
order: 200,
+ title: titleInLeftNav,
},
]);
core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.essentials, [
{
id: visualizeAppId,
- category: DEFAULT_APP_CATEGORIES.visualizeAndReport,
- order: 200,
+ category: undefined,
+ order: 400,
+ title: titleInLeftNav,
},
]);
core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.search, [
@@ -254,6 +261,7 @@ export class VisualizePlugin
id: visualizeAppId,
category: DEFAULT_APP_CATEGORIES.analyzeSearch,
order: 400,
+ title: titleInLeftNav,
},
]);
core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [
@@ -261,6 +269,7 @@ export class VisualizePlugin
id: visualizeAppId,
category: undefined,
order: 400,
+ title: titleInLeftNav,
},
]);
diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx
index c2e8e39331d4..2ef12e3f12bb 100644
--- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx
+++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx
@@ -108,7 +108,7 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => {
};
const currentWorkspaceButton = currentWorkspace ? (
-
+
{
expect.arrayContaining([
{
id: 'workspace_list',
- order: 150,
- title: 'Workspace settings',
+ order: 350,
+ title: 'Workspaces',
},
])
);
});
- it('#setup should register workspace detail with a visible application and register to all nav group', async () => {
+ it('#setup should register workspace detail', async () => {
const setupMock = coreMock.createSetup();
setupMock.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true);
const workspacePlugin = new WorkspacePlugin();
@@ -189,20 +189,8 @@ describe('Workspace plugin', () => {
expect(setupMock.application.register).toHaveBeenCalledWith(
expect.objectContaining({
id: 'workspace_detail',
- navLinkStatus: AppNavLinkStatus.hidden,
})
);
-
- expect(setupMock.chrome.navGroup.addNavLinksToGroup).toHaveBeenCalledWith(
- DEFAULT_NAV_GROUPS.all,
- expect.arrayContaining([
- {
- id: 'workspace_detail',
- title: 'Overview',
- order: 100,
- },
- ])
- );
});
it('#setup should register workspace initial with a visible application', async () => {
diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts
index 4731e9d205b7..1617744fa9ff 100644
--- a/src/plugins/workspace/public/plugin.ts
+++ b/src/plugins/workspace/public/plugin.ts
@@ -113,19 +113,7 @@ export class WorkspacePlugin
this.registeredUseCases$,
]).subscribe(([currentWorkspace, registeredUseCases]) => {
if (currentWorkspace) {
- const isAllUseCase =
- getFirstUseCaseOfFeatureConfigs(currentWorkspace.features || []) === ALL_USE_CASE_ID;
this.appUpdater$.next((app) => {
- // When in all workspace, the home should be replaced by workspace detail page
- if (app.id === 'home' && isAllUseCase) {
- return { navLinkStatus: AppNavLinkStatus.hidden };
- }
-
- // show the overview page in all use case
- if (app.id === WORKSPACE_DETAIL_APP_ID && isAllUseCase) {
- return { navLinkStatus: AppNavLinkStatus.visible };
- }
-
if (isAppAccessibleInWorkspace(app, currentWorkspace, registeredUseCases)) {
return;
}
@@ -356,7 +344,6 @@ export class WorkspacePlugin
title: i18n.translate('workspace.settings.workspaceDetail', {
defaultMessage: 'Workspace Detail',
}),
- navLinkStatus: AppNavLinkStatus.hidden,
async mount(params: AppMountParameters) {
const { renderDetailApp } = await import('./application');
return mountWorkspaceApp(params, renderDetailApp);
@@ -425,16 +412,6 @@ export class WorkspacePlugin
workspaceAvailability: WorkspaceAvailability.outsideWorkspace,
});
- core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [
- {
- id: WORKSPACE_DETAIL_APP_ID,
- order: 100,
- title: i18n.translate('workspace.nav.workspaceDetail.title', {
- defaultMessage: 'Overview',
- }),
- },
- ]);
-
/**
* register workspace column into saved objects table
*/
@@ -446,9 +423,9 @@ export class WorkspacePlugin
core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [
{
id: WORKSPACE_LIST_APP_ID,
- order: 150,
- title: i18n.translate('workspace.settings.workspaceSettings', {
- defaultMessage: 'Workspace settings',
+ order: 350,
+ title: i18n.translate('workspace.settings.workspaces', {
+ defaultMessage: 'Workspaces',
}),
},
]);
diff --git a/src/plugins/workspace/public/services/use_case_service.test.ts b/src/plugins/workspace/public/services/use_case_service.test.ts
index 00938fd7d60d..17f977474f07 100644
--- a/src/plugins/workspace/public/services/use_case_service.test.ts
+++ b/src/plugins/workspace/public/services/use_case_service.test.ts
@@ -5,14 +5,17 @@
import { BehaviorSubject } from 'rxjs';
import { first } from 'rxjs/operators';
-import { chromeServiceMock } from '../../../../core/public/mocks';
+import { chromeServiceMock, coreMock } from '../../../../core/public/mocks';
import {
ALL_USE_CASE_ID,
+ DEFAULT_APP_CATEGORIES,
DEFAULT_NAV_GROUPS,
NavGroupItemInMap,
NavGroupType,
} from '../../../../core/public';
import { UseCaseService } from './use_case_service';
+import { waitFor } from '@testing-library/dom';
+import { WORKSPACE_DETAIL_APP_ID } from '../../common/constants';
const mockNavGroupsMap = {
system: {
@@ -61,6 +64,54 @@ const setupUseCaseStart = (options?: { navGroupEnabled?: boolean }) => {
};
describe('UseCaseService', () => {
+ describe('#setup', () => {
+ it('should add manage workspace category to current use case', async () => {
+ const useCaseService = new UseCaseService();
+ const coreSetup = coreMock.createSetup();
+ const navGroupMap$ = new BehaviorSubject>({});
+ const coreStartMock = coreMock.createStart();
+ coreSetup.getStartServices.mockResolvedValue([coreStartMock, {}, {}]);
+ coreStartMock.chrome.navGroup.getNavGroupsMap$.mockReturnValue(navGroupMap$);
+ useCaseService.setup(coreSetup);
+ const navGroupInfo = {
+ ...DEFAULT_NAV_GROUPS.all,
+ navLinks: [],
+ };
+ navGroupMap$.next({
+ [ALL_USE_CASE_ID]: navGroupInfo,
+ });
+ coreSetup.workspaces.currentWorkspace$.next({
+ id: ALL_USE_CASE_ID,
+ name: ALL_USE_CASE_ID,
+ features: [`use-case-${ALL_USE_CASE_ID}`],
+ });
+ await waitFor(() => {
+ expect(coreSetup.chrome.navGroup.addNavLinksToGroup).toBeCalledWith(navGroupInfo, [
+ {
+ id: 'dataSources_core',
+ category: DEFAULT_APP_CATEGORIES.manageWorkspace,
+ order: 100,
+ },
+ {
+ id: 'indexPatterns',
+ category: DEFAULT_APP_CATEGORIES.manageWorkspace,
+ order: 200,
+ },
+ {
+ id: 'objects',
+ category: DEFAULT_APP_CATEGORIES.manageWorkspace,
+ order: 300,
+ },
+ {
+ id: WORKSPACE_DETAIL_APP_ID,
+ category: DEFAULT_APP_CATEGORIES.manageWorkspace,
+ order: 400,
+ title: 'Workspace settings',
+ },
+ ]);
+ });
+ });
+ });
describe('#start', () => {
it('should return built in use cases when nav group disabled', async () => {
const { useCaseStart } = setupUseCaseStart({
diff --git a/src/plugins/workspace/public/services/use_case_service.ts b/src/plugins/workspace/public/services/use_case_service.ts
index 59764a256480..7807c4af3881 100644
--- a/src/plugins/workspace/public/services/use_case_service.ts
+++ b/src/plugins/workspace/public/services/use_case_service.ts
@@ -5,6 +5,7 @@
import { combineLatest, Observable, Subscription } from 'rxjs';
import { distinctUntilChanged, map } from 'rxjs/operators';
+import { i18n } from '@osd/i18n';
import {
ChromeStart,
@@ -15,7 +16,7 @@ import {
DEFAULT_NAV_GROUPS,
ALL_USE_CASE_ID,
} from '../../../../core/public';
-import { WORKSPACE_USE_CASES } from '../../common/constants';
+import { WORKSPACE_DETAIL_APP_ID, WORKSPACE_USE_CASES } from '../../common/constants';
import {
convertNavGroupToWorkspaceUseCase,
getFirstUseCaseOfFeatureConfigs,
@@ -78,6 +79,14 @@ export class UseCaseService {
category: DEFAULT_APP_CATEGORIES.manageWorkspace,
order: 300,
},
+ {
+ id: WORKSPACE_DETAIL_APP_ID,
+ category: DEFAULT_APP_CATEGORIES.manageWorkspace,
+ order: 400,
+ title: i18n.translate('workspace.settings.workspaceSettings', {
+ defaultMessage: 'Workspace settings',
+ }),
+ },
]);
}
});