Skip to content

Commit e57195d

Browse files
committed
Add registerNavGroupUpdater to nav group service
Signed-off-by: Lin Wang <wonglam@amazon.com>
1 parent 9ac3184 commit e57195d

File tree

7 files changed

+119
-4
lines changed

7 files changed

+119
-4
lines changed

src/core/public/chrome/chrome_service.mock.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const createSetupContractMock = () => {
3939
navGroup: {
4040
addNavLinksToGroup: jest.fn(),
4141
getNavGroupEnabled: jest.fn(),
42+
registerNavGroupUpdater: jest.fn(),
4243
},
4344
};
4445
};

src/core/public/chrome/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,4 @@ export { ChromeRecentlyAccessed, ChromeRecentlyAccessedHistoryItem } from './rec
5050
export { ChromeNavControl, ChromeNavControls } from './nav_controls';
5151
export { ChromeDocTitle } from './doc_title';
5252
export { RightNavigationOrder } from './constants';
53-
export { ChromeRegistrationNavLink } from './nav_group';
53+
export { ChromeRegistrationNavLink, ChromeNavGroupUpdater } from './nav_group';

src/core/public/chrome/nav_group/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ export {
99
ChromeNavGroupServiceStartContract,
1010
ChromeRegistrationNavLink,
1111
NavGroupItemInMap,
12+
ChromeNavGroupUpdater,
1213
} from './nav_group_service';

src/core/public/chrome/nav_group/nav_group_service.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { uiSettingsServiceMock } from '../../ui_settings/ui_settings_service.moc
1010
import { NavLinksService } from '../nav_links';
1111
import { applicationServiceMock, httpServiceMock } from '../../mocks';
1212
import { AppCategory } from 'opensearch-dashboards/public';
13+
import { DEFAULT_NAV_GROUPS } from '../../';
1314

1415
const mockedGroupFoo = {
1516
id: 'foo',
@@ -219,3 +220,66 @@ describe('ChromeNavGroupService#start()', () => {
219220
expect(chromeNavGroupServiceStart.getNavGroupEnabled()).toBe(false);
220221
});
221222
});
223+
224+
describe('nav group updater', () => {
225+
it('should emit updated nav group after nav group updater called', async () => {
226+
const navGroup = new ChromeNavGroupService();
227+
const uiSettings = uiSettingsServiceMock.createSetupContract();
228+
uiSettings.get$.mockImplementation(() => new Rx.BehaviorSubject(true));
229+
230+
const navGroupSetup = navGroup.setup({ uiSettings });
231+
navGroupSetup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.dataAdministration, [
232+
{
233+
id: 'foo',
234+
},
235+
]);
236+
const navGroupStart = await navGroup.start({ navLinks: mockedNavLinkService });
237+
238+
expect(await navGroupStart.getNavGroupsMap$().pipe(first()).toPromise()).toEqual({
239+
dataAdministration: expect.not.objectContaining({
240+
status: expect.anything,
241+
}),
242+
});
243+
navGroupSetup.registerNavGroupUpdater(
244+
new Rx.BehaviorSubject(() => ({
245+
status: 2,
246+
}))
247+
);
248+
expect(await navGroupStart.getNavGroupsMap$().pipe(first()).toPromise()).toEqual({
249+
dataAdministration: expect.objectContaining({
250+
status: 2,
251+
}),
252+
});
253+
});
254+
255+
it('should reset to original status after nav group updater unregister', async () => {
256+
const navGroup = new ChromeNavGroupService();
257+
const uiSettings = uiSettingsServiceMock.createSetupContract();
258+
uiSettings.get$.mockImplementation(() => new Rx.BehaviorSubject(true));
259+
260+
const navGroupSetup = navGroup.setup({ uiSettings });
261+
navGroupSetup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.dataAdministration, [
262+
{
263+
id: 'foo',
264+
},
265+
]);
266+
const appUpdater$ = new Rx.BehaviorSubject(() => ({
267+
status: 2,
268+
}));
269+
const unregister = navGroupSetup.registerNavGroupUpdater(appUpdater$);
270+
const navGroupStart = await navGroup.start({ navLinks: mockedNavLinkService });
271+
expect(await navGroupStart.getNavGroupsMap$().pipe(first()).toPromise()).toEqual({
272+
dataAdministration: expect.objectContaining({
273+
status: 2,
274+
}),
275+
});
276+
277+
unregister();
278+
279+
expect(await navGroupStart.getNavGroupsMap$().pipe(first()).toPromise()).toEqual({
280+
dataAdministration: expect.not.objectContaining({
281+
status: expect.anything,
282+
}),
283+
});
284+
});
285+
});

