npm package: @glue42/launchpad-ui-react
Description: Glue42 Launchpad and GlobalSearch React Components
Author: Glue42
Latest version: 0.5.8

# [Glue42 Launchpad and Global Search](https://docs.glue42.com) · ![](https://img.shields.io/badge/license-MIT-blue.svg) ![](https://badge.fury.io/js/%40glue42%2Flaunchpad-ui-react.svg) ![example workflow](https://github.com/github/docs/actions/workflows/main.yml/badge.svg) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)


This @glue42/launchpad-react-ui component library contains Glue42 enabled React components that let you create a Glue42 toolbar. It exports two main components: ```<Launchpad/>``` and ```<GlobalSearch/>```. The primary purpose of a Glue42 toolbar is managing the applications, workspaces and various Glue42 Enterprise settings available to the user. In addition to that, you can create an application that implements the ```Search Provider``` protocol and be able to send your own custom search results to the ```<GlobalSearch/>``` component, which can do whatever you program them to do, when a user clicks on them!

Currently @glue42/launchpad-react-ui components only work with Glue42 Enterprise. Glue Desktop for Enterprise should already be running in order for the toolbar to be usable.

## Quick Start
---
### Getting started with the default settings

You need to a create a ```React``` application using ```create-react-app``` cli tool. Run the following command in a directory of your choice:

```npm
npx create-react-app awesome-glue-toolbar
```

The toolbar is a ```Glue Desktop Application``` that is configured to run on ```http://localhost:3008``` by default. The ```<Launchpad />``` component is served on the URL path ```/launchpad``` and the ```<GlobalSearch />``` component is served on the URL path ```/global-search```. You must instruct ```create-react-app``` to launch the ```awesome-glue-toolbar``` application on **port 3008**. You can do that by creating a ```.env``` file at the root of the project directory with the following text:

```bash
PORT=3008
SKIP_PREFLIGHT_CHECK=true
```

After setting up on which port the application should run on, install the following dependencies:
```npm
npm i -S @glue42/launchpad-ui-react @glue42/react-hooks react-router-dom
```

The toolbar expects that the **Glue** object is initialized using the ```@glue42/react-hooks``` library. You need to import the ```<GlueProvider />``` component from it. It uses the ```React Context API``` to pass the initialized ```Glue``` object down the ```React``` tree. You need to pass the following object ```{ appManager: 'full', layouts: 'full' ``` to the ```config``` prop of the ```<GlueProvider />```, because they are required for proper operation.
Go to the ```index.js``` file of the ```awesome-glue-toolbar``` project and add the following code:

```jsx
import React from 'react';
import ReactDOM from 'react-dom';
import '@glue42/launchpad-ui-react/dist/vnext.css';
import Glue from '@glue42/desktop';
import { GlueProvider } from '@glue42/react-hooks';

import { LaunchPad, GlobalSearch } from '@glue42/launchpad-ui-react';

ReactDOM.render(
  <GlueProvider config={{ appManager: 'full', layouts: 'full' }} glueFactory={Glue}>
    <BrowserRouter>
      <Routes>
        <Route path="/launchpad" element={<LaunchPad/>} />
        <Route path="/global-search" element={<GlobalSearch placeholder="Search..."/>} />
      </Routes>
    </BrowserRouter>
  </GlueProvider>,
  document.getElementById('root')
);
```

and run the following command:
```npm
npm start
```

You should now be able to open **Launchpad** when you press the ```Wnd + G``` keyboard combination and **Global Search** when you press the ```Ctrl + Space``` keyboard combination.

## Launchpad Features Overview
---
### Displaying all applications and layouts of type ```Global``` and ```Workspace``` in ```<Launchpad/>``` which are not hidden

Upon starting the application that uses the ```<Launchpad/>``` component, it will load all of the Glue42 applications and layouts that are avaliable to the current user. 

### Grouping applications and layouts by folders

