diff --git a/packages/application-extension/src/index.ts b/packages/application-extension/src/index.ts index d85a7911..8c439e7c 100644 --- a/packages/application-extension/src/index.ts +++ b/packages/application-extension/src/index.ts @@ -55,6 +55,11 @@ const EDITOR_FACTORY = 'Editor'; */ const TREE_PATTERN = new RegExp('/(notebooks|edit)/(.*)'); +/** + * A regular expression to suppress the file extension from display for .ipynb files. + */ +const STRIP_IPYNB = /\.ipynb$/; + /** * The command IDs used by the application plugin. */ @@ -383,7 +388,8 @@ const tabTitle: JupyterFrontEndPlugin = { const title = current.sessionContext.path || current.sessionContext.name; const basename = PathExt.basename(title); - document.title = basename; + // Strip the ".ipynb" suffix from filenames for display in tab titles. + document.title = basename.replace(STRIP_IPYNB, ''); }; current.sessionContext.sessionChanged.connect(update); update(); @@ -391,7 +397,7 @@ const tabTitle: JupyterFrontEndPlugin = { } else if (current instanceof DocumentWidget) { const update = () => { const basename = PathExt.basename(current.context.path); - document.title = basename; + document.title = basename.replace(STRIP_IPYNB, ''); }; current.context.pathChanged.connect(update); update(); @@ -435,7 +441,7 @@ const title: JupyterFrontEndPlugin = { } const h = document.createElement('h1'); - h.textContent = current.title.label; + h.textContent = current.title.label.replace(STRIP_IPYNB, ''); widget.node.appendChild(h); widget.node.style.marginLeft = '10px'; if (!docManager) { @@ -468,7 +474,8 @@ const title: JupyterFrontEndPlugin = { const newPath = current.context.path ?? result.path; const basename = PathExt.basename(newPath); - h.textContent = basename; + + h.textContent = basename.replace(STRIP_IPYNB, ''); if (!router) { return; } diff --git a/ui-tests/test/notebook.spec.ts b/ui-tests/test/notebook.spec.ts index 7028b72f..f99e4edc 100644 --- a/ui-tests/test/notebook.spec.ts +++ b/ui-tests/test/notebook.spec.ts @@ -34,11 +34,12 @@ test.describe('Notebook', () => { const notebook = `${tmpPath}/${NOTEBOOK}`; await page.goto(`notebooks/${notebook}`); - // Click on the title - await page.click('text="example.ipynb"'); + // Click on the title (with .ipynb extension stripped) + await page.click('text="example"'); // Rename in the input dialog const newName = 'test.ipynb'; + const newNameStripped = 'test'; await page.fill( `//div[normalize-space(.)='File Path${notebook}New Name']/input`, newName @@ -52,6 +53,6 @@ test.describe('Notebook', () => { // Check the URL contains the new name const url = page.url(); - expect(url).toContain(newName); + expect(url).toContain(newNameStripped); }); });