src/core/public/chrome/nav_group/nav_group_service.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { BehaviorSubject, combineLatest, Observable, ReplaySubject, Subscription } from 'rxjs';
6+
import { BehaviorSubject, combineLatest, Observable, of, ReplaySubject, Subscription } from 'rxjs';
77
import { AppCategory, ChromeNavGroup, ChromeNavLink } from 'opensearch-dashboards/public';
8-
import { map, takeUntil } from 'rxjs/operators';
8+
import { map, switchMap, takeUntil } from 'rxjs/operators';
99
import { IUiSettingsClient } from '../../ui_settings';
1010
import {
1111
flattenLinksOrCategories,
@@ -31,12 +31,15 @@ export type NavGroupItemInMap = ChromeNavGroup & {
3131
navLinks: ChromeRegistrationNavLink[];
3232
};
3333

34+
export type ChromeNavGroupUpdater = (navGroup: ChromeNavGroup) => Partial<ChromeNavGroup> | void;
35+
3436
export interface ChromeNavGroupServiceSetupContract {
3537
addNavLinksToGroup: (navGroup: ChromeNavGroup, navLinks: ChromeRegistrationNavLink[]) => void;
3638
/**
3739
* Get a boolean value to indicates whether use case is enabled
3840
*/
3941
getNavGroupEnabled: () => boolean;
42+
registerNavGroupUpdater: (navGroupUpdater: Observable<ChromeNavGroupUpdater>) => () => void;
4043
}
4144

4245
export interface ChromeNavGroupServiceStartContract {
@@ -51,6 +54,7 @@ export class ChromeNavGroupService {
5154
private navLinks$: Observable<Array<Readonly<ChromeNavLink>>> = new BehaviorSubject([]);
5255
private navGroupEnabled: boolean = false;
5356
private navGroupEnabledUiSettingsSubscription: Subscription | undefined;
57+
private navGroupUpdaters$$ = new BehaviorSubject<Array<Observable<ChromeNavGroupUpdater>>>([]);
5458
private addNavLinkToGroup(
5559
currentGroupsMap: Record<string, NavGroupItemInMap>,
5660
navGroup: ChromeNavGroup,
@@ -78,7 +82,7 @@ export class ChromeNavGroupService {
7882
return currentGroupsMap;
7983
}
8084
private getSortedNavGroupsMap$() {
81-
return combineLatest([this.navGroupsMap$, this.navLinks$])
85+
return combineLatest([this.getUpdatedNavGroupsMap$(), this.navLinks$])
8286
.pipe(takeUntil(this.stop$))
8387
.pipe(
8488
map(([navGroupsMap, navLinks]) => {
@@ -96,6 +100,33 @@ export class ChromeNavGroupService {
96100
})
97101
);
98102
}
103+
104+
private getUpdatedNavGroupsMap$() {
105+
return combineLatest([this.navGroupsMap$, this.navGroupUpdaters$$]).pipe(
106+
switchMap(([navGroupsMap, updaters$]) => {
107+
if (updaters$.length === 0) {
108+
return of(navGroupsMap);
109+
}
110+
return combineLatest(updaters$).pipe(
111+
map((updaters) => {
112+
return Object.keys(navGroupsMap).reduce<Record<string, NavGroupItemInMap>>(
113+
(previousValue, currentKey) => ({
114+
...previousValue,
115+
[currentKey]: updaters.reduce(
116+
(prevNavGroup, currentUpdater) => ({
117+
...prevNavGroup,
118+
...currentUpdater(prevNavGroup),
119+
}),
120+
navGroupsMap[currentKey]
121+
),
122+
}),
123+
{}
124+
);
125+
})
126+
);
127+
})
128+
);
129+
}
99130
setup({ uiSettings }: { uiSettings: IUiSettingsClient }): ChromeNavGroupServiceSetupContract {
100131
this.navGroupEnabledUiSettingsSubscription = uiSettings
101132
.get$('home:useNewHomePage', false)
@@ -116,6 +147,14 @@ export class ChromeNavGroupService {
116147
this.navGroupsMap$.next(navGroupsMapAfterAdd);
117148
},
118149
getNavGroupEnabled: () => this.navGroupEnabled,
150+
registerNavGroupUpdater: (updater$) => {
151+
this.navGroupUpdaters$$.next([...this.navGroupUpdaters$$.getValue(), updater$]);
152+
return () => {
153+
this.navGroupUpdaters$$.next(
154+
this.navGroupUpdaters$$.getValue().filter((item) => item !== updater$)
155+
);
156+
};
157+
},
119158
};
120159
}
121160
async start({

src/core/public/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import {
7272
RightNavigationButton,
7373
RightNavigationButtonProps,
7474
ChromeRegistrationNavLink,
75+
ChromeNavGroupUpdater,
7576
} from './chrome';
7677
import { FatalErrorsSetup, FatalErrorsStart, FatalErrorInfo } from './fatal_errors';
7778
import { HttpSetup, HttpStart } from './http';
@@ -118,6 +119,7 @@ export {
118119
WorkspaceAttribute,
119120
ChromeNavGroup,
120121
NavGroupType,
122+
NavGroupStatus,
121123
} from '../types';
122124

123125
export {
@@ -371,6 +373,7 @@ export {
371373
RightNavigationButton,
372374
RightNavigationButtonProps,
373375
ChromeRegistrationNavLink,
376+
ChromeNavGroupUpdater,
374377
};
375378

376379
export { __osdBootstrap__ } from './osd_bootstrap';

src/core/types/nav_group.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export enum NavGroupType {
1616
SYSTEM = 'system',
1717
}
1818

19+
export enum NavGroupStatus {
20+
Visible,
21+
Hidden,
22+
}
23+
1924
/** @public */
2025
export interface ChromeNavGroup {
2126
id: string;
@@ -24,4 +29,6 @@ export interface ChromeNavGroup {
2429
order?: number;
2530
icon?: EuiIconType;
2631
type?: NavGroupType;
32+
33+
status?: NavGroupStatus;
2734
}

0 commit comments

Comments
 (0)