Folder names can be specified in the configuration files of different layouts and applications which ```Launchpad``` will automatically detect and group the applications and layouts by their corresponding folders. Layouts and applications without folders will be grouped at the bottom of the list

### Providing a custom sort order for each application

Applications and layouts can be rearranged by setting the ```userProperties.appManagerOrder``` in each applications config. By default each application has a **sortOrder of 1000**. When two applications have the same sort order, they will be ordered lexicographically. Folders inherit the minimum of the sort orders of the child applications.

### Searching by application/layout name

At the top there is a search bar which allows for searching applications and layouts by name.

### Constrain the search to layout names only

When you click on the ```Show layouts only``` button next to the search bar, ```<Launchpad/>``` will show you only the layouts whose name includes the search term.

### Marking applications and layouts as favorites

You can mark every application and layout in the list as favorite by clicking on the star icon next to it's name, so that you can have easy access to it in the future. Clicking on the star icon again will unmark the given application as favorite.

### Track recently used applications and layouts

Every time you click on applications and layouts they will be marked as recently used.

### Use the context-sensitive menu

You can right click on items in the list of applications and layouts, on the favorite and recently used applications and layouts as well, which will bring up a context-sensitive menu. You can mark an application or layout as favorite, unmark it, and you can even delete layouts using this menu, when you click on a layout

### Saving the current layout

When you have a few open applications, you can save them as a layout by pressing the keyboard combination Ctrl + S while the Launchpad part of the toolbar is open. This will bring a dialog which will prompt you to enter the layout's name and then save it when you click on the save button. If you enter a layout's name which already exists, the dialog will offer to replace the existing layout. You can close the dialog ot any time by clicking on the ```Cancel``` button, by clicking on the close button at the top of the window, or by pressing the ```Escape``` key.

### See notifications and open the notifications bar

You have a bell icon at the top left corner of the ```Launchpad``` window which shows the current number of unread notifications. By clicking on it, you can view them in the notifications bar, which will be opened.

### Hamburger menu

Next to the notifications bell, there is a hamburger menu which contains useful information and a couple of features. The information included is:

* Glue42 Version
* Current user
* Gateway URL
* Environment and region

The functionality provided by the hamburger menu is:

* Save Layout - which will open the previously mentioned layout dialog
* Launch Global Search - which will open the Global Search window
* Switch Themes
* Feedback - which will open the Glue42 Feedback form
* About - which will open the Glue42 About form
* Restart
* Shutdown

## Global Search Features Overview
---

### Loading results from Search Providers

```Global Search``` will make a request to all ```Glue 42 Search Providers``` when you start typing in the search box. All the results will be displayed in a list at the bottom of the search box.

### Mark result as favorite

You can mark the returned results as favorites by clicking on the star icon next to their name. They will be presented in ```Launchpad```.

### Mark results as recently used

Whenever a search result is clicked or opened in any way through ```Global Search```, it will be marked as recently used in ```Launchpad```.

### Provide your custom search results

You can create your own ```Search Provider```! ```Global Search``` follows a protocol when making requests to and getting results from search providers. The protocol uses the ```Glue42 Interop API``` as a communication medium. If you properly implement the given protocol and supply data in the appropriate format, you can send results to ```Global Search``` whenever someone starts searching for something!
The protocol is not limited to just returning items as search results. You can specify an action that should happen when someone clicks on the result that has been returned by your search provider! The only limitation is that the action must happen through the ```Glue42 Interop API```.

## Customizations
---
### LaunchPad

#### **Hiding the favorite and recent applications panel**

You can toggle the ```showFavoritesAndRecentsPanel``` flag to show/hide the panel with the favorite and recent applications:

```jsx
<LaunchPad
  showFavoritesAndRecentsPanel={false}
/>
```
The above example will hide the favorites and recents panel.

#### **Hiding the save layout icon**

You can toggle the ```showSaveButton``` flag to show/hide the save button at the top of the application:

