Repository: nebari-dev/jupyterlab-launchpad (language: python)

Issue:
Add a settings button or menu (in top right corner?)
We could add the cog icon in the top right corner:

![image](https://github.com/nebari-dev/jupyterlab-new-launcher/assets/5832902/18a25250-435d-4a26-9d84-9c15bf1e610f)

It could either open the existing settings section (which currently is 3-4 clicks away):

![image](https://github.com/nebari-dev/jupyterlab-new-launcher/assets/5832902/74338241-517e-4d08-a3ce-ec03d0c34150)

Or show a small menu allowing to toggle some quick settings (like whether to show starred section).

Thoughts?


Discussion / hints:
I like this idea. The name may change to something more specific, but I had to actually read through the list of settings to find the settings for "New Launcher" because the name is fairly generic. This would really help jump right to it. 
@krassowski, have you started on this, or is this something I can take a stab at?
No, I haven't - feel free to pick it up
@krassowski, I've been trying to figure out how to open the specific settings page via a button, and I am struggling to find a way. It looks like I can use `settingeditor:open`, but I don't think I can pass it any arguments to specify specific plugins. Am I missing something? 

If that's the case, then I think I will need to go with the second option here of adding a dropdown for key settings. Above you mentioned the setting for showing starred section. What other sections do you think should be included here? 
>  It looks like I can use settingeditor:open, but I don't think I can pass it any arguments to specify specific plugins.

Something like this should work:

```js
app.commands.execute('settingeditor:open', {
  query: 'New Launcher'
})
```

> If that's the case, then I think I will need to go with the second option here of adding a dropdown for key settings

I think that would be best in either case - I think having quick settings may make them more discoverable.

>  What other sections do you think should be included here?

Including a toggle for `searchAllSections` might be valuable too.

Maybe something like:

```
✓ Search in All Sections
✓ Show Starred Section
  Open Settings
```

We can add more items later. I think you use `Menu` class and add commands to it (which will need to be created).
Any updates @andrewfulton9?
@krassowski, it's coming along. I've added commands for the new options, and added the commands to a Menu object. I am currently working on displaying the menu in a popup opened from a settings icon.

Fix patch:
diff --git a/src/commands.ts b/src/commands.ts
index 1f134cd..8c454c4 100644
--- a/src/commands.ts
+++ b/src/commands.ts
@@ -76,4 +76,38 @@ export function addCommands(
       await settings.set('columnOrder', order);
     }
   });
+  app.commands.addCommand(CommandIDs.showStarred, {
+    isToggleable: true,
+    isToggled: () => {
+      return settings.composite
+        .starredSection as ISettingsLayout['starredSection'];
+    },
+    label: trans.__('Show Starred Section'),
+    execute: async () => {
+      const starredSection = settings.composite
+        .starredSection as ISettingsLayout['starredSection'];
+      await settings.set('starredSection', !starredSection);
+    }
+  });
+  app.commands.addCommand(CommandIDs.searchAllSections, {
+    isToggleable: true,
+    isToggled: () => {
+      return settings.composite
+        .searchAllSections as ISettingsLayout['searchAllSections'];
+    },
+    label: trans.__('Search in All Sections'),
+    execute: async () => {
+      const searchAllSections = settings.composite
+        .searchAllSections as ISettingsLayout['searchAllSections'];
+      await settings.set('searchAllSections', !searchAllSections);
+    }
+  });
+  app.commands.addCommand(CommandIDs.openSettings, {
+    label: trans.__('Open Settings Editor'),
+    execute: () => {
+      app.commands.execute('settingeditor:open', {
+        query: 'New Launcher'
+      });
+    }
+  });
 }
diff --git a/src/components/quick-settings.tsx b/src/components/quick-settings.tsx
new file mode 100644
index 0000000..6bdfe51
--- /dev/null
+++ b/src/components/quick-settings.tsx
@@ -0,0 +1,48 @@
+import { TranslationBundle } from '@jupyterlab/translation';
+import type { CommandRegistry } from '@lumino/commands';
+import { MenuSvg, settingsIcon } from '@jupyterlab/ui-components';
+import * as React from 'react';
+
+import { CommandIDs } from '../types';
+
+export function QuickSettings(props: {
+  trans: TranslationBundle;
+  commands: CommandRegistry;
+}): React.ReactElement {
+  const { commands } = props;
+
+  const menu = new MenuSvg({ commands: commands });
+  menu.addItem({ command: CommandIDs.showStarred });
+  menu.addItem({ command: CommandIDs.searchAllSections });
+  menu.addItem({ command: CommandIDs.openSettings });
+
+  const iconRef = React.useRef<HTMLDivElement>(null);
+
+  const onClickHandler = (event: React.MouseEvent) => {
+    const current = iconRef.current;
+    let x, y;
+    if (current) {
+      const position = current.getBoundingClientRect();
+      x = position.left;
+      y = position.bottom;
+    } else {
+      x = event.clientX;
+      y = event.clientY;
+    }
+    menu.open(x, y);
+  };
+
+  return (
+    <div
+      className="jp-Launcher-TypeCard jp-LauncherCard jp-Launcher-QuickSettings"
+      ref={iconRef}
+      onClick={event => {
+        onClickHandler(event);
+      }}
+    >
+      <div className="jp-LauncherCard-icon">
+        <settingsIcon.react />
+      </div>
+    </div>
+  );
+}
diff --git a/src/launcher.tsx b/src/launcher.tsx
index f334c8c..04f0761 100644
--- a/src/launcher.tsx
+++ b/src/launcher.tsx
@@ -10,6 +10,7 @@ import {
   notebookIcon,
   consoleIcon
 } from '@jupyterlab/ui-components';
