diff --git a/schema/plugin.json b/schema/plugin.json index e2baf9e..0644399 100644 --- a/schema/plugin.json +++ b/schema/plugin.json @@ -56,9 +56,24 @@ "type": "string" } }, + "createEmptySection": { + "type": "boolean", + "title": "Show \"Create Empty\" section", + "default": true + }, "starredSection": { "type": "boolean", - "title": "Show starred section" + "title": "Show \"Starred\" section" + }, + "launchNotebookSection": { + "type": "boolean", + "title": "Show \"Launch New Notebook\" section", + "default": true + }, + "launchConsoleSection": { + "type": "boolean", + "title": "Show \"Launch New Console\" section", + "default": true }, "searchAllSections": { "type": "boolean", diff --git a/src/commands.ts b/src/commands.ts index beaeb55..f29c122 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -76,19 +76,58 @@ export function addCommands( await settings.set('columnOrder', order); } }); + app.commands.addCommand(CommandIDs.showCreateEmpty, { + isToggleable: true, + isToggled: () => { + return settings.composite + .createEmptySection as ISettingsLayout['createEmptySection']; + }, + label: trans.__('Show "Create Empty" Section'), + execute: async () => { + const createEmptySection = settings.composite + .createEmptySection as ISettingsLayout['createEmptySection']; + await settings.set('createEmptySection', !createEmptySection); + } + }); app.commands.addCommand(CommandIDs.showStarred, { isToggleable: true, isToggled: () => { return settings.composite .starredSection as ISettingsLayout['starredSection']; }, - label: trans.__('Show Starred Section'), + label: trans.__('Show "Starred" Section'), execute: async () => { const starredSection = settings.composite .starredSection as ISettingsLayout['starredSection']; await settings.set('starredSection', !starredSection); } }); + app.commands.addCommand(CommandIDs.showNotebookLauncher, { + isToggleable: true, + isToggled: () => { + return settings.composite + .launchNotebookSection as ISettingsLayout['launchNotebookSection']; + }, + label: trans.__('Show "Launch New Notebook" Section'), + execute: async () => { + const launchNotebookSection = settings.composite + .launchNotebookSection as ISettingsLayout['launchNotebookSection']; + await settings.set('launchNotebookSection', !launchNotebookSection); + } + }); + app.commands.addCommand(CommandIDs.showConsoleLauncher, { + isToggleable: true, + isToggled: () => { + return settings.composite + .launchConsoleSection as ISettingsLayout['launchConsoleSection']; + }, + label: trans.__('Show "Launch New Console" Section'), + execute: async () => { + const launchConsoleSection = settings.composite + .launchConsoleSection as ISettingsLayout['launchConsoleSection']; + await settings.set('launchConsoleSection', !launchConsoleSection); + } + }); app.commands.addCommand(CommandIDs.searchAllSections, { isToggleable: true, isToggled: () => { diff --git a/src/components/quick-settings.tsx b/src/components/quick-settings.tsx index 6bdfe51..a0d41e4 100644 --- a/src/components/quick-settings.tsx +++ b/src/components/quick-settings.tsx @@ -12,7 +12,10 @@ export function QuickSettings(props: { const { commands } = props; const menu = new MenuSvg({ commands: commands }); + menu.addItem({ command: CommandIDs.showCreateEmpty }); menu.addItem({ command: CommandIDs.showStarred }); + menu.addItem({ command: CommandIDs.showNotebookLauncher }); + menu.addItem({ command: CommandIDs.showConsoleLauncher }); menu.addItem({ command: CommandIDs.searchAllSections }); menu.addItem({ command: CommandIDs.openSettings }); diff --git a/src/launcher.tsx b/src/launcher.tsx index 497f79e..88f944c 100644 --- a/src/launcher.tsx +++ b/src/launcher.tsx @@ -45,11 +45,29 @@ function LauncherBody(props: { props; const [query, updateQuery] = React.useState(''); const [, forceUpdate] = React.useReducer(x => x + 1, 0); + const [showCreateEmpty, updateCreateEmpty] = React.useState< + ISettingsLayout['createEmptySection'] + >( + props.settings.composite + .createEmptySection as ISettingsLayout['createEmptySection'] + ); const [showStarred, updateShowStarred] = React.useState< ISettingsLayout['starredSection'] >( props.settings.composite.starredSection as ISettingsLayout['starredSection'] ); + const [showNotebookLauncher, updateShowNotebookLauncher] = React.useState< + ISettingsLayout['launchNotebookSection'] + >( + props.settings.composite + .launchNotebookSection as ISettingsLayout['launchNotebookSection'] + ); + const [showConsole, updateShowConsole] = React.useState< + ISettingsLayout['launchConsoleSection'] + >( + props.settings.composite + .launchConsoleSection as ISettingsLayout['launchConsoleSection'] + ); const [searchAll, updateSearchAll] = React.useState< ISettingsLayout['searchAllSections'] @@ -59,11 +77,27 @@ function LauncherBody(props: { ); const syncSettings = () => { + const newShowCreateEmpty = props.settings.composite + .createEmptySection as ISettingsLayout['createEmptySection']; + if (showCreateEmpty !== newShowCreateEmpty) { + updateCreateEmpty(newShowCreateEmpty); + } const newStarred = props.settings.composite .starredSection as ISettingsLayout['starredSection']; if (showStarred !== newStarred) { updateShowStarred(newStarred); } + const newShowConsole = props.settings.composite + .launchConsoleSection as ISettingsLayout['launchConsoleSection']; + if (showConsole !== newShowConsole) { + updateShowConsole(newShowConsole); + } + const newShowNotebook = props.settings.composite + .launchNotebookSection as ISettingsLayout['launchNotebookSection']; + if (showNotebookLauncher !== newShowNotebook) { + updateShowNotebookLauncher(newShowNotebook); + } + const newSearchAll = props.settings.composite .searchAllSections as ISettingsLayout['searchAllSections']; if (searchAll !== newSearchAll) { @@ -80,9 +114,18 @@ function LauncherBody(props: { if (favouritesChanged) { const updateIfNeeded = () => { + if (showCreateEmpty) { + forceUpdate(); + } if (showStarred) { forceUpdate(); } + if (showNotebookLauncher) { + forceUpdate(); + } + if (showConsole) { + forceUpdate(); + } }; React.useEffect(() => { favouritesChanged.connect(updateIfNeeded); @@ -110,8 +153,9 @@ function LauncherBody(props: { const startCollapsed = props.settings.composite .collapsedSections as ISettingsLayout['collapsedSections']; - const builtinSections: ISectionOptions[] = [ - { + const builtinSections: ISectionOptions[] = []; + if (showCreateEmpty) { + builtinSections.push({ className: 'jp-Launcher-openByType', title: trans.__('Create Empty'), icon: fileIcon, @@ -125,8 +169,36 @@ function LauncherBody(props: { item.label.toLowerCase().indexOf(query.toLowerCase()) !== -1 ) .map(item => ) - }, - { + }); + } + if (showStarred) { + builtinSections.push({ + className: 'jp-Launcher-openByKernel', + title: trans.__('Starred'), + icon: starIcon, + id: 'starred', + rank: 2, + render: () => + starred.length > 0 ? ( + item.execute()} + favouritesChanged={props.favouritesChanged} + lastUsedChanged={props.lastUsedChanged} + /> + ) : ( + trans.__('No starred items') + ) + }); + } + if (showNotebookLauncher) { + builtinSections.push({ className: 'jp-Launcher-openByKernel jp-Launcher-launchNotebook', title: trans.__('Launch New Notebook'), icon: notebookIcon, @@ -145,8 +217,10 @@ function LauncherBody(props: { lastUsedChanged={props.lastUsedChanged} /> ) - }, - { + }); + } + if (showConsole) { + builtinSections.push({ className: 'jp-Launcher-openByKernel jp-Launcher-launchConsole', title: trans.__('Launch New Console'), icon: consoleIcon, @@ -165,32 +239,6 @@ function LauncherBody(props: { lastUsedChanged={props.lastUsedChanged} /> ) - } - ]; - if (showStarred) { - builtinSections.push({ - className: 'jp-Launcher-openByKernel', - title: trans.__('Starred'), - icon: starIcon, - id: 'starred', - rank: 2, - render: () => - starred.length > 0 ? ( - item.execute()} - favouritesChanged={props.favouritesChanged} - lastUsedChanged={props.lastUsedChanged} - /> - ) : ( - 'No starred items' - ) }); } const allSections = [...builtinSections, ...props.sections]; diff --git a/src/types.ts b/src/types.ts index 371317a..829698f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -28,7 +28,10 @@ export namespace CommandIDs { export const create = 'launcher:create'; export const moveColumn = 'launchpad:table-move-column'; export const toggleColumn = 'launchpad:table-toggle-column'; + export const showCreateEmpty = 'launchpad:show-create-empty'; export const showStarred = 'launchpad:show-starred'; + export const showNotebookLauncher = 'launchpad:show-notebook-launcher'; + export const showConsoleLauncher = 'launchpad:show-console-launcher'; export const searchAllSections = 'launchpad:search-all-sections'; export const openSettings = 'launchpad:open-settings'; } @@ -36,7 +39,10 @@ export namespace CommandIDs { export interface ISettingsLayout { hiddenColumns: Record; columnOrder: string[]; + createEmptySection: boolean; starredSection: boolean; + launchNotebookSection: boolean; + launchConsoleSection: boolean; collapsedSections: Record; searchAllSections: boolean; utilityCommands: string[]; diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts b/ui-tests/tests/jupyterlab_new_launcher.spec.ts index 079650a..299e803 100644 --- a/ui-tests/tests/jupyterlab_new_launcher.spec.ts +++ b/ui-tests/tests/jupyterlab_new_launcher.spec.ts @@ -101,11 +101,23 @@ test.describe('Quick Settings', () => { const launcher = page.locator('.jp-LauncherBody'); await page.locator('.jp-Launcher-QuickSettings').click(); await page - .locator('.lm-Menu-itemLabel:text("Show Starred Section")') + .locator('.lm-Menu-itemLabel:text(\'Show "Starred" Section\')') .click(); const starredSection = page.locator( '.jp-CollapsibleSection-Title:has-text("starred")' ); await expect(starredSection).toBeVisible(); }); + + test('hide console 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 "Launch New Console" Section\')') + .click(); + const starredSection = page.locator( + '.jp-CollapsibleSection-Title:has-text("Launch New Console")' + ); + await expect(starredSection).toHaveCount(0); + }); }); 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 index 4424f62..7268532 100644 Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-open-quicksettings-linux.png 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/table-context-menu-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/table-context-menu-linux.png index cdff52c..80e4e68 100644 Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/table-context-menu-linux.png and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/table-context-menu-linux.png differ diff --git a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/table-context-menu-visible-columns-linux.png b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/table-context-menu-visible-columns-linux.png index 91aa78d..1465aa5 100644 Binary files a/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/table-context-menu-visible-columns-linux.png and b/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/table-context-menu-visible-columns-linux.png differ