```jsx
<LaunchPad
  showSaveButton={false}
/>
```

The above example will hide the save layout button.

#### **Hiding the notifications button**

You can toggle the ```showNotificationsButton``` button to show/hide the notifications button at the top of the application:
```jsx
<LaunchPad
  showNotificationsButton={false}
/>
```

The above example will hide the notifications button.

*The following props are implemented using React's [render prop pattern](https://reactjs.org/docs/render-props.html). Refer to the documentation for a thorough explanation of what it is and how it works.*

#### **Adding custom/reordering items in the hamburger menu**
You can reorder the items in the hamburger menu and you can even add you own custom elements using ```<LaunchPad/>```'s ```hamburgerMenuItems``` props.

```jsx
import { AboutMenuItem } from '@glue42/launchpad-ui-react';

<LaunchPad
  components={{
    hamburgerMenuItems: [
      AboutMenuItem
    ]
  }}
/>
```

The code snippet above will remove all items from the hamburger menu and leave only the ```AboutMenuItem```, which when clicked gives information about the application.
All snippets can be imported from the ```@glue42/launchpad-ui-react``` library. Here is a list of all the menu items that you can add to the ```hamburgerMenuItems``` array prop:
* AboutMenuItem - gives information about the application when clicked on
* SaveLayoutMenuItem - opens the save layout dialog which allows you the save a group of applications as a single layout
* LaunchGlobalSearchMenuItem - open the ```Global Search``` application
* SwitchThemesMenuItem - switches the themes of the application
* FeedbackMenuItem - allows the user to send feedback about the application when clicked on
* DividerMenuItem - inserts a dividing line between to adjacent menu items
* SystemInfoHeader - the system information header item
* SystemInfoVersion - shows the system version
* SystemInfoUser - shows the current user
* SystemInfoGatewayURL - shows the Gateway URL
* SystemInfoEnvRegion - shows the environment and the region of the application
* RestartAppMenuItem - shows the restart application button
* ShutdownAppMenuItem - shows the shutdown application button

You can add your own custom menu items like so:

```jsx
import { FeedbackMenuItem } from '@glue42/launchpad-ui-react';

<LaunchPad 
  components={{
    hamburgerMenuItems: [
      FeedbackMenuItem,
      () => <p>This is my custom hamburger menu item component</p>
    ]
  }}
/>
```
This will show the send feedback button and your own custom hamburger menu component below it. **Note: In order to have a properly formatted menu items you need to use the ```<DropdownItem/>``` component which we export. If you do not wrap your menu item JSX with this component, you are responsible for the proper styling of your custom menu item.**

Here is how to insert a custom menu item component that is styled like the existing build-in menu item components:
```jsx
import { DropdownItem } from '@glue42/launchpad-ui-react';

<LaunchPad 
  components={{
    hamburgerMenuItems: [
      () => <DropdownItem>This is FIRST custom hamburger menu item component</DropdownItem>,
      () => <DropdownItem>This is SECOND custom hamburger menu item component</DropdownItem>
    ]
  }}
/>
```

This will display your custom menu items with styling that makes them visually appear like the built-in menu items.

#### **Adding a custom restart/shutdown dialog content**
You can create custom dialog content for when the user clicks the shutdown or restart button to exit the application. The following examples will show how to create such content:

```jsx
<LaunchPad 
  components={{
    renderShutdownDialog: ({ closeDialog }) => {
      return (
        <div>
          <p>Do you want to shutdown LaunchPad?</p>
          <button onClick={() => glue.appManager.exit({showDialogs: false})}>Yes</button>
          <button onClick={closeDialog}>No</button>
        </div>
      )
    }
  }}
/>
```

```jsx
<LaunchPad 
  components={{
    renderRestartDialog: ({ closeDialog }) => {
      return (
        <div>
          <p>Do you want to restart LaunchPad?</p>
          <button onClick={() => glue.appManager.restart()}>Yes</button>
          <button onClick={closeDialog}>No</button>
        </div>
      )
    }
  }}
/>
```

