Skip to content

Commit

Permalink
[Workspace] Add global search bar into left nav (opensearch-project#8538
Browse files Browse the repository at this point in the history
)

* search bar on left nav

Signed-off-by: Hailong Cui <[email protected]>

search bar on left nav

Signed-off-by: Hailong Cui <[email protected]>

compressed input

Signed-off-by: Hailong Cui <[email protected]>

* support search dev tools

Signed-off-by: Hailong Cui <[email protected]>

* enable devtools search only if new home is enabled

Signed-off-by: Hailong Cui <[email protected]>

* add unit test

Signed-off-by: Hailong Cui <[email protected]>

add more unit test

Signed-off-by: Hailong Cui <[email protected]>

* Changeset file for PR opensearch-project#8538 created/updated

* fix incorrect variable name

Signed-off-by: Hailong Cui <[email protected]>

* dismiss tooltip when close popover

Signed-off-by: Hailong Cui <[email protected]>

* style adjustment

Signed-off-by: Hailong Cui <[email protected]>

* address review comments

Signed-off-by: Hailong Cui <[email protected]>

* rename search stategy to searchHandler

Signed-off-by: Hailong Cui <[email protected]>

* rename to searchCommand

Signed-off-by: Hailong Cui <[email protected]>

* exclude parent pages

Signed-off-by: Hailong Cui <[email protected]>

* remove duplicate return

Signed-off-by: Hailong Cui <[email protected]>

* address review comments

Signed-off-by: Hailong Cui <[email protected]>

* wording change for strategy

Signed-off-by: Hailong Cui <[email protected]>

* add icon for data adminstration & settings

Signed-off-by: Hailong Cui <[email protected]>

---------

Signed-off-by: Hailong Cui <[email protected]>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
2 people authored and Qxisylolo committed Oct 30, 2024
1 parent 5e5d54c commit 2a1e361
Show file tree
Hide file tree
Showing 31 changed files with 1,698 additions and 14 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/8538.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- [Workspace] Add global search bar into left nav ([#8538](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8538))
6 changes: 6 additions & 0 deletions src/core/public/chrome/chrome_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const createSetupContractMock = () => {
getNavGroupEnabled: jest.fn(),
registerNavGroupUpdater: jest.fn(),
},
globalSearch: {
registerSearchCommand: jest.fn(),
},
};
};

Expand Down Expand Up @@ -83,6 +86,9 @@ const createStartContractMock = () => {
getCurrentNavGroup$: jest.fn(() => new BehaviorSubject(undefined)),
setCurrentNavGroup: jest.fn(),
},
globalSearch: {
getAllSearchCommands: jest.fn(() => []),
},
setAppTitle: jest.fn(),
setIsVisible: jest.fn(),
getIsVisible$: jest.fn(),
Expand Down
18 changes: 17 additions & 1 deletion src/core/public/chrome/chrome_service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ import {
ChromeNavGroupServiceSetupContract,
ChromeNavGroupServiceStartContract,
} from './nav_group';
import {
GlobalSearchService,
GlobalSearchServiceSetupContract,
GlobalSearchServiceStartContract,
} from './global_search';

export { ChromeNavControls, ChromeRecentlyAccessed, ChromeDocTitle };

