diff --git a/packages/docprovider-extension/src/filebrowser.ts b/packages/docprovider-extension/src/filebrowser.ts index bcea4f9a..d68ecd90 100644 --- a/packages/docprovider-extension/src/filebrowser.ts +++ b/packages/docprovider-extension/src/filebrowser.ts @@ -158,35 +158,37 @@ export const statusBarTimeline: JupyterFrontEndPlugin = { documentPath: string, documentId: string ) => { - if (drive) { - // Remove 'RTC:' from document path - documentPath = documentPath.slice(drive.name.length + 1); - // Dispose of the previous timelineWidget if it exists - if (timelineWidget) { - timelineWidget.dispose(); - timelineWidget = null; - } + if (documentId && documentPath.split(':')[0] === 'RTC') { + if (drive) { + // Remove 'RTC:' from document path + documentPath = documentPath.slice(drive.name.length + 1); + // Dispose of the previous timelineWidget if it exists + if (timelineWidget) { + timelineWidget.dispose(); + timelineWidget = null; + } - const [format, type] = documentId.split(':'); - const provider = drive.providers.get( - `${format}:${type}:${documentPath}` - ) as unknown as IForkProvider; - const fullPath = URLExt.join( - app.serviceManager.serverSettings.baseUrl, - DOCUMENT_TIMELINE_URL, - documentPath - ); + const [format, type] = documentId.split(':'); + const provider = drive.providers.get( + `${format}:${type}:${documentPath}` + ) as unknown as IForkProvider; + const fullPath = URLExt.join( + app.serviceManager.serverSettings.baseUrl, + DOCUMENT_TIMELINE_URL, + documentPath + ); - timelineWidget = new TimelineWidget( - fullPath, - provider, - provider.contentType, - provider.format - ); + timelineWidget = new TimelineWidget( + fullPath, + provider, + provider.contentType, + provider.format + ); - const elt = document.getElementById('jp-slider-status-bar'); - if (elt && !timelineWidget.isAttached) { - Widget.attach(timelineWidget, elt); + const elt = document.getElementById('jp-slider-status-bar'); + if (elt && !timelineWidget.isAttached) { + Widget.attach(timelineWidget, elt); + } } } }; @@ -222,8 +224,22 @@ export const statusBarTimeline: JupyterFrontEndPlugin = { align: 'left', rank: 4, isActive: () => { - const currentWidget = app.shell.currentWidget; - return !!currentWidget && 'context' in currentWidget; + const currentWidget = app.shell + .currentWidget as DocumentWidget | null; + + if ( + currentWidget && + currentWidget.context && + typeof currentWidget.context.path === 'string' + ) { + const documentPath = currentWidget.context.path; + const documentId = + currentWidget.context.model.sharedModel.getState( + 'document_id' + ) as string; + return !!documentId && documentPath.split(':')[0] === 'RTC'; + } + return false; } }); } diff --git a/ui-tests/tests/timeline-slider.spec.ts b/ui-tests/tests/timeline-slider.spec.ts new file mode 100644 index 00000000..4a052787 --- /dev/null +++ b/ui-tests/tests/timeline-slider.spec.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) Jupyter Development Team. + * Distributed under the terms of the Modified BSD License. + */ + +import { expect, test } from '@jupyterlab/galata'; +import { Page } from '@playwright/test'; + +async function capturePageErrors(page: Page) { + const pageErrors: string[] = []; + page.on('pageerror', (error) => pageErrors.push(error.message)); + return pageErrors; +} + +async function openNotebook(page: Page, notebookPath: string) { + await page.click('text=File'); + await page.click('.lm-Menu-itemLabel:text("Open from Path…")'); + await page.fill( + 'input[placeholder="/path/relative/to/jlab/root"]', + notebookPath + ); + await page.click('.jp-Dialog-buttonLabel:text("Open")'); + await page.waitForSelector('.jp-Notebook', { state: 'visible' }); +} + +test.describe('Open from Path', () => { + + test('should fail if there are console errors', async ({ page, tmpPath }) => { + const pageErrors = await capturePageErrors(page); + + await page.notebook.createNew(); + await page.notebook.save(); + await page.notebook.close(); + + await openNotebook(page, `${tmpPath}/Untitled.ipynb`); + + expect(pageErrors).toHaveLength(0); + }); +});