#### **Adding a custom logo**
You can add your own custom logo that will be shown on the upper right corner of the UI. You can change the logo by using the ```logo``` property that is part of the ```components``` prop on the ```<LaunchPad />``` component like in the following example:

```jsx
<LaunchPad
  components={{
    logo={() => <img src={/my/awesome/company/logo}>}
  }}
/>
```

#### **Adding a custom list item renderer**
Additionally, you can customize how the list items on the left (the ones that show applications and layouts) are rendered by passing your own renderer to the ```<LaunchPad />``` component like so:

```jsx
<LaunchPad
  components={{
    renderApplicationsAndLayoutsItem={props => <p>This is my custom list item!</p>}
  }}
/>
```
The custom component that you pass will receive the following properties from the ```<LaunchPad />``` components:

* *app* - this is the internal representation of ```Glue42 Applications``` and ```Glue42 Layouts (global and workspace)``` that ```LaunchPad``` uses. It is the current app of the current row that is being rendered.
* *focusOrder* - this is a ```number``` that represents the position at which the current list item should receive focus. It is used internally by focus manager of ```<LaunchPad />```. **In order for your renderer to participate in focus switching, you must register it with the ```FocusArea``` React context. Otherwise, your renderer will work, but it will not receive focus. Example given below:**
* *level* - this is a ```number``` that represents the nesting level of the currently rendered application. The levels start from 0, which means that the application is not in any folder, and increases by 1 for each nesting level. **Currently we can't nest folders but this will probably be added in the near future.**

```jsx
    const appRef = useRef<HTMLElement | null>(null);

    const { addFocusElement } = useContext(FocusAreaContext);

    useEffect(() => {
        if (addFocusElement && appRef && (focusOrder !== undefined)) {
            addFocusElement({ focusOrder, elementRef: appRef });
        }
        return;
    }, [addFocusElement, appRef, focusOrder]);

    return (<div ref={appRef}>My custom HTML</div>)
```
* *setShowcaseApp* - you can use this function to send the application to be showcased the the user hovers over it, clicks it, moves focus to it, etc. You can use it likes so:

```jsx
<div
  onMouseOver={() => setShowcaseApp(app)}
  onMouseLeave={() => setShowcaseApp(undefined)}
  ...
```

This will display the application in the special showcase component inside of ```<LaunchPad />``` when the user hovers over your custom list item renderer and will clear the application from the showcase component when the user's mouse leaves the div element.

* *markRecentlyUsed* - you can use this function to mark the current application being rendered as favorite. Here is an example of marking the application as recently used when the user click's on the application:

```jsx
<div
  onClick={() => markRecentlyUsed(app)}
```

* *markFavorite* - this function can be used to mark the application as favorite. This will cause ```<LaunchPad />``` to display the application in the **Favorites** grid to the right of the list Example:

```jsx
<div
  onClick={() => markFavorite(app)}
```

* *unmarkFavorite* - this function can be used to remove the application from favorites, which will cause ```<LaunchPad />``` to remove the application from the favorites grid to the right of the list items. This example will unmark the application as favorite whenever the user right clicks on it:

```jsx
<div
  onContextMenu={() => unmarkFavorite(app)}
```

* *syncFavWithLP* - this function is used to synchronize the favorite applications with ```<GlobalSearch />```. Because ```<LaunchPad />``` and ```<GlobalSearch />``` are used as separate applications, internally they use the ```Glue42 Interop API``` to understand which applications have been marked as recent or favorite. **Note: Every application has a 'persistable' form. You get this from when you call the getPersistableForm() method. You must send the persistable form and from each application or the Glue42 Interop API will throw an error!**. Example usage:

