Skip to content

Commit

Permalink
Introduce the redesign page and applications headers behind a switch (o…
Browse files Browse the repository at this point in the history
…pensearch-project#7637)

* Bump OUI to 1.9.0

Signed-off-by: Miki <[email protected]>

* Introduce the redesigned page header

Signed-off-by: Miki <[email protected]>

Update UX of breadcrumbs, menu toggle, and the new contribution points

Signed-off-by: Miki <[email protected]>

Add renderElement option in HeaderControls

Signed-off-by: Shenoy Pratik <[email protected]>

Update application mocks and rearrange header layout

Signed-off-by: Shenoy Pratik <[email protected]>

Break and restyle breadcrumb

Signed-off-by: Zhongnan Su <[email protected]>

Implement header updates

Signed-off-by: Miki <[email protected]>

* Introduce HeaderVariant

Signed-off-by: Miki <[email protected]>

* Organize Header's layout

Signed-off-by: Miki <[email protected]>

* Fix header control spacing

Signed-off-by: Miki <[email protected]>

* Conditionally append breadcrumb to recent popover
Fix mock for recent items

Co-authored-by: Zhongnan Su <[email protected]>
Co-authored-by: Shenoy Pratik <[email protected]>

* Update top nav render and add app header
Use ScreenTitle instead of appname from topnav menu

Signed-off-by: Shenoy Pratik <[email protected]>

* Compress QueryStringInput appearance

Signed-off-by: Miki <[email protected]>

* Update header for applications

Signed-off-by: Miki <[email protected]>

* Eliminate colors from the borders of grouped action menu items

Signed-off-by: Miki <[email protected]>

* Update TopNavControl*Data type to controlType for consistency

Signed-off-by: Miki <[email protected]>

* Add tests for chrome Header

Signed-off-by: Shenoy Pratik <[email protected]>

* Update Breadcrumbs tests

Signed-off-by: Shenoy Pratik <[email protected]>

* Add tests for HeaderControlsContainer

Signed-off-by: Miki <[email protected]>

* Add tests for TopNavControls and TopNavControlItem

Signed-off-by: Shenoy Pratik <[email protected]>

* Updated tests for TopNavMenu and TopNavMenuItem

Signed-off-by: Shenoy Pratik <[email protected]>

* Fix `uiSettingsServiceMock` missing `start`

Signed-off-by: Miki <[email protected]>

* Add the `target` property to TopNavControlItem

Signed-off-by: Miki <[email protected]>

* Update Navigation mock and start contract

Signed-off-by: Miki <[email protected]>

* Add createGetterSetter mock in dashboards app state

Signed-off-by: Shenoy Pratik <[email protected]>

* Add tests for setting and unsetting header variant

Signed-off-by: Miki <[email protected]>

* Add tests for setting header controls

Signed-off-by: Miki <[email protected]>

* Re-skin DataSource selection's trigger button

Signed-off-by: Miki <[email protected]>

* Conditionally change where theme management menu item shows up

Signed-off-by: Miki <[email protected]>

* Conditionally change where the help menu items shows up

Signed-off-by: Miki <[email protected]>

* Make IndexPatternTable page conditionally use the new page header

Signed-off-by: Miki <[email protected]>

* Make Discover conditionally use the new application header

Signed-off-by: Miki <[email protected]>

* Make Dashboards conditionally use the new application header

Signed-off-by: Miki <[email protected]>

* Add changelog fragment

Signed-off-by: Shenoy Pratik <[email protected]>
Signed-off-by: Miki <[email protected]>

* Add tracking issue for empty label for DataSourceMenuPopoverButton

Signed-off-by: Miki <[email protected]>

* Use EUI aliases in CSS variables

Signed-off-by: Miki <[email protected]>

* Remove TopNavMenuLink

Signed-off-by: Miki <[email protected]>

* Make sure OuiHeader doesn't contribute to the background

Also:
* Remove unused code

Signed-off-by: Miki <[email protected]>

* Better border hiding for DSM popover button

Signed-off-by: Miki <[email protected]>

* Make popover button overflow later

Signed-off-by: Miki <[email protected]>

---------

Signed-off-by: Miki <[email protected]>
Signed-off-by: Shenoy Pratik <[email protected]>
Co-authored-by: Zhongnan Su <[email protected]>
Co-authored-by: Shenoy Pratik <[email protected]>

(cherry picked from commit 265a176)
Signed-off-by: Miki <[email protected]>
  • Loading branch information
3 people committed Aug 13, 2024
1 parent 3fad78c commit bfe424c
Show file tree
Hide file tree
Showing 103 changed files with 15,047 additions and 4,538 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7637.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Introduce the redesign page and applications headers behind a switch ([#7637](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7637))
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
"dependencies": {
"@aws-crypto/client-node": "^3.1.1",
"@elastic/datemath": "5.0.3",
"@elastic/eui": "npm:@opensearch-project/oui@1.8.1",
"@elastic/eui": "npm:@opensearch-project/oui@1.9.0",
"@elastic/good": "^9.0.1-kibana3",
"@elastic/numeral": "npm:@amoo-miki/[email protected]",
"@elastic/request-crypto": "2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/osd-ui-framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"enzyme-adapter-react-16": "^1.9.1"
},
"devDependencies": {
"@elastic/eui": "npm:@opensearch-project/oui@1.8.1",
"@elastic/eui": "npm:@opensearch-project/oui@1.9.0",
"@osd/babel-preset": "1.0.0",
"@osd/optimizer": "1.0.0",
"comment-stripper": "^0.0.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/osd-ui-shared-deps/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"dependencies": {
"@elastic/charts": "31.1.0",
"@elastic/eui": "npm:@opensearch-project/oui@1.8.1",
"@elastic/eui": "npm:@opensearch-project/oui@1.9.0",
"@elastic/numeral": "npm:@amoo-miki/[email protected]",
"@opensearch/datemath": "5.0.3",
"@osd/i18n": "1.0.0",
Expand Down

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

18 changes: 18 additions & 0 deletions src/core/public/application/application_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ const createStartContractMock = (): jest.Mocked<ApplicationStart> => {
navigateToUrl: jest.fn(),
getUrlForApp: jest.fn(),
registerMountContext: jest.fn(),
setAppLeftControls: jest.fn(),
setAppCenterControls: jest.fn(),
setAppRightControls: jest.fn(),
setAppBadgeControls: jest.fn(),
setAppDescriptionControls: jest.fn(),
setAppBottomControls: jest.fn(),
};
};

Expand Down Expand Up @@ -98,6 +104,18 @@ const createInternalStartContractMock = (): jest.Mocked<InternalApplicationStart
capabilities: capabilitiesServiceMock.createStartContract().capabilities,
currentAppId$: currentAppId$.asObservable(),
currentActionMenu$: new BehaviorSubject<MountPoint | undefined>(undefined),
currentLeftControls$: new BehaviorSubject<MountPoint | undefined>(undefined),
currentCenterControls$: new BehaviorSubject<MountPoint | undefined>(undefined),
currentRightControls$: new BehaviorSubject<MountPoint | undefined>(undefined),
currentBadgeControls$: new BehaviorSubject<MountPoint | undefined>(undefined),
currentDescriptionControls$: new BehaviorSubject<MountPoint | undefined>(undefined),
currentBottomControls$: new BehaviorSubject<MountPoint | undefined>(undefined),
setAppLeftControls: jest.fn(),
setAppCenterControls: jest.fn(),
setAppRightControls: jest.fn(),
setAppBadgeControls: jest.fn(),
setAppDescriptionControls: jest.fn(),
setAppBottomControls: jest.fn(),
getComponent: jest.fn(),
getUrlForApp: jest.fn(),
navigateToApp: jest.fn().mockImplementation((appId) => currentAppId$.next(appId)),
Expand Down
32 changes: 31 additions & 1 deletion src/core/public/application/application_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
} from './application_service.test.mocks';

import { createElement } from 'react';
import { BehaviorSubject, Subject } from 'rxjs';
import { BehaviorSubject, Subject, Observable } from 'rxjs';
import { bufferCount, take, takeUntil } from 'rxjs/operators';
import { shallow, mount } from 'enzyme';

Expand All @@ -51,7 +51,9 @@ import {
AppStatus,
AppUpdater,
WorkspaceAvailability,
InternalApplicationStart,
} from './types';
import { MountPoint } from '../types';
import { act } from 'react-dom/test-utils';
import { workspacesServiceMock } from '../mocks';

Expand Down Expand Up @@ -937,6 +939,34 @@ describe('#start()', () => {
expect(setupDeps.redirectTo).not.toHaveBeenCalled();
});
});

describe('AppControls', () => {
test.each(['Left', 'Center', 'Right', 'Badge', 'Description', 'Bottom'])(
'records the App%sControls',
async (container) => {
const { register } = service.setup(setupDeps);

register(Symbol(), createApp({ id: `app${container}` }));
const appStart = await service.start(startDeps);
const setControls = appStart[
`setApp${container}Controls` as keyof InternalApplicationStart
] as (mount: MountPoint | undefined) => void;
const currentControls$ = appStart[
`current${container}Controls$` as keyof InternalApplicationStart
] as Observable<MountPoint | undefined>;

const oldMountPoint = jest.fn();
const expectedMountPoint = jest.fn();

await appStart.navigateToApp(`app${container}`);
setControls(oldMountPoint);
setControls(expectedMountPoint);

const mountPoint = await currentControls$.pipe(take(1)).toPromise();
expect(mountPoint).toBe(expectedMountPoint);
}
);
});
});

describe('#stop()', () => {
Expand Down
142 changes: 142 additions & 0 deletions src/core/public/application/application_service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { RecursiveReadonly } from '@osd/utility-types';
import { MountPoint } from '../types';
import { HttpSetup, HttpStart } from '../http';
import { OverlayStart } from '../overlays';
import { HeaderControlsContainer } from '../chrome/constants';
import { ContextSetup, IContextContainer } from '../context';
import { PluginOpaqueId } from '../plugins';
import { AppRouter } from './ui';
Expand Down Expand Up @@ -104,6 +105,12 @@ interface AppUpdaterWrapper {
interface AppInternalState {
leaveHandler?: AppLeaveHandler;
actionMenu?: MountPoint;
leftControls?: MountPoint;
centerControls?: MountPoint;
rightControls?: MountPoint;
badgeControls?: MountPoint;
descriptionControls?: MountPoint;
bottomControls?: MountPoint;
}

/**
Expand All @@ -117,6 +124,15 @@ export class ApplicationService {
private readonly appInternalStates = new Map<string, AppInternalState>();
private currentAppId$ = new BehaviorSubject<string | undefined>(undefined);
private currentActionMenu$ = new BehaviorSubject<MountPoint | undefined>(undefined);

// HeaderControls
private currentLeftControls$ = new BehaviorSubject<MountPoint | undefined>(undefined);
private currentCenterControls$ = new BehaviorSubject<MountPoint | undefined>(undefined);
private currentRightControls$ = new BehaviorSubject<MountPoint | undefined>(undefined);
private currentBadgeControls$ = new BehaviorSubject<MountPoint | undefined>(undefined);
private currentDescriptionControls$ = new BehaviorSubject<MountPoint | undefined>(undefined);
private currentBottomControls$ = new BehaviorSubject<MountPoint | undefined>(undefined);

private readonly statusUpdaters$ = new BehaviorSubject<Map<symbol, AppUpdaterWrapper>>(new Map());
private readonly subscriptions: Subscription[] = [];
private stop$ = new Subject();
Expand Down Expand Up @@ -291,6 +307,15 @@ export class ApplicationService {

this.currentAppId$.subscribe(() => this.refreshCurrentActionMenu());

this.currentAppId$.subscribe(() => this.refreshCurrentControls(HeaderControlsContainer.LEFT));
this.currentAppId$.subscribe(() => this.refreshCurrentControls(HeaderControlsContainer.CENTER));
this.currentAppId$.subscribe(() => this.refreshCurrentControls(HeaderControlsContainer.RIGHT));
this.currentAppId$.subscribe(() => this.refreshCurrentControls(HeaderControlsContainer.BADGE));
this.currentAppId$.subscribe(() =>
this.refreshCurrentControls(HeaderControlsContainer.DESCRIPTION)
);
this.currentAppId$.subscribe(() => this.refreshCurrentControls(HeaderControlsContainer.BOTTOM));

return {
applications$: applications$.pipe(
map((apps) => new Map([...apps.entries()].map(([id, app]) => [id, getAppInfo(app)]))),
Expand All @@ -306,6 +331,46 @@ export class ApplicationService {
distinctUntilChanged(),
takeUntil(this.stop$)
),

// HeaderControls
currentLeftControls$: this.currentLeftControls$.pipe(
distinctUntilChanged(),
takeUntil(this.stop$)
),
currentCenterControls$: this.currentCenterControls$.pipe(
distinctUntilChanged(),
takeUntil(this.stop$)
),
currentRightControls$: this.currentRightControls$.pipe(
distinctUntilChanged(),
takeUntil(this.stop$)
),
currentBadgeControls$: this.currentBadgeControls$.pipe(
distinctUntilChanged(),
takeUntil(this.stop$)
),
currentDescriptionControls$: this.currentDescriptionControls$.pipe(
distinctUntilChanged(),
takeUntil(this.stop$)
),
currentBottomControls$: this.currentBottomControls$.pipe(
distinctUntilChanged(),
takeUntil(this.stop$)
),

setAppLeftControls: (mount: MountPoint | undefined) =>
this.setAppLeftControls(this.currentAppId$.value, mount),
setAppCenterControls: (mount: MountPoint | undefined) =>
this.setAppCenterControls(this.currentAppId$.value, mount),
setAppRightControls: (mount: MountPoint | undefined) =>
this.setAppRightControls(this.currentAppId$.value, mount),
setAppBadgeControls: (mount: MountPoint | undefined) =>
this.setAppBadgeControls(this.currentAppId$.value, mount),
setAppDescriptionControls: (mount: MountPoint | undefined) =>
this.setAppDescriptionControls(this.currentAppId$.value, mount),
setAppBottomControls: (mount: MountPoint | undefined) =>
this.setAppBottomControls(this.currentAppId$.value, mount),

history: this.history!,
registerMountContext: this.mountContext.registerContext,
getUrlForApp: (
Expand Down Expand Up @@ -339,6 +404,12 @@ export class ApplicationService {
appStatuses$={applicationStatuses$}
setAppLeaveHandler={this.setAppLeaveHandler}
setAppActionMenu={this.setAppActionMenu}
setAppLeftControls={this.setAppLeftControls}
setAppCenterControls={this.setAppCenterControls}
setAppRightControls={this.setAppRightControls}
setAppBadgeControls={this.setAppBadgeControls}
setAppDescriptionControls={this.setAppDescriptionControls}
setAppBottomControls={this.setAppBottomControls}
setIsMounting={(isMounting) => httpLoadingCount$.next(isMounting ? 1 : 0)}
/>
);
Expand Down Expand Up @@ -367,6 +438,71 @@ export class ApplicationService {
this.currentActionMenu$.next(currentActionMenu);
};

private setAppLeftControls = (appPath: string | undefined, mount: MountPoint | undefined) =>
this.setAppControls(appPath, mount, HeaderControlsContainer.LEFT);

private setAppCenterControls = (appPath: string | undefined, mount: MountPoint | undefined) =>
this.setAppControls(appPath, mount, HeaderControlsContainer.CENTER);

private setAppRightControls = (appPath: string | undefined, mount: MountPoint | undefined) =>
this.setAppControls(appPath, mount, HeaderControlsContainer.RIGHT);

private setAppBadgeControls = (appPath: string | undefined, mount: MountPoint | undefined) =>
this.setAppControls(appPath, mount, HeaderControlsContainer.BADGE);

private setAppDescriptionControls = (
appPath: string | undefined,
mount: MountPoint | undefined
) => this.setAppControls(appPath, mount, HeaderControlsContainer.DESCRIPTION);

private setAppBottomControls = (appPath: string | undefined, mount: MountPoint | undefined) =>
this.setAppControls(appPath, mount, HeaderControlsContainer.BOTTOM);

private setAppControls = (
appPath: string | undefined,
mount: MountPoint | undefined,
container: HeaderControlsContainer
) => {
if (!appPath) return;

this.appInternalStates.set(appPath, {
...(this.appInternalStates.get(appPath) ?? {}),
[`${container}Controls`]: mount,
});

this.refreshCurrentControls(container);
};

private refreshCurrentControls = (container: HeaderControlsContainer) => {
const appId = this.currentAppId$.getValue();
switch (container) {
case HeaderControlsContainer.LEFT:
return this.currentLeftControls$.next(
appId ? this.appInternalStates.get(appId)?.leftControls : undefined
);
case HeaderControlsContainer.CENTER:
return this.currentCenterControls$.next(
appId ? this.appInternalStates.get(appId)?.centerControls : undefined
);
case HeaderControlsContainer.RIGHT:
return this.currentRightControls$.next(
appId ? this.appInternalStates.get(appId)?.rightControls : undefined
);
case HeaderControlsContainer.BADGE:
return this.currentBadgeControls$.next(
appId ? this.appInternalStates.get(appId)?.badgeControls : undefined
);
case HeaderControlsContainer.DESCRIPTION:
return this.currentDescriptionControls$.next(
appId ? this.appInternalStates.get(appId)?.descriptionControls : undefined
);
case HeaderControlsContainer.BOTTOM:
return this.currentBottomControls$.next(
appId ? this.appInternalStates.get(appId)?.bottomControls : undefined
);
}
};

private async shouldNavigate(overlays: OverlayStart): Promise<boolean> {
const currentAppId = this.currentAppId$.value;
if (currentAppId === undefined) {
Expand Down Expand Up @@ -402,6 +538,12 @@ export class ApplicationService {
this.stop$.next();
this.currentAppId$.complete();
this.currentActionMenu$.complete();
this.currentLeftControls$.complete();
this.currentCenterControls$.complete();
this.currentRightControls$.complete();
this.currentBadgeControls$.complete();
this.currentDescriptionControls$.complete();
this.currentBottomControls$.complete();
this.statusUpdaters$.complete();
this.subscriptions.forEach((sub) => sub.unsubscribe());
window.removeEventListener('beforeunload', this.onBeforeUnload);
Expand Down
6 changes: 6 additions & 0 deletions src/core/public/application/integration_tests/router.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ describe('AppRouter', () => {
appStatuses$={mountersToAppStatus$()}
setAppLeaveHandler={noop}
setAppActionMenu={noop}
setAppLeftControls={noop}
setAppCenterControls={noop}
setAppRightControls={noop}
setAppBadgeControls={noop}
setAppDescriptionControls={noop}
setAppBottomControls={noop}
setIsMounting={noop}
/>
);
Expand Down
Loading

0 comments on commit bfe424c

Please sign in to comment.