55
66import { ReactNode } from 'react' ;
77import { i18n } from '@osd/i18n' ;
8+ import { BehaviorSubject , Observable } from 'rxjs' ;
89
910/**
1011 * search input match with `@` will handled by saved objects search command
@@ -24,10 +25,27 @@ export const SearchCommandTypes = {
2425 } ) ,
2526 alias : SAVED_OBJECTS_SYMBOL ,
2627 } ,
28+ ACTIONS : {
29+ description : i18n . translate ( 'core.globalSearch.actions.description' , {
30+ defaultMessage : 'Actions' ,
31+ } ) ,
32+ alias : null ,
33+ } ,
2734} as const ;
2835
2936export type SearchCommandKeyTypes = keyof typeof SearchCommandTypes ;
3037
38+ /**
39+ * Options for the run method of GlobalSearchCommand
40+ * @experimental
41+ */
42+ export interface GlobalSearchCommandRunOptions {
43+ /**
44+ * AbortSignal to cancel the search operation
45+ */
46+ abortSignal ?: AbortSignal ;
47+ }
48+
3149/**
3250 * @experimental
3351 */
@@ -41,21 +59,140 @@ export interface GlobalSearchCommand {
4159 * @type {SearchCommandTypes }
4260 */
4361 type : SearchCommandKeyTypes ;
62+
63+ /**
64+ * Defines the placeholder text displayed in the global search input field.
65+ * When multiple commands specify a placeholder, only the first registered command's placeholder will be used.
66+ *
67+ * @example 'Search pages, assets, and actions...'
68+ */
69+ inputPlaceholder ?: string ;
70+
4471 /**
4572 * do the search and return search result with a React element
4673 * @param value search query
4774 * @param callback callback function when search is done
75+ * @param options options object containing abortSignal and other future extensible properties
76+ */
77+ run (
78+ value : string ,
79+ callback ?: ( ) => void ,
80+ options ?: GlobalSearchCommandRunOptions
81+ ) : Promise < ReactNode [ ] > ;
82+
83+ /**
84+ * Callback function executed when the user presses Enter in the global search bar.
85+ * This allows commands to perform custom actions based on the search query, such as navigation or triggering specific functionality.
86+ *
87+ * @param payload - The payload object containing the search content
88+ * @param payload.content - The search query string entered by the user
89+ *
90+ * @example
91+ * ```typescript
92+ * action: ({ content }) => {
93+ * // Navigate to search results page
94+ * window.location.href = `/search?q=${encodeURIComponent(content)}`;
95+ * }
96+ * ```
4897 */
49- run ( value : string , callback ?: ( ) => void ) : Promise < ReactNode [ ] > ;
98+ action ?: ( payload : { content : string } ) => void ;
5099}
51100
101+ /**
102+ * Setup contract for the global search service.
103+ * Provides methods to register search commands and submit commands during the setup lifecycle.
104+ * @experimental
105+ */
52106export interface GlobalSearchServiceSetupContract {
107+ /**
108+ * Registers a search command that will be executed when users perform searches in the global search bar.
109+ * Each command must have a unique ID and will be invoked based on the search query pattern.
110+ *
111+ * @param searchCommand - The search command to register
112+ * @throws Warning if a command with the same ID already exists
113+ *
114+ * @example
115+ * ```typescript
116+ * chrome.globalSearch.registerSearchCommand({
117+ * id: 'my-search-command',
118+ * type: 'PAGES',
119+ * run: async (query, callback, abortSignal) => {
120+ * // Perform search logic
121+ * return [<SearchResult key="1">Result 1</SearchResult>];
122+ * }
123+ * });
124+ * ```
125+ */
53126 registerSearchCommand ( searchCommand : GlobalSearchCommand ) : void ;
54127}
55128
129+ /**
130+ * Start contract for the global search service.
131+ * Provides methods to retrieve and manage search commands during the start lifecycle.
132+ * @experimental
133+ */
56134export interface GlobalSearchServiceStartContract {
135+ /**
136+ * Retrieves all registered search commands.
137+ * Returns an array of all search commands that have been registered during the setup phase.
138+ *
139+ * @returns An array of all registered GlobalSearchCommand instances
140+ *
141+ * @example
142+ * ```typescript
143+ * const commands = chrome.globalSearch.getAllSearchCommands();
144+ * console.log(`Total commands: ${commands.length}`);
145+ * ```
146+ */
57147 getAllSearchCommands ( ) : GlobalSearchCommand [ ] ;
148+
149+ /**
150+ * Unregisters a previously registered search command by its ID.
151+ * This removes the command from the list of available search commands.
152+ *
153+ * @param id - The unique identifier of the search command to unregister
154+ *
155+ * @example
156+ * ```typescript
157+ * chrome.globalSearch.unregisterSearchCommand('my-search-command');
158+ * ```
159+ */
58160 unregisterSearchCommand ( id : string ) : void ;
161+
162+ /**
163+ * Returns an observable stream of all registered search commands.
164+ * Subscribers will receive updates whenever search commands are added or removed.
165+ *
166+ * @returns An Observable that emits the current array of GlobalSearchCommand instances
167+ *
168+ * @example
169+ * ```typescript
170+ * chrome.globalSearch.getAllSearchCommands$().subscribe(commands => {
171+ * console.log(`Available commands: ${commands.length}`);
172+ * });
173+ * ```
174+ */
175+ getAllSearchCommands$ : ( ) => Observable < GlobalSearchCommand [ ] > ;
176+ /**
177+ * Registers a search command that will be executed when users perform searches in the global search bar.
178+ * Each command must have a unique ID and will be invoked based on the search query pattern.
179+ *
180+ * @param searchCommand - The search command to register
181+ * @throws Warning if a command with the same ID already exists
182+ *
183+ * @example
184+ * ```typescript
185+ * chrome.globalSearch.registerSearchCommand({
186+ * id: 'my-search-command',
187+ * type: 'PAGES',
188+ * run: async (query, callback, abortSignal) => {
189+ * // Perform search logic
190+ * return [<SearchResult key="1">Result 1</SearchResult>];
191+ * }
192+ * });
193+ * ```
194+ */
195+ registerSearchCommand ( searchCommand : GlobalSearchCommand ) : void ;
59196}
60197
61198/**
@@ -76,7 +213,11 @@ export interface GlobalSearchServiceStartContract {
76213 * @experimental
77214 */
78215export class GlobalSearchService {
79- private searchCommands = [ ] as GlobalSearchCommand [ ] ;
216+ private searchCommands$ = new BehaviorSubject < GlobalSearchCommand [ ] > ( [ ] ) ;
217+
218+ private get searchCommands ( ) {
219+ return this . searchCommands$ . getValue ( ) ;
220+ }
80221
81222 private registerSearchCommand ( searchHandler : GlobalSearchCommand ) {
82223 const exists = this . searchCommands . find ( ( item ) => {
@@ -87,15 +228,16 @@ export class GlobalSearchService {
87228 console . warn ( `Duplicate SearchCommands id ${ searchHandler . id } found` ) ;
88229 return ;
89230 }
90- this . searchCommands . push ( searchHandler ) ;
231+ this . searchCommands$ . next ( [ ... this . searchCommands , searchHandler ] ) ;
91232 }
92233
93234 private unregisterSearchCommand ( id : string ) {
94- this . searchCommands = this . searchCommands . filter ( ( item ) => {
95- return item . id !== id ;
96- } ) ;
235+ this . searchCommands$ . next (
236+ this . searchCommands . filter ( ( item ) => {
237+ return item . id !== id ;
238+ } )
239+ ) ;
97240 }
98-
99241 public setup ( ) : GlobalSearchServiceSetupContract {
100242 return {
101243 registerSearchCommand : this . registerSearchCommand . bind ( this ) ,
@@ -106,6 +248,8 @@ export class GlobalSearchService {
106248 return {
107249 getAllSearchCommands : ( ) => this . searchCommands ,
108250 unregisterSearchCommand : this . unregisterSearchCommand . bind ( this ) ,
251+ getAllSearchCommands$ : ( ) => this . searchCommands$ . asObservable ( ) ,
252+ registerSearchCommand : this . registerSearchCommand . bind ( this ) ,
109253 } ;
110254 }
111255}
0 commit comments