```jsx
<div
  onKeyDown={e => {
    if (e.key === "Enter") {
      markFavorite(app);
      // ATTENTION: SEND THE PERSISTABLE FORM
      syncFavWithLP(app.getPersistableForm());
    }
  }}
```

* *syncUnfavWithLP* - use this function to synchronize and application that was unmarked as favorite. **Note: Send the persistable form of the application, which you can get using the getPersistableForm() method of the application**. Example:

```jsx
<div
  onKeyDown={e => {
    if (e.key === "Enter") {
      unmarkFavorite(app);
      // ATTENTION: SEND THE PERSISTABLE FORM
      syncUnfavWithLP(app.getPersistableForm());
    }
  }}
```
The above examples will mark/unmark the application as favorite in ```<LaunchPad />``` and synchronize the change with ```<GlobalSearch />```.

*The next three methods work with the LaunchPad's context menu. You pass an application to it and the coordinates at which you want the context menu to appear at.*

* *setIsContextMenuOpen* - tell ```<LaunchPad />``` to open the context menu.

* *setContextMenuCoordinates* - the coordinates at which to render the context menu (usually the current mouse x and y coordinates).

* *setAppForContextMenu* - the application which the context menu analyses and display different options based on the state of the application (hence the name "context" menu).

Example usage of all of the above mentioned methods:
```jsx
<div
  onContextMenu={e => {
    setAppForContextMenu(app);
    setContextMenuCoordinates({ x: e.pageX, y: e.pageY });
    setIsContextMenuOpen(true);
  }}
```
This example will open the context menu with the current application selected at the user's current mouse coordinates, when the user clicks on the list item with the right mouse button.

### **Adding a custom renderer for applications marked as favorite**

Additionally, you can customize how the favorite items are being rendered on the right (the ones that show applications and layouts) are rendered by passing your own renderer to the ```<LaunchPad />``` component like so:

```jsx
<LaunchPad
  components={{
    renderFavoriteItem={props => <p>This is my custom favorite item!</p>}
  }}
/>
```
* *app* - this is the internal representation of ```Glue42 Applications``` and ```Glue42 Layouts (global and workspace)``` that ```LaunchPad``` uses. It is the current app of the current row that is being rendered.
* *focusOrder* - this is a ```number``` that represents the position at which the current list item should receive focus. It is used internally by focus manager of ```<LaunchPad />```. **In order for your renderer to participate in focus switching, you must register it with the ```FocusArea``` React context. Otherwise, your renderer will work, but it will not receive focus. Example given below:**

```jsx
    const appRef = useRef<HTMLElement | null>(null);

    const { addFocusElement } = useContext(FocusAreaContext);

    useEffect(() => {
        if (addFocusElement && appRef && (focusOrder !== undefined)) {
            addFocusElement({ focusOrder, elementRef: appRef });
        }
        return;
    }, [addFocusElement, appRef, focusOrder]);

    return (<div ref={appRef}>My custom HTML</div>)
```
* *setShowcaseApp* - you can use this function to send the application to be showcased the the user hovers over it, clicks it, moves focus to it, etc. You can use it likes so:

```jsx
<div
  onMouseOver={() => setShowcaseApp(app)}
  onMouseLeave={() => setShowcaseApp(undefined)}
  ...
```

This will display the application in the special showcase component inside of ```<LaunchPad />``` when the user hovers over your custom list item renderer and will clear the application from the showcase component when the user's mouse leaves the div element.

* *markRecentlyUsed* - you can use this function to mark the current application being rendered as favorite. Here is an example of marking the application as recently used when the user click's on the application:

```jsx
<div
  onClick={() => markRecentlyUsed(app)}
```
*The next three methods work with the LaunchPad's context menu. You pass an application to it and the coordinates at which you want the context menu to appear at.*

* *setIsContextMenuOpen* - tell ```<LaunchPad />``` to open the context menu.

* *setContextMenuCoordinates* - the coordinates at which to render the context menu (usually the current mouse x and y coordinates).

