Skip to content

Commit

Permalink
Add starred section (#8)
Browse files Browse the repository at this point in the history
* Add starred section

* Use `test.describe`

* Distinguish between notebook/console in starred

* Hotfix for JupyterLab 4.2

* Harmonise border color between versions

* Update snapshots
  • Loading branch information
krassowski authored May 6, 2024
1 parent 9a9fcda commit f35b769
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 9 deletions.
6 changes: 6 additions & 0 deletions schema/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"type": "object",
"properties": {
"hiddenColumns": {
"title": "Hidden columns",
"type": "object",
"default": {
"conda_env_path": "hidden",
Expand All @@ -18,10 +19,15 @@
}
},
"columnOrder": {
"title": "Column order",
"type": "array",
"items": {
"type": "string"
}
},
"starredSection": {
"type": "boolean",
"title": "Show starred section"
}
},
"additionalProperties": false
Expand Down
13 changes: 13 additions & 0 deletions src/components/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export function KernelTable(props: {
query: string;
onClick: (item: IKernelItem) => void;
hideColumns?: string[];
showWidgetType?: boolean;
}) {
const { trans } = props;
let query: string;
Expand Down Expand Up @@ -121,6 +122,18 @@ export function KernelTable(props: {
}
);

if (props.showWidgetType) {
extraColumns.push({
id: 'widget-type',
label: trans.__('Type'),
renderCell: (row: IKernelItem) => {
return row.command.split(':')[0];
},
sort: (a: IKernelItem, b: IKernelItem) =>
a.command.localeCompare(b.command)
});
}

const availableColumns: Table.IColumn<IKernelItem>[] = [
{
id: 'kernel',
Expand Down
8 changes: 8 additions & 0 deletions src/database.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IStateDB } from '@jupyterlab/statedb';
import { ReadonlyPartialJSONValue, PromiseDelegate } from '@lumino/coreutils';
import { Signal } from '@lumino/signaling';
import { ILauncher } from '@jupyterlab/launcher';
import {
ILastUsedDatabase,
Expand Down Expand Up @@ -94,7 +95,14 @@ export class FavoritesDatabase

async set(item: ILauncher.IItemOptions, isFavourite: boolean) {
this._set(item, isFavourite);
this._changed.emit();
}

get changed() {
return this._changed;
}

private _changed = new Signal<FavoritesDatabase, void>(this);
}

/**
Expand Down
75 changes: 70 additions & 5 deletions src/launcher.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Nebari Development Team.
// Distributed under the terms of the Modified BSD License.
import type { CommandRegistry } from '@lumino/commands';
import type { ISignal } from '@lumino/signaling';
import { ISettingRegistry } from '@jupyterlab/settingregistry';
import { ILauncher, Launcher } from '@jupyterlab/launcher';
import { TranslationBundle } from '@jupyterlab/translation';
Expand All @@ -14,9 +15,10 @@ import {
IItem,
IKernelItem,
ILastUsedDatabase,
IFavoritesDatabase
IFavoritesDatabase,
ISettingsLayout
} from './types';
import { fileIcon } from './icons';
import { fileIcon, starIcon } from './icons';
import { Item } from './item';
import { KernelTable } from './components/table';
import { CollapsibleSection } from './components/section';
Expand All @@ -31,9 +33,44 @@ function LauncherBody(props: {
otherItems: IItem[];
commands: CommandRegistry;
settings: ISettingRegistry.ISettings;
favouritesChanged?: ISignal<IFavoritesDatabase, void>;
}): React.ReactElement {
const { trans, cwd, typeItems, otherItems } = props;
const { trans, cwd, typeItems, otherItems, favouritesChanged } = props;
const [query, updateQuery] = React.useState<string>('');
const [, forceUpdate] = React.useReducer(x => x + 1, 0);
const [showStarred, updateShowStarred] = React.useState<
ISettingsLayout['starredSection']
>(
props.settings.composite.starredSection as ISettingsLayout['starredSection']
);

const syncSettings = () => {
updateShowStarred(
props.settings.composite
.starredSection as ISettingsLayout['starredSection']
);
};

React.useEffect(() => {
props.settings.changed.connect(syncSettings);
return () => {
props.settings.changed.disconnect(syncSettings);
};
});

if (favouritesChanged) {
const updateIfNeeded = () => {
if (showStarred) {
forceUpdate();
}
};
React.useEffect(() => {
favouritesChanged.connect(updateIfNeeded);
return () => {
favouritesChanged.disconnect(updateIfNeeded);
};
});
}

const metadataAvailable = new Set<string>();
for (const item of props.notebookItems) {
Expand All @@ -46,6 +83,10 @@ function LauncherBody(props: {
}
}

const starred = [...props.notebookItems, ...props.consoleItems].filter(
item => item.starred
);

return (
<div className="jp-LauncherBody">
<div className="jp-NewLauncher-TopBar">
Expand Down Expand Up @@ -86,8 +127,31 @@ function LauncherBody(props: {
<TypeCard item={item} trans={trans} />
))}
</CollapsibleSection>
{showStarred ? (
<CollapsibleSection
className="jp-Launcher-openByKernel"
title={trans.__('Starred')}
icon={starIcon}
open={true} // TODO: store this in layout/state higher up
>
{starred.length > 0 ? (
<KernelTable
items={starred}
commands={props.commands}
showSearchBox={false}
showWidgetType={true}
query={query}
settings={props.settings}
trans={trans}
onClick={item => item.execute()}
/>
) : (
'No starred items'
)}
</CollapsibleSection>
) : null}
<CollapsibleSection
className="jp-Launcher-openByKernel"
className="jp-Launcher-openByKernel jp-Launcher-launchNotebook"
title={trans.__('Launch Notebook')}
icon={notebookIcon}
open={true} // TODO: store this in layout/state higher up
Expand All @@ -103,7 +167,7 @@ function LauncherBody(props: {
/>
</CollapsibleSection>
<CollapsibleSection
className="jp-Launcher-openByKernel"
className="jp-Launcher-openByKernel jp-Launcher-launchConsole"
title={trans.__('Launch Console')}
icon={consoleIcon}
open={false}
Expand Down Expand Up @@ -229,6 +293,7 @@ export class NewLauncher extends Launcher {
consoleItems={consoleItems}
otherItems={otherItems}
settings={this._settings}
favouritesChanged={this._favoritesDatabase.changed}
/>
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export namespace CommandIDs {
export interface ISettingsLayout {
hiddenColumns: Record<string, 'visible' | 'hidden'>;
columnOrder: string[];
starredSection: boolean;
}

export interface IItem extends ILauncher.IItemOptions {
Expand Down Expand Up @@ -47,6 +48,7 @@ export interface IFavoritesDatabase {
ready: Promise<void>;
get(item: ILauncher.IItemOptions): boolean | null;
set(item: ILauncher.IItemOptions, isFavourite: boolean): Promise<void>;
changed: ISignal<IFavoritesDatabase, void>;
}

/**
Expand Down
9 changes: 9 additions & 0 deletions style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,19 @@
}

.jp-Launcher-searchBox input {
/* (no longer needed in lab 4.2+) */
box-shadow: none;
}

.jp-Launcher-searchBox input,
.jp-Launcher-searchBox jp-search::part(root) {
border: var(--jp-border-width) solid var(--jp-border-color1);
}

.jp-Launcher-searchBox .jp-FilterBox {
width: 100%;
}

.jp-CollapsibleSection > summary {
cursor: pointer;
transition: margin var(--jp-animation-time) ease-out;
Expand Down
38 changes: 34 additions & 4 deletions ui-tests/tests/jupyterlab_new_launcher.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
import { expect, test } from '@jupyterlab/galata';
import { expect, test, galata } from '@jupyterlab/galata';

test('should render new launcher', async ({ page }) => {
const launcher = page.locator('.jp-LauncherBody');
expect(await launcher.screenshot()).toMatchSnapshot('launcher.png');
const SETTINGS_ID = 'jupyterlab-new-launcher:plugin';

test.describe('Default settings', () => {
test('should render new launcher', async ({ page }) => {
const launcher = page.locator('.jp-LauncherBody');
expect(await launcher.screenshot()).toMatchSnapshot('launcher.png');
});
});

test.describe('With starred section', () => {
test.use({
mockSettings: {
...galata.DEFAULT_SETTINGS,
[SETTINGS_ID]: {
...galata.DEFAULT_SETTINGS[SETTINGS_ID],
starredSection: true
}
}
});

test('should render new launcher with starred section', async ({ page }) => {
const launcher = page.locator('.jp-LauncherBody');
// expand the console section
await page.locator('.jp-Launcher-launchConsole summary').click();
// star some items
await page
.locator('.jp-Launcher-launchNotebook .jp-starIconButton')
.click();
await page.locator('.jp-Launcher-launchConsole .jp-starIconButton').click();
expect(await launcher.screenshot()).toMatchSnapshot(

Check failure on line 32 in ui-tests/tests/jupyterlab_new_launcher.spec.ts

View workflow job for this annotation

GitHub Actions / Integration tests

tests/jupyterlab_new_launcher.spec.ts:23:7 › With starred section › should render new launcher with starred section

1) tests/jupyterlab_new_launcher.spec.ts:23:7 › With starred section › should render new launcher with starred section Error: Screenshot comparison failed: 25163 pixels (ratio 0.06 of all image pixels) are different. Expected: /home/runner/work/jupyterlab-new-launcher/jupyterlab-new-launcher/ui-tests/tests/jupyterlab_new_launcher.spec.ts-snapshots/launcher-with-starred-linux.png Received: /home/runner/work/jupyterlab-new-launcher/jupyterlab-new-launcher/ui-tests/test-results/tests-jupyterlab_new_launc-99976-uncher-with-starred-section/launcher-with-starred-actual.png Diff: /home/runner/work/jupyterlab-new-launcher/jupyterlab-new-launcher/ui-tests/test-results/tests-jupyterlab_new_launc-99976-uncher-with-starred-section/launcher-with-starred-diff.png 30 | .click(); 31 | await page.locator('.jp-Launcher-launchConsole .jp-starIconButton').click(); > 32 | expect(await launcher.screenshot()).toMatchSnapshot( | ^ 33 | 'launcher-with-starred.png' 34 | ); 35 | }); at /home/runner/work/jupyterlab-new-launcher/jupyterlab-new-launcher/ui-tests/tests/jupyterlab_new_launcher.spec.ts:32:41
'launcher-with-starred.png'
);
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit f35b769

Please sign in to comment.