Expand Down Expand Up @@ -136,6 +141,7 @@ export class ChromeService {
private readonly recentlyAccessed = new RecentlyAccessedService();
private readonly docTitle = new DocTitleService();
private readonly navGroup = new ChromeNavGroupService();
private readonly globalSearch = new GlobalSearchService();
private useUpdatedHeader = false;
private updatedHeaderSubscription: Subscription | undefined;
private collapsibleNavHeaderRender?: CollapsibleNavHeaderRender;
Expand Down Expand Up @@ -198,6 +204,7 @@ export class ChromeService {

public setup({ uiSettings }: SetupDeps): ChromeSetup {
const navGroup = this.navGroup.setup({ uiSettings });
const globalSearch = this.globalSearch.setup();
return {
registerCollapsibleNavHeader: (render: CollapsibleNavHeaderRender) => {
if (this.collapsibleNavHeaderRender) {
Expand All @@ -209,6 +216,7 @@ export class ChromeService {
this.collapsibleNavHeaderRender = render;
},
navGroup,
globalSearch,
};
}

Expand Down Expand Up @@ -255,6 +263,8 @@ export class ChromeService {
workspaces,
});

const globalSearch = this.globalSearch.start();

// erase chrome fields from a previous app while switching to a next app
application.currentAppId$.subscribe(() => {
helpExtension$.next(undefined);
Expand Down Expand Up @@ -346,6 +356,7 @@ export class ChromeService {
docTitle,
logos,
navGroup,
globalSearch,

getHeaderComponent: () => (
<Header
Expand Down Expand Up @@ -388,6 +399,7 @@ export class ChromeService {
workspaceList$={workspaces.workspaceList$}
currentWorkspace$={workspaces.currentWorkspace$}
useUpdatedHeader={this.useUpdatedHeader}
globalSearchCommands={globalSearch.getAllSearchCommands()}
/>
),

Expand Down Expand Up @@ -476,6 +488,8 @@ export class ChromeService {
export interface ChromeSetup {
registerCollapsibleNavHeader: (render: CollapsibleNavHeaderRender) => void;
navGroup: ChromeNavGroupServiceSetupContract;
/** {@inheritdoc GlobalSearchService} */
globalSearch: GlobalSearchServiceSetupContract;
}

/**
Expand Down Expand Up @@ -517,6 +531,8 @@ export interface ChromeStart {
navGroup: ChromeNavGroupServiceStartContract;
/** {@inheritdoc Logos} */
readonly logos: Logos;
/** {@inheritdoc GlobalSearchService} */
globalSearch: GlobalSearchServiceStartContract;

/**
* Sets the current app's title
Expand Down Expand Up @@ -605,7 +621,7 @@ export interface ChromeStart {
setCustomNavLink(newCustomNavLink?: Partial<ChromeNavLink>): void;

/**
* Get an observable of the current custom help conttent
* Get an observable of the current custom help content
*/
getHelpExtension$(): Observable<ChromeHelpExtension | undefined>;

Expand Down
54 changes: 54 additions & 0 deletions src/core/public/chrome/global_search/global_search_service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

// test global_search_service.ts
import { GlobalSearchService } from './global_search_service';

describe('GlobalSearchService', () => {
it('registerSearchCommand', async () => {
const globalSearchService = new GlobalSearchService();
const setup = globalSearchService.setup();
const start = globalSearchService.start();

setup.registerSearchCommand({
id: 'test1',
type: 'PAGES',
run: async (query) => {
return [];
},
});

expect(start.getAllSearchCommands()).toHaveLength(1);
expect(start.getAllSearchCommands()[0].id).toEqual('test1');
expect(start.getAllSearchCommands()[0].type).toEqual('PAGES');
});

it('registerSearchCommand with duplicate id', async () => {
const globalSearchService = new GlobalSearchService();
const setup = globalSearchService.setup();
const start = globalSearchService.start();

setup.registerSearchCommand({
id: 'test2',
type: 'PAGES',
run: async (query) => {
return [];
},
});

setup.registerSearchCommand({
id: 'test2',
type: 'SAVED_OBJECTS',
run: async (query) => {
return [];
},
});

// the second one will not overwrite the first one
expect(start.getAllSearchCommands()).toHaveLength(1);
expect(start.getAllSearchCommands()[0].id).toEqual('test2');
expect(start.getAllSearchCommands()[0].type).toEqual('PAGES');
});
});
103 changes: 103 additions & 0 deletions src/core/public/chrome/global_search/global_search_service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { ReactNode } from 'react';
import { i18n } from '@osd/i18n';

/**
* search input match with `@` will handled by saved objects search command
* search input match with `>` will handled by plugin customized commands
*/
export const SAVED_OBJECTS_SYMBOL = '@';
export const COMMANDS_SYMBOL = '>';

export const SearchCommandTypes = {
PAGES: {
description: i18n.translate('core.globalSearch.pages.description', { defaultMessage: 'Pages' }),
alias: null,
},
SAVED_OBJECTS: {
description: i18n.translate('core.globalSearch.assets.description', {
defaultMessage: 'Assets',
}),
alias: SAVED_OBJECTS_SYMBOL,
},
} as const;

export type SearchCommandKeyTypes = keyof typeof SearchCommandTypes;

/**
* @experimental
*/
export interface GlobalSearchCommand {
/**
* unique id of this command
*/
id: string;
/**
* search command type
* @type {SearchCommandTypes}
*/
type: SearchCommandKeyTypes;
/**
* do the search and return search result with a React element
* @param value search query
* @param callback callback function when search is done
*/
run(value: string, callback?: () => void): Promise<ReactNode[]>;
}

export interface GlobalSearchServiceSetupContract {
registerSearchCommand(searchCommand: GlobalSearchCommand): void;
}

export interface GlobalSearchServiceStartContract {
getAllSearchCommands(): GlobalSearchCommand[];
}

/**
* {@link GlobalSearchCommand | APIs} for registering new global search command when do search from header search bar .
*
* @example
* Register a GlobalSearchCommand to search pages
* ```jsx
* chrome.globalSearch.registerSearchCommand({
* id: 'test',
* type: SearchObjectTypes.PAGES,
* run: async (query) => {
* return [];
* },
* })
* ```
*
* @experimental
*/
export class GlobalSearchService {
private searchCommands = [] as GlobalSearchCommand[];

private registerSearchCommand(searchHandler: GlobalSearchCommand) {
const exists = this.searchCommands.find((item) => {
return item.id === searchHandler.id;
});
if (exists) {
// eslint-disable-next-line no-console
console.warn(`Duplicate SearchCommands id ${searchHandler.id} found`);
return;
}
this.searchCommands.push(searchHandler);
}

public setup(): GlobalSearchServiceSetupContract {
return {
registerSearchCommand: this.registerSearchCommand.bind(this),
};
}

public start(): GlobalSearchServiceStartContract {
return {
getAllSearchCommands: () => this.searchCommands,
};
}
}
6 changes: 6 additions & 0 deletions src/core/public/chrome/global_search/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export * from './global_search_service';
1 change: 1 addition & 0 deletions src/core/public/chrome/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ export { ChromeDocTitle } from './doc_title';
export { RightNavigationOrder, HeaderVariant } from './constants';
export { ChromeRegistrationNavLink, ChromeNavGroupUpdater, NavGroupItemInMap } from './nav_group';
export { fulfillRegistrationLinksToChromeNavLinks, LinkItemType, getSortedNavLinks } from './utils';
export { SearchCommandKeyTypes, GlobalSearchCommand } from './global_search';

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 @@ -114,4 +114,25 @@
padding: 0 $euiSizeS;
padding-left: $euiSize;
}

.searchBar-wrapper {
padding: $euiSize;
padding-top: $euiSizeS;
background-color: transparent;
flex-grow: 0;

.searchInput {
background-color: transparentize($euiFormBackgroundColor, 0.5);
}

.searchInput:focus {
background-color: $euiFormBackgroundColor;
}
}

.searchBarIcon {
position: fixed;
top: $ouiHeaderChildSize;
left: 0;
}
}
Loading

0 comments on commit 2a1e361

Please sign in to comment.