* *setAppForContextMenu* - the application which the context menu analyses and display different options based on the state of the application (hence the name "context" menu).

Example usage of all of the above mentioned methods:
```jsx
<div
  onContextMenu={e => {
    setAppForContextMenu(app);
    setContextMenuCoordinates({ x: e.pageX, y: e.pageY });
    setIsContextMenuOpen(true);
  }}
```
This example will open the context menu with the current application selected at the user's current mouse coordinates, when the user clicks on the list item with the right mouse button.

### **Adding a custom renderer for applications marked as recent**

Additionally, you can customize how the recent items are being rendered on the right (the ones that show applications and layouts) are rendered by passing your own renderer to the ```<LaunchPad />``` component like so:

```jsx
<LaunchPad
  components={{
    renderRecentItem={props => <p>This is my recent item!</p>}
  }}
/>
```

* *app* - this is the internal representation of ```Glue42 Applications``` and ```Glue42 Layouts (global and workspace)``` that ```LaunchPad``` uses. It is the current app of the current row that is being rendered.
* *focusOrder* - this is a ```number``` that represents the position at which the current list item should receive focus. It is used internally by focus manager of ```<LaunchPad />```. **In order for your renderer to participate in focus switching, you must register it with the ```FocusArea``` React context. Otherwise, your renderer will work, but it will not receive focus. Example given below:**

```jsx
    const appRef = useRef<HTMLElement | null>(null);

    const { addFocusElement } = useContext(FocusAreaContext);

    useEffect(() => {
        if (addFocusElement && appRef && (focusOrder !== undefined)) {
            addFocusElement({ focusOrder, elementRef: appRef });
        }
        return;
    }, [addFocusElement, appRef, focusOrder]);

    return (<div ref={appRef}>My custom HTML</div>)
```
* *setShowcaseApp* - you can use this function to send the application to be showcased the the user hovers over it, clicks it, moves focus to it, etc. You can use it likes so:

```jsx
<div
  onMouseOver={() => setShowcaseApp(app)}
  onMouseLeave={() => setShowcaseApp(undefined)}
  ...
```

This will display the application in the special showcase component inside of ```<LaunchPad />``` when the user hovers over your custom list item renderer and will clear the application from the showcase component when the user's mouse leaves the div element.

* *markRecentlyUsed* - you can use this function to mark the current application being rendered as favorite. Here is an example of marking the application as recently used when the user click's on the application:

```jsx
<div
  onClick={() => markRecentlyUsed(app)}
```

*The next three methods work with the LaunchPad's context menu. You pass an application to it and the coordinates at which you want the context menu to appear at.*

* *setIsContextMenuOpen* - tell ```<LaunchPad />``` to open the context menu.

* *setContextMenuCoordinates* - the coordinates at which to render the context menu (usually the current mouse x and y coordinates).

* *setAppForContextMenu* - the application which the context menu analyses and display different options based on the state of the application (hence the name "context" menu).

Example usage of all of the above mentioned methods:
```jsx
<div
  onContextMenu={e => {
    setAppForContextMenu(app);
    setContextMenuCoordinates({ x: e.pageX, y: e.pageY });
    setIsContextMenuOpen(true);
  }}
```
This example will open the context menu with the current application selected at the user's current mouse coordinates, when the user clicks on the list item with the right mouse button.

### **Adding a component at the top of LaunchPad**
This custom component can be added to the top of ```<LaunchPad />``` to display whatever you like. You will not receive any props. **Note you must be aware ot the css styling of <LaunchPad /> in order not to break the UI**.

```jsx
<LaunchPad
  components={{
    renderHeaderContents={() => <p>This will show at the very top of LaunchPad</p>}
  }}
/>

```

### Global Search
---
#### **Adding a custom renderer for a list item**

The only thing you can currently customize in ```<GlobalSearch />``` is the list item in the search results:


