Skip to content

Commit 3b5d9cc

Browse files
Rework leave confirmation dialogue to use "save/leave" text in buttons and add a cancel button (#233)
* Change text in buttons * Add styles * Update tests * Fix strict mode violation for button selection * Update Playwright Snapshots * Add padding only for leave dialogue, not others * Override Jupyter colours for "X" button SVG Co-authored-by: Michał Krassowski <[email protected]> * Subclass `Dialog` into `LeaveDialog` and add a container * Update src/ui-components/LeaveConfirmation.tsx Co-authored-by: Michał Krassowski <[email protected]> --------- Co-authored-by: Michał Krassowski <[email protected]>
1 parent ac32016 commit 3b5d9cc

File tree

5 files changed

+67
-10
lines changed

5 files changed

+67
-10
lines changed

src/sidebar.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { TabBar, Widget } from '@lumino/widgets';
22
import { ILabShell, JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application';
3-
import { Dialog, showDialog } from '@jupyterlab/apputils';
3+
import { Dialog } from '@jupyterlab/apputils';
44

55
import { SidebarIcon } from './ui-components/SidebarIcon';
66
import { EverywhereIcons } from './icons';
7-
import { LEAVE_CONFIRMATION_TITLE, LeaveConfirmation } from './ui-components/LeaveConfirmation';
7+
import {
8+
LEAVE_CONFIRMATION_TITLE,
9+
LeaveConfirmation,
10+
LeaveDialog
11+
} from './ui-components/LeaveConfirmation';
812
import { Commands } from './commands';
913

1014
import { INotebookTracker } from '@jupyterlab/notebook';
@@ -87,17 +91,32 @@ export const customSidebar: JupyterFrontEndPlugin<void> = {
8791
}
8892

8993
// Non-empty regular notebook -> confirm and optionally save/share
90-
const result = await showDialog({
94+
const dialog = new LeaveDialog({
9195
title: LEAVE_CONFIRMATION_TITLE,
9296
body: new LeaveConfirmation(),
97+
hasClose: true,
9398
buttons: [
94-
Dialog.cancelButton({ label: 'Cancel' }),
95-
Dialog.okButton({ label: 'Yes' })
99+
Dialog.createButton({
100+
label: "Don't save and leave",
101+
accept: true,
102+
actions: ['leave-nosave']
103+
}),
104+
Dialog.okButton({
105+
label: 'Save and leave',
106+
actions: ['leave-save']
107+
})
96108
],
97-
defaultButton: 0
109+
defaultButton: 1
98110
});
99111

100-
if (result.button.label === 'Yes') {
112+
const result = await dialog.launch();
113+
const actions = result.button.actions ?? [];
114+
115+
if (actions.includes('leave-nosave')) {
116+
window.location.href = '/index.html';
117+
return;
118+
}
119+
if (actions.includes('leave-save')) {
101120
try {
102121
await app.commands.execute(Commands.shareNotebookCommand);
103122
} catch (error) {

src/ui-components/LeaveConfirmation.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ReactWidget } from '@jupyterlab/apputils';
1+
import { Dialog, ReactWidget } from '@jupyterlab/apputils';
22
import React from 'react';
33

44
export const LEAVE_CONFIRMATION_TITLE =
@@ -26,3 +26,20 @@ export class LeaveConfirmation extends ReactWidget {
2626
);
2727
}
2828
}
29+
30+
/**
31+
* A dialog with a "close" button in the top-right corner, currently here
32+
* because we only use hasClose in the leave confirmation dialog.
33+
*/
34+
export class LeaveDialog extends Dialog<void> {
35+
constructor(
36+
options: Partial<Dialog.IOptions<void>> & Pick<Dialog.IOptions<void>, 'title' | 'body'>
37+
) {
38+
const normalized: Partial<Dialog.IOptions<void>> = {
39+
host: document.body,
40+
...options
41+
};
42+
super(normalized);
43+
this.addClass('je-LeaveDialog-container');
44+
}
45+
}

style/base.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868

6969
.jp-Dialog-footerButtons {
7070
text-align: center;
71+
cursor: pointer;
7172
}
7273

7374
.jp-Dialog {
@@ -86,6 +87,7 @@
8687
font-style: normal;
8788
font-weight: 500;
8889
line-height: 150%;
90+
cursor: pointer;
8991
}
9092

9193
.jp-Dialog-header {
@@ -360,3 +362,22 @@ consistent with code cells */
360362
.je-LeaveDialog.jp-Dialog-body {
361363
order: 2;
362364
}
365+
366+
/* we reserve space for the close button */
367+
@supports selector(:has(*)) {
368+
.jp-Dialog-content:has(> .je-LeaveDialog.jp-Dialog-body) > .jp-Dialog-header {
369+
padding-right: 28px;
370+
}
371+
}
372+
373+
.jp-Dialog.je-LeaveDialog-container .jp-Dialog-close-button,
374+
.jp-Dialog-content.je-LeaveDialog-container .jp-Dialog-close-button {
375+
position: absolute;
376+
top: -16px;
377+
right: -8px;
378+
transform: scale(calc(var(--je-scale) * 1.5));
379+
}
380+
381+
.jp-Dialog .jp-Dialog-close-button .jp-Icon {
382+
--jp-inverse-layout-color3: var(--je-slate-blue);
383+
}

ui-tests/tests/jupytereverywhere.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ test.describe('Leave confirmation', () => {
622622
const dialog = page.locator('.jp-Dialog');
623623
await expect(dialog).toBeVisible();
624624

625-
await dialog.getByRole('button', { name: 'Cancel' }).click();
625+
await dialog.locator('.jp-Dialog-close-button').click();
626626

627627
await expect(page.locator('.jp-NotebookPanel')).toBeVisible();
628628
await expect(dialog).toHaveCount(0);
@@ -644,7 +644,7 @@ test.describe('Leave confirmation', () => {
644644
const dialog = page.locator('.jp-Dialog');
645645
await expect(dialog).toBeVisible();
646646

647-
await dialog.getByRole('button', { name: 'Yes' }).click();
647+
await dialog.getByRole('button', { name: 'Save and leave', exact: true }).click();
648648

649649
const shareDialog = page.locator('.jp-Dialog-content');
650650
await expect(shareDialog).toBeVisible();
3.43 KB
Loading

0 commit comments

Comments
 (0)