+
 import * as React from 'react';
 import {
   IItem,
@@ -23,6 +24,7 @@ import { Item } from './item';
 import { KernelTable } from './components/table';
 import { CollapsibleSection } from './components/section';
 import { TypeCard } from './components/card';
+import { QuickSettings } from './components/quick-settings';
 
 function LauncherBody(props: {
   trans: TranslationBundle;
@@ -36,7 +38,8 @@ function LauncherBody(props: {
   favouritesChanged: ISignal<IFavoritesDatabase, void>;
   lastUsedChanged: ISignal<ILastUsedDatabase, void>;
 }): React.ReactElement {
-  const { trans, cwd, typeItems, otherItems, favouritesChanged } = props;
+  const { trans, cwd, typeItems, commands, otherItems, favouritesChanged } =
+    props;
   const [query, updateQuery] = React.useState<string>('');
   const [, forceUpdate] = React.useReducer(x => x + 1, 0);
   const [showStarred, updateShowStarred] = React.useState<
@@ -116,6 +119,7 @@ function LauncherBody(props: {
           {otherItems.map(item => (
             <TypeCard item={item} trans={trans} />
           ))}
+          <QuickSettings commands={commands} trans={trans} />
         </div>
       </div>
       {searchAll ? (
diff --git a/src/types.ts b/src/types.ts
index a8078c8..6e062a7 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -14,6 +14,9 @@ export namespace CommandIDs {
   export const create = 'launcher:create';
   export const moveColumn = 'new-launcher:table-move-column';
   export const toggleColumn = 'new-launcher:table-toggle-column';
+  export const showStarred = 'new-launcher:show-starred';
+  export const searchAllSections = 'new-launcher:search-all-sections';
+  export const openSettings = 'new-launcher:open-settings';
 }
 
 export interface ISettingsLayout {


Test patch:
diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts b/ui-tests/tests/jupyterlab_new_launcher.spec.ts
index a3ec91e..f7aa18f 100644
--- a/ui-tests/tests/jupyterlab_new_launcher.spec.ts
+++ b/ui-tests/tests/jupyterlab_new_launcher.spec.ts
@@ -1,4 +1,5 @@
 import { expect, test, galata } from '@jupyterlab/galata';
+import { Page } from '@playwright/test';
 
 const SETTINGS_ID = 'jupyterlab-new-launcher:plugin';
 
@@ -80,3 +81,25 @@ test.describe('Filter individual', () => {
     );
   });
 });
+
+test.describe('Quick Settings', () => {
+  test('open quick settings menu', async ({ page }) => {
+    const launcher = page.locator('.jp-LauncherBody');
+    await page.locator('.jp-Launcher-QuickSettings').click();
+    expect(await launcher.screenshot()).toMatchSnapshot(
+      'launcher_open_quicksettings.png'
+    );
+  });
+
+  test('show starred from quick settings', async ({ page }) => {
+    const launcher = page.locator('.jp-LauncherBody');
+    await page.locator('.jp-Launcher-QuickSettings').click();
+    await page
+      .locator('.lm-Menu-itemLabel:text("Show Starred Section")')
+      .click();
+    const starredSection = page.locator(
+      '.jp-CollapsibleSection-Title:has-text("starred")'
+    );
+    await expect(starredSection).toBeVisible();
+  });
+});
diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-linux.png
index 4043a38..a225e96 100644
Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-linux.png and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-linux.png differ
diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-open-quicksettings-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-open-quicksettings-linux.png
new file mode 100644
index 0000000..6fedadd
Binary files /dev/null and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-open-quicksettings-linux.png differ
diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-search-in-individual-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-search-in-individual-linux.png
index 25b7721..35d8639 100644
Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-search-in-individual-linux.png and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-search-in-individual-linux.png differ
diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-with-starred-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-with-starred-linux.png
index abc175c..6aa2e10 100644
Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-with-starred-linux.png and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-with-starred-linux.png differ