```jsx
<GlobalSearch
  components={{
    renderGlobalSearchItem{props => <p>My custom Global Search list item</p>}
  }}
/>
```

You will receive the following props from ```<GlobalSearch />```:

* *app* - this is the internal representation of ```Glue42 Applications``` and ```Glue42 Layouts (global and workspace)``` that ```LaunchPad``` uses. It is the current app of the current row that is being rendered.
* *focusOrder* - this is a ```number``` that represents the position at which the current list item should receive focus. It is used internally by focus manager of ```<GlobalSearch />```. **In order for your renderer to participate in focus switching, you must register it with the ```FocusArea``` React context. Otherwise, your renderer will work, but it will not receive focus. Example given below:**

```jsx
    const appRef = useRef<HTMLElement | null>(null);

    const { addFocusElement } = useContext(FocusAreaContext);

    useEffect(() => {
        if (addFocusElement && appRef && (focusOrder !== undefined)) {
            addFocusElement({ focusOrder, elementRef: appRef });
        }
        return;
    }, [addFocusElement, appRef, focusOrder]);

    return (<div ref={appRef}>My custom HTML</div>)
```
* *setShowcaseApp* - you can use this function to send the application to be showcased the the user hovers over it, clicks it, moves focus to it, etc. You can use it likes so:

```jsx
<div
  onMouseOver={() => setShowcaseApp(app)}
  onMouseLeave={() => setShowcaseApp(undefined)}
  ...
```

This will display the application in the special showcase component inside of ```<GlobalSearch />``` when the user hovers over your custom list item renderer and will clear the application from the showcase component when the user's mouse leaves the div element.

* *syncRecentWithLP* - you can use this function to mark the application as recent in ```<LaunchPad />```. Currently, ```<GlobalSearch />``` does not formally keep track of the recently used applications, so you only need to sync them with the other application:

```jsx
<div
  onClick={() => syncRecentWithLP(app)}
```

* *markFavorite* - this function can be used to mark the application as favorite. This will cause ```<GlobalSearch />``` to display the application in the **Favorites** grid to the right of the list Example:

```jsx
<div
  onClick={() => markFavorite(app)}
```

* *unmarkFavorite* - this function can be used to remove the application from favorites, which will cause ```<GlobalSearch />``` to remove the application from the favorites grid to the right of the list items. This example will unmark the application as favorite whenever the user right clicks on it:

```jsx
<div
  onContextMenu={() => unmarkFavorite(app)}
```

* *syncFavWithLP* - this function is used to synchronize the favorite applications with ```<LaunchPad />```. Because ```<LaunchPad />``` and ```<GlobalSearch />``` are used as separate applications, internally they use the ```Glue42 Interop API``` to understand which applications have been marked as recent or favorite. **Note: Every application has a 'persistable' form. You get this from when you call the getPersistableForm() method. You must send the persistable form and from each application or the Glue42 Interop API will throw an error!**. Example usage:

```jsx
<div
  onKeyDown={e => {
    if (e.key === "Enter") {
      markFavorite(app);
      // ATTENTION: SEND THE PERSISTABLE FORM
      syncFavWithLP(app.getPersistableForm());
    }
  }}
```

* *syncUnfavWithLP* - use this function to synchronize and application that was unmarked as favorite. **Note: Send the persistable form of the application, which you can get using the getPersistableForm() method of the application**. Example:

```jsx
<div
  onKeyDown={e => {
    if (e.key === "Enter") {
      unmarkFavorite(app);
      // ATTENTION: SEND THE PERSISTABLE FORM
      syncUnfavWithLP(app.getPersistableForm());
    }
  }}
```
The above examples will mark/unmark the application as favorite in ```<GlobalSearch />``` and synchronize the change with ```<LaunchPad />```.

#### **Change the placeholder**
The placeholder can be changed using the ``placeholder`` prop.
```jsx
<GlobalSearch
  placeholder="Search..."
/>
```