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

Introduce the redesign page and applications headers behind a switch #7637

Merged
merged 35 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
1b246b8
Bump OUI to 1.9.0
AMoo-Miki Aug 5, 2024
782f968
Introduce the redesigned page header
AMoo-Miki Jul 30, 2024
84d9845
Introduce HeaderVariant
AMoo-Miki Aug 2, 2024
09f5245
Organize Header's layout
AMoo-Miki Aug 2, 2024
23a7cd3
Fix header control spacing
AMoo-Miki Aug 3, 2024
7c48239
Conditionally append breadcrumb to recent popover
zhongnansu Aug 2, 2024
19bf6ce
Update top nav render and add app header
ps48 Aug 2, 2024
4e33467
Compress QueryStringInput appearance
AMoo-Miki Aug 3, 2024
6d26211
Update header for applications
AMoo-Miki Aug 3, 2024
51ba337
Eliminate colors from the borders of grouped action menu items
AMoo-Miki Aug 5, 2024
d69eff8
Update TopNavControl*Data type to controlType for consistency
AMoo-Miki Aug 6, 2024
dcefaad
Add tests for chrome Header
ps48 Aug 6, 2024
04335a8
Update Breadcrumbs tests
ps48 Aug 6, 2024
a73791c
Add tests for HeaderControlsContainer
AMoo-Miki Aug 7, 2024
7a12fe6
Add tests for TopNavControls and TopNavControlItem
ps48 Aug 6, 2024
67e2886
Updated tests for TopNavMenu and TopNavMenuItem
ps48 Aug 6, 2024
e7531bf
Fix `uiSettingsServiceMock` missing `start`
AMoo-Miki Aug 6, 2024
8268975
Add the `target` property to TopNavControlItem
AMoo-Miki Aug 6, 2024
f070ce7
Update Navigation mock and start contract
AMoo-Miki Aug 6, 2024
7bf25f9
Add createGetterSetter mock in dashboards app state
ps48 Aug 6, 2024
ddb7276
Add tests for setting and unsetting header variant
AMoo-Miki Aug 7, 2024
93a3443
Add tests for setting header controls
AMoo-Miki Aug 7, 2024
272a85e
Re-skin DataSource selection's trigger button
AMoo-Miki Aug 3, 2024
6a7d951
Conditionally change where theme management menu item shows up
AMoo-Miki Aug 5, 2024
0f90ff2
Conditionally change where the help menu items shows up
AMoo-Miki Aug 6, 2024
046c4f2
Make IndexPatternTable page conditionally use the new page header
AMoo-Miki Aug 1, 2024
cf9839d
Make Discover conditionally use the new application header
AMoo-Miki Aug 4, 2024
f903d17
Make Dashboards conditionally use the new application header
AMoo-Miki Aug 5, 2024
310c069
Add changelog fragment
AMoo-Miki Aug 7, 2024
1cfe38a
Add tracking issue for empty label for DataSourceMenuPopoverButton
AMoo-Miki Aug 9, 2024
db4fb52
Use EUI aliases in CSS variables
AMoo-Miki Aug 9, 2024
79431ae
Remove TopNavMenuLink
AMoo-Miki Aug 9, 2024
11a4151
Make sure OuiHeader doesn't contribute to the background
AMoo-Miki Aug 9, 2024
9a4e1fe
Better border hiding for DSM popover button
AMoo-Miki Aug 9, 2024
ddb9c3d
Make popover button overflow later
AMoo-Miki Aug 10, 2024
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/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 @@ -144,7 +144,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);
};
AMoo-Miki marked this conversation as resolved.
Show resolved Hide resolved

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
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
Loading