Skip to content

Commit

Permalink
Merge branch 'main' into feature/discover-pagination
Browse files Browse the repository at this point in the history
Signed-off-by: Kishor Rathva <kishorrathva8298@gmail.com>
  • Loading branch information
kishor82 committed Dec 19, 2023
2 parents dac7ad7 + 5695f9b commit d04f92f
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Decouple] Add new cross compatibility check core service which export functionality for plugins to verify if their OpenSearch plugin counterpart is installed on the cluster or has incompatible version to configure the plugin behavior([#4710](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4710))
- [Discover] Display inner properties in the left navigation bar [#5429](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5429)
- [Discover] Added customizable pagination options based on Discover UI settings [#5610](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5610)
- [Chrome] Introduce registerCollapsibleNavHeader to allow plugins to customize the rendering of nav menu header ([#5244](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5244))
- [Custom Branding] Relative URL should be allowed for logos ([#5572](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5572))

### 🐛 Bug Fixes
Expand Down
8 changes: 8 additions & 0 deletions src/core/public/chrome/chrome_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ import type { PublicMethodsOf } from '@osd/utility-types';
import { ChromeBadge, ChromeBreadcrumb, ChromeService, InternalChromeStart } from './';
import { getLogosMock } from '../../common/mocks';

const createSetupContractMock = () => {
return {
registerCollapsibleNavHeader: jest.fn(),
};
};

const createStartContractMock = () => {
const startContract: DeeplyMockedKeys<InternalChromeStart> = {
getHeaderComponent: jest.fn(),
Expand Down Expand Up @@ -95,6 +101,7 @@ const createStartContractMock = () => {
type ChromeServiceContract = PublicMethodsOf<ChromeService>;
const createMock = () => {
const mocked: jest.Mocked<ChromeServiceContract> = {
setup: jest.fn(),
start: jest.fn(),
stop: jest.fn(),
};
Expand All @@ -105,4 +112,5 @@ const createMock = () => {
export const chromeServiceMock = {
create: createMock,
createStartContract: createStartContractMock,
createSetupContract: createSetupContractMock,
};
38 changes: 38 additions & 0 deletions src/core/public/chrome/chrome_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,44 @@ afterAll(() => {
(window as any).localStorage = originalLocalStorage;
});

describe('setup', () => {
afterEach(() => {
jest.restoreAllMocks();
});

it('register custom Nav Header render', async () => {
const customHeaderMock = React.createElement('TestCustomNavHeader');
const renderMock = jest.fn().mockReturnValue(customHeaderMock);
const chrome = new ChromeService({ browserSupportsCsp: true });

const chromeSetup = chrome.setup();
chromeSetup.registerCollapsibleNavHeader(renderMock);

const chromeStart = await chrome.start(defaultStartDeps());
const wrapper = shallow(React.createElement(() => chromeStart.getHeaderComponent()));
expect(wrapper.prop('collapsibleNavHeaderRender')).toBeDefined();
expect(wrapper.prop('collapsibleNavHeaderRender')()).toEqual(customHeaderMock);
});

it('should output warning message if calling `registerCollapsibleNavHeader` more than once', () => {
const warnMock = jest.fn();
jest.spyOn(console, 'warn').mockImplementation(warnMock);
const customHeaderMock = React.createElement('TestCustomNavHeader');
const renderMock = jest.fn().mockReturnValue(customHeaderMock);
const chrome = new ChromeService({ browserSupportsCsp: true });

const chromeSetup = chrome.setup();
// call 1st time
chromeSetup.registerCollapsibleNavHeader(renderMock);
// call 2nd time
chromeSetup.registerCollapsibleNavHeader(renderMock);
expect(warnMock).toHaveBeenCalledTimes(1);
expect(warnMock).toHaveBeenCalledWith(
'[ChromeService] An existing custom collapsible navigation bar header render has been overridden.'
);
});
});

describe('start', () => {
it('adds legacy browser warning if browserSupportsCsp is disabled and warnLegacyBrowsers is enabled', async () => {
const { startDeps } = await start({ options: { browserSupportsCsp: false } });
Expand Down
32 changes: 32 additions & 0 deletions src/core/public/chrome/chrome_service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ export interface StartDeps {
uiSettings: IUiSettingsClient;
}

type CollapsibleNavHeaderRender = () => JSX.Element | null;

/** @internal */
export class ChromeService {
private isVisible$!: Observable<boolean>;
Expand All @@ -107,6 +109,7 @@ export class ChromeService {
private readonly navLinks = new NavLinksService();
private readonly recentlyAccessed = new RecentlyAccessedService();
private readonly docTitle = new DocTitleService();
private collapsibleNavHeaderRender?: CollapsibleNavHeaderRender;

constructor(private readonly params: ConstructorParams) {}

Expand Down Expand Up @@ -142,6 +145,20 @@ export class ChromeService {
);
}

public setup() {
return {
registerCollapsibleNavHeader: (render: CollapsibleNavHeaderRender) => {
if (this.collapsibleNavHeaderRender) {
// eslint-disable-next-line no-console
console.warn(
'[ChromeService] An existing custom collapsible navigation bar header render has been overridden.'
);
}
this.collapsibleNavHeaderRender = render;
},
};
}

public async start({
application,
docLinks,
Expand Down Expand Up @@ -262,6 +279,7 @@ export class ChromeService {
branding={injectedMetadata.getBranding()}
logos={logos}
survey={injectedMetadata.getSurvey()}
collapsibleNavHeaderRender={this.collapsibleNavHeaderRender}
/>
),

Expand Down Expand Up @@ -325,6 +343,20 @@ export class ChromeService {
}
}

/**
* ChromeSetup allows plugins to customize the global chrome header UI rendering
* before the header UI is mounted.
*
* @example
* Customize the Collapsible Nav's (left nav menu) header section:
* ```ts
* core.chrome.registerCollapsibleNavHeader(() => <CustomNavHeader />)
* ```
*/
export interface ChromeSetup {
registerCollapsibleNavHeader: (render: CollapsibleNavHeaderRender) => void;
}

/**
* ChromeStart allows plugins to customize the global chrome header UI and
* enrich the UX with additional information about the current location of the
Expand Down
1 change: 1 addition & 0 deletions src/core/public/chrome/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export {
ChromeBadge,
ChromeBreadcrumb,
ChromeService,
ChromeSetup,
ChromeStart,
InternalChromeStart,
ChromeHelpExtension,
Expand Down
3 changes: 3 additions & 0 deletions src/core/public/chrome/ui/header/collapsible_nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ function setIsCategoryOpen(id: string, isOpen: boolean, storage: Storage) {
interface Props {
appId$: InternalApplicationStart['currentAppId$'];
basePath: HttpStart['basePath'];
collapsibleNavHeaderRender?: () => JSX.Element | null;
id: string;
isLocked: boolean;
isNavOpen: boolean;
Expand All @@ -106,6 +107,7 @@ interface Props {

export function CollapsibleNav({
basePath,
collapsibleNavHeaderRender,
id,
isLocked,
isNavOpen,
Expand Down Expand Up @@ -150,6 +152,7 @@ export function CollapsibleNav({
onClose={closeNav}
outsideClickCloses={false}
>
{collapsibleNavHeaderRender && collapsibleNavHeaderRender()}
{customNavLink && (
<Fragment>
<EuiFlexItem grow={false} style={{ flexShrink: 0 }}>
Expand Down
3 changes: 3 additions & 0 deletions src/core/public/chrome/ui/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export interface HeaderProps {
appTitle$: Observable<string>;
badge$: Observable<ChromeBadge | undefined>;
breadcrumbs$: Observable<ChromeBreadcrumb[]>;
collapsibleNavHeaderRender?: () => JSX.Element | null;
customNavLink$: Observable<ChromeNavLink | undefined>;
homeHref: string;
isVisible$: Observable<boolean>;
Expand Down Expand Up @@ -105,6 +106,7 @@ export function Header({
branding,
survey,
logos,
collapsibleNavHeaderRender,
...observables
}: HeaderProps) {
const isVisible = useObservable(observables.isVisible$, false);
Expand Down Expand Up @@ -246,6 +248,7 @@ export function Header({

<CollapsibleNav
appId$={application.currentAppId$}
collapsibleNavHeaderRender={collapsibleNavHeaderRender}
id={navId}
isLocked={isLocked}
navLinks$={observables.navLinks$}
Expand Down
2 changes: 2 additions & 0 deletions src/core/public/core_system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,12 @@ export class CoreSystem {
});
const application = this.application.setup({ context, http });
this.coreApp.setup({ application, http, injectedMetadata, notifications });
const chrome = this.chrome.setup();

const core: InternalCoreSetup = {
application,
context,
chrome,
fatalErrors: this.fatalErrorsSetup,
http,
injectedMetadata,
Expand Down
3 changes: 3 additions & 0 deletions src/core/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
ChromeNavLinks,
ChromeNavLinkUpdateableFields,
ChromeDocTitle,
ChromeSetup,
ChromeStart,
ChromeRecentlyAccessed,
ChromeRecentlyAccessedHistoryItem,
Expand Down Expand Up @@ -221,6 +222,8 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
* @deprecated
*/
context: ContextSetup;
/** {@link ChromeSetup} */
chrome: ChromeSetup;
/** {@link FatalErrorsSetup} */
fatalErrors: FatalErrorsSetup;
/** {@link HttpSetup} */
Expand Down
1 change: 1 addition & 0 deletions src/core/public/plugins/plugin_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export function createPluginSetupContext<
registerMountContext: (contextName, provider) =>
deps.application.registerMountContext(plugin.opaqueId, contextName, provider),
},
chrome: deps.chrome,
context: deps.context,
fatalErrors: deps.fatalErrors,
http: deps.http,
Expand Down
1 change: 1 addition & 0 deletions src/core/public/plugins/plugins_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ describe('PluginsService', () => {
];
mockSetupDeps = {
application: applicationServiceMock.createInternalSetupContract(),
chrome: chromeServiceMock.createSetupContract(),
context: contextServiceMock.createSetupContract(),
fatalErrors: fatalErrorsServiceMock.createSetupContract(),
http: httpServiceMock.createSetupContract(),
Expand Down

0 comments on commit d04f92f

Please sign in to comment.