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

[Workspace][Page header] Integrate new page header for workspace pages #7697

Merged
merged 5 commits into from
Aug 15, 2024
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/7697.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Integrate new page header for workspace pages ([#7697](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7697))
3 changes: 2 additions & 1 deletion src/plugins/management/opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"server": true,
"ui": true,
"optionalPlugins": ["home", "managementOverview"],
"requiredBundles": ["opensearchDashboardsReact", "opensearchDashboardsUtils"]
"requiredBundles": ["opensearchDashboardsReact", "opensearchDashboardsUtils"],
"requiredPlugins": ["navigation"]
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ import React from 'react';
import { fireEvent, render } from '@testing-library/react';
import { FeatureCards } from './feature_cards';
import { AppCategory, ChromeNavLink } from 'opensearch-dashboards/public';
import { navigationPluginMock } from '../../../../navigation/public/mocks';
import { coreMock } from '../../../../../../src/core/public/mocks';

const mockCategory: AppCategory = {
id: 'dashboard',
label: 'Dashboard',
order: 2,
};

const mockSetAppDescriptionControls = coreMock.createStart().application.setAppDescriptionControls;
const mockNavigationUI = navigationPluginMock.createStartContract().ui;
mockNavigationUI.HeaderControl = () => null;

const navLinks: ChromeNavLink[] = [
{
id: '1',
Expand Down Expand Up @@ -85,18 +91,25 @@ const navLinks: ChromeNavLink[] = [
describe('<FeatureCards />', () => {
it('render with empty navLinks', () => {
const { container } = render(
<FeatureCards getStartedCards={[]} pageTitle="" navLinks={[]} navigateToApp={jest.fn()} />
<FeatureCards
pageDescription=""
navLinks={[]}
navigateToApp={jest.fn()}
setAppDescriptionControls={mockSetAppDescriptionControls}
navigationUI={mockNavigationUI}
/>
);
expect(container).toMatchSnapshot();
});

it('render with complex navLinks', () => {
const { container, getAllByTestId } = render(
<FeatureCards
getStartedCards={[]}
pageTitle=""
pageDescription=""
navLinks={navLinks}
navigateToApp={jest.fn()}
setAppDescriptionControls={mockSetAppDescriptionControls}
navigationUI={mockNavigationUI}
/>
);
expect(container).toMatchSnapshot();
Expand All @@ -107,10 +120,11 @@ describe('<FeatureCards />', () => {
const mockedNavigateToApp = jest.fn();
const { getByTestId } = render(
<FeatureCards
getStartedCards={[]}
pageTitle=""
pageDescription=""
navLinks={navLinks}
navigateToApp={mockedNavigateToApp}
setAppDescriptionControls={mockSetAppDescriptionControls}
navigationUI={mockNavigationUI}
/>
);
fireEvent.click(getByTestId('landingPageFeature_1'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,32 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { i18n } from '@osd/i18n';
import {
EuiCard,
EuiFlexGrid,
EuiFlexGroup,
EuiFlexItem,
EuiPageContent,
EuiPageHeader,
EuiPageHeaderSection,
EuiPanel,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { AppCategory, ChromeNavLink, CoreStart } from 'opensearch-dashboards/public';
import React, { useMemo } from 'react';
import { NavigationPublicPluginStart } from '../../../../../../src/plugins/navigation/public';

export interface FeatureCardsProps {
pageTitle: string;
pageDescription: string;
navLinks: ChromeNavLink[];
navigateToApp: CoreStart['application']['navigateToApp'];
getStartedCards: Array<{
id: string;
title: string;
description: string;
}>;
setAppDescriptionControls: CoreStart['application']['setAppDescriptionControls'];
navigationUI: NavigationPublicPluginStart['ui'];
}

const getStartedTitle = i18n.translate('management.gettingStarted.label', {
defaultMessage: 'Get started',
});

export const FeatureCards = ({
navLinks,
navigateToApp,
pageTitle,
getStartedCards,
setAppDescriptionControls,
pageDescription,
navigationUI: { HeaderControl },
}: FeatureCardsProps) => {
const itemsPerRow = 4;
const groupedCardForDisplay = useMemo(() => {
Expand All @@ -65,41 +55,14 @@ export const FeatureCards = ({
}
return (
<>
<EuiPageContent borderRadius="none">
<EuiPageHeader>
<EuiPageHeaderSection>
<EuiTitle size="l">
<h1>{pageTitle}</h1>
</EuiTitle>
</EuiPageHeaderSection>
</EuiPageHeader>
{getStartedCards.length ? (
<>
<EuiSpacer size="s" />
<EuiTitle>
<h3>{getStartedTitle}</h3>
</EuiTitle>
<EuiFlexGrid columns={4}>
{getStartedCards.map((card) => {
return (
<EuiFlexItem>
<EuiPanel>
<EuiCard
title={card.title}
description={card.description}
data-test-subj={`getStartedCard_${card.id}`}
textAlign="left"
onClick={() => navigateToApp(card.id)}
titleSize="xs"
/>
</EuiPanel>
</EuiFlexItem>
);
})}
</EuiFlexGrid>
</>
) : null}
</EuiPageContent>
<HeaderControl
controls={[
{
description: pageDescription,
},
]}
setMountPoint={setAppDescriptionControls}
/>
<EuiPageContent hasShadow={false} hasBorder={false} color="transparent">
{groupedCardForDisplay.map((group) => (
<div key={group.category?.id}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
*/

import { renderApp } from './landing_page_application';
import { navigationPluginMock } from '../../navigation/public/mocks';
import { coreMock } from '../../../../src/core/public/mocks';

describe('Landing page application', () => {
it('renders and unmount without crashing', () => {
Expand All @@ -13,6 +15,9 @@ describe('Landing page application', () => {
props: {
navigateToApp: jest.fn(),
navLinks: [],
navigationUI: navigationPluginMock.createStartContract().ui,
setAppDescriptionControls: coreMock.createStart().application.setAppDescriptionControls,
pageDescription: '',
},
});

Expand Down
58 changes: 46 additions & 12 deletions src/plugins/management/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import {
AppNavLinkStatus,
DEFAULT_NAV_GROUPS,
WorkspaceAvailability,
ChromeNavLink,
} from '../../../core/public';

import { MANAGEMENT_APP_ID } from '../common/contants';
Expand All @@ -62,13 +61,17 @@ import {
LinkItemType,
getSortedNavLinks,
} from '../../../core/public';
import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public';

interface ManagementSetupDependencies {
home?: HomePublicPluginSetup;
managementOverview?: ManagementOverViewPluginSetup;
}

export class ManagementPlugin implements Plugin<ManagementSetup, ManagementStart> {
interface ManagementStartDependencies {
navigation: NavigationPublicPluginStart;
}
export class ManagementPlugin
implements Plugin<ManagementSetup, ManagementStart, {}, ManagementStartDependencies> {
private readonly managementSections = new ManagementSectionsService();

private readonly appUpdater = new BehaviorSubject<AppUpdater>(() => ({}));
Expand All @@ -81,7 +84,10 @@ export class ManagementPlugin implements Plugin<ManagementSetup, ManagementStart
defaultMessage: 'Dashboards Management',
});

public setup(core: CoreSetup, { home, managementOverview }: ManagementSetupDependencies) {
public setup(
core: CoreSetup<ManagementStartDependencies>,
{ home, managementOverview }: ManagementSetupDependencies
) {
const opensearchDashboardsVersion = this.initializerContext.env.packageInfo.version;

core.application.register({
Expand Down Expand Up @@ -111,15 +117,30 @@ export class ManagementPlugin implements Plugin<ManagementSetup, ManagementStart
const settingsLandingPageId = 'settings_landing';

const settingsLandingPageTitle = i18n.translate('management.settings.landingPage.title', {
defaultMessage: 'Settings and setup',
defaultMessage: 'Settings and setup overview',
});

const settingsLandingPageDescription = i18n.translate(
'management.settings.landingPage.description',
{
defaultMessage:
'Customize the appearance of the application, change feature behavior, and more.',
}
);

const dataAdministrationLandingPageId = 'data_administration_landing';

const dataAdministrationPageTitle = i18n.translate(
'management.dataAdministration.landingPage.title',
{
defaultMessage: 'Data administration',
defaultMessage: 'Data administration overview',
}
);

const dataAdministrationPageDescription = i18n.translate(
'management.dataAdministration.landingPage.description',
{
defaultMessage: 'Configure automation and access control policies to manage your data.',
}
);

Expand Down Expand Up @@ -186,18 +207,24 @@ export class ManagementPlugin implements Plugin<ManagementSetup, ManagementStart
workspaceAvailability: WorkspaceAvailability.outsideWorkspace,
mount: async (params: AppMountParameters) => {
const { renderApp } = await import('./landing_page_application');
const [coreStart] = await core.getStartServices();
const [coreStart, { navigation }] = await core.getStartServices();
const navLinks = (
await getNavLinksByNavGroupId(DEFAULT_NAV_GROUPS.settingsAndSetup.id)
).filter((navLink) => navLink.id !== settingsLandingPageId);

coreStart.chrome.setBreadcrumbs([
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: How about move page title update logic to FeatureCards component?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would say that I have no preference whether to still maintain it here or move it into component, because I think there won't be much difference on it or maintainability.

{
text: settingsLandingPageTitle,
},
]);
return renderApp({
mountElement: params.element,
props: {
navigateToApp: coreStart.application.navigateToApp,
setAppDescriptionControls: coreStart.application.setAppDescriptionControls,
navLinks,
pageTitle: settingsLandingPageTitle,
getStartedCards: [],
pageDescription: settingsLandingPageDescription,
navigationUI: navigation.ui,
},
});
},
Expand All @@ -213,18 +240,25 @@ export class ManagementPlugin implements Plugin<ManagementSetup, ManagementStart
workspaceAvailability: WorkspaceAvailability.outsideWorkspace,
mount: async (params: AppMountParameters) => {
const { renderApp } = await import('./landing_page_application');
const [coreStart] = await core.getStartServices();
const [coreStart, { navigation }] = await core.getStartServices();
const navLinks = (
await getNavLinksByNavGroupId(DEFAULT_NAV_GROUPS.dataAdministration.id)
).filter((navLink) => navLink.id !== dataAdministrationLandingPageId);

coreStart.chrome.setBreadcrumbs([
{
text: dataAdministrationPageTitle,
},
]);

return renderApp({
mountElement: params.element,
props: {
navigateToApp: coreStart.application.navigateToApp,
navLinks,
pageTitle: dataAdministrationPageTitle,
getStartedCards: [],
pageDescription: dataAdministrationPageDescription,
navigationUI: navigation.ui,
setAppDescriptionControls: coreStart.application.setAppDescriptionControls,
},
});
},
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/workspace/opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"ui": true,
"requiredPlugins": [
"savedObjects",
"opensearchDashboardsReact"
"opensearchDashboardsReact",
"navigation"
],
"optionalPlugins": ["savedObjectsManagement","management","dataSourceManagement","contentManagement"],
"requiredBundles": ["opensearchDashboardsReact", "home","dataSource"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ const WorkspaceCreator = ({
},
},
dataSourceManagement: {},
navigationUI: {
HeaderControl: () => null,
},
},
});
const registeredUseCases$ = new BehaviorSubject([
Expand Down
Loading
Loading