Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests for short relative date #81

Open
wants to merge 22 commits into
base: short-relative-date
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b57e54e
Revert "Alternate description for disabled filters"
JasonWeill Feb 23, 2024
576d186
Revert "Revert "Alternate description for disabled filters""
JasonWeill Mar 6, 2024
69b2933
Uses extremely short units, shrinks the Last Modified column by 62 px
JasonWeill Mar 8, 2024
210ef07
Lint fixes
JasonWeill Mar 8, 2024
4ffb112
Uses standard library in 'narrow' mode
JasonWeill Mar 13, 2024
65ad6bf
Three-step container query to display longer or shorter date
JasonWeill Mar 13, 2024
cbedc96
Update Playwright Snapshots
github-actions[bot] Mar 18, 2024
2435bed
Update Playwright Snapshots
github-actions[bot] Mar 19, 2024
67da58e
WIP: Creates test files
JasonWeill Mar 20, 2024
3819e71
Adds small and large sidebar tests specifically for filebrowser
JasonWeill Mar 20, 2024
f81916e
Adds medium sidebar test for filebrowser
JasonWeill Mar 20, 2024
ea544ba
Fix loop issue
JasonWeill Mar 20, 2024
f6b230c
Update comment
JasonWeill Mar 21, 2024
f0b923a
Update Playwright Snapshots
github-actions[bot] Mar 21, 2024
915ccc3
Reinstates previous screen shots not modified by this change
JasonWeill Mar 21, 2024
01ead6c
Freezes dates at one day ago
JasonWeill Mar 21, 2024
c1eedf5
Disable stylelint for container queries
JasonWeill Mar 21, 2024
7accff5
Avoid using page in beforeAll
JasonWeill Mar 21, 2024
202669c
Uploads files with time stamp override in a separate test pass
JasonWeill Mar 21, 2024
15deb0f
Reverts screen shots not modified by this change
JasonWeill Mar 22, 2024
dd5fc1c
Reverts tests so I can put them into another branch
JasonWeill Mar 22, 2024
c41ca55
Revert "Reverts tests so I can put them into another branch"
JasonWeill Mar 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,15 @@
"id": "application:toggle-side-tabbar",
"label": "Show Left Activity Bar",
"caption": "",
"shortcuts": [
"Alt 1"
]
"shortcuts": []
},
{
"id": "application:toggle-sidebar-widget",
"label": "Toggle Sidebar Element",
"caption": "",
"shortcuts": []
"shortcuts": [
"Alt 1"
]
},
{
"id": "apputils:activate-command-palette",
Expand Down Expand Up @@ -367,6 +367,12 @@
"caption": "",
"shortcuts": []
},
{
"id": "console:redo",
"label": "Redo",
"caption": "",
"shortcuts": []
},
{
"id": "console:replace-selection",
"label": "Replace Selection in Console",
Expand Down Expand Up @@ -413,6 +419,12 @@
"caption": "",
"shortcuts": []
},
{
"id": "console:undo",
"label": "Undo",
"caption": "",
"shortcuts": []
},
{
"id": "csv:go-to-line",
"label": "Go to Line",
Expand Down
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.
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.
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.
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.
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.
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.
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.
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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 61 additions & 2 deletions galata/test/jupyterlab/sidebars.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import { expect, galata, Handle, test } from '@jupyterlab/galata';
import { expect, galata, test } from '@jupyterlab/galata';

import { Locator } from '@playwright/test';

import * as path from 'path';

const sidebarIds: galata.SidebarTabId[] = [
'filebrowser',
'jp-property-inspector',
Expand All @@ -12,6 +15,16 @@ const sidebarIds: galata.SidebarTabId[] = [
'extensionmanager.main-view'
];

const testFileName = 'simple.md';
const testNotebook = 'simple_notebook.ipynb';
const testFolderName = 'test-folder';

const sidebarWidths = {
small: 226,
medium: 308,
large: 371
};

/**
* Add provided text as label on first tab in given tabbar.
* By default we only have icons, but we should test for the
Expand All @@ -26,6 +39,10 @@ async function mockLabelOnFirstTab(tabbar: Locator, text: string) {
}, text);
}

test.use({
tmpPath: 'test-sidebars'
});

test.describe('Sidebars', () => {
sidebarIds.forEach(sidebarId => {
test(`Open Sidebar tab ${sidebarId}`, async ({ page }) => {
Expand Down Expand Up @@ -61,7 +78,6 @@ test.describe('Sidebars', () => {
await page.notebook.createNew('notebook.ipynb');

const unusedRules = await page.style.findUnusedStyleRules({
page,
fragments: ['jp-DirListing', 'jp-FileBrowser'],
exclude: [
// active during renaming
Expand Down Expand Up @@ -199,3 +215,46 @@ test.describe('Sidebars', () => {
expect(tableOfContentsElementRole).toEqual('region');
});
});

test.describe('Sidebar filebrowser', () => {
test.beforeEach(async ({ page, request, tmpPath }) => {
const contents = galata.newContentsHelper(request);
// Make each of these files a day old, so they show as 1 day old in the browser.
await galata.Mock.freezeContentLastModified(page);

// Create some dummy content
await contents.uploadFile(
path.resolve(__dirname, `./notebooks/${testNotebook}`),
`${tmpPath}/${testNotebook}`
);
await contents.uploadFile(
path.resolve(__dirname, `./notebooks/${testFileName}`),
`${tmpPath}/${testFileName}`
);
// Create a dummy folder
await contents.createDirectory(`${tmpPath}/${testFolderName}`);
});

test.afterEach(async ({ request, tmpPath }) => {
// Clean up the test files
const contents = galata.newContentsHelper(request);
await contents.deleteDirectory(tmpPath);
});

// Additional test cases for resized widths of the file browser
for (const [sizeName, size] of Object.entries(sidebarWidths)) {
test(`size ${sizeName}`, async ({ page }) => {
await page.sidebar.openTab('filebrowser');
// Resize the sidebar to the desired width.
await page.sidebar.setWidth(size, 'left');
const imageName = `opened-sidebar-filebrowser-${sizeName}.png`;
const position = await page.sidebar.getTabPosition('filebrowser');
const sidebar = page.sidebar.getContentPanelLocator(
position ?? undefined
);
expect(await sidebar.screenshot()).toMatchSnapshot(
imageName.toLowerCase()
);
});
}
});
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.
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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 11 additions & 2 deletions packages/coreutils/src/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,25 @@ const UNITS: { name: Intl.RelativeTimeFormatUnit; milliseconds: number }[] = [
* The namespace for date functions.
*/
export namespace Time {
// Intl.RelativeTimeFormatStyle contains these, but we can't compile with it yet
export type HumanStyle = 'long' | 'short' | 'narrow';

/**
* Convert a timestring to a human readable string (e.g. 'two minutes ago').
*
* @param value - The date timestring or date object.
*
* @returns A formatted date.
*/
export function formatHuman(value: string | Date): string {
export function formatHuman(
value: string | Date,
format: HumanStyle = 'long'
): string {
const lang = document.documentElement.lang || 'en';
const formatter = new Intl.RelativeTimeFormat(lang, { numeric: 'auto' });
const formatter = new Intl.RelativeTimeFormat(lang, {
numeric: 'auto',
style: format
});
const delta = new Date(value).getTime() - Date.now();
for (let unit of UNITS) {
const amount = Math.ceil(delta / unit.milliseconds);
Expand Down
24 changes: 19 additions & 5 deletions packages/filebrowser/src/listing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2297,7 +2297,7 @@ export namespace DirListing {
const trans = translator.load('jupyterlab');
const name = this.createHeaderItemNode(trans.__('Name'));
const narrow = document.createElement('div');
const modified = this.createHeaderItemNode(trans.__('Last Modified'));
const modified = this.createHeaderItemNode(trans.__('Modified'));
const fileSize = this.createHeaderItemNode(trans.__('File Size'));
name.classList.add(NAME_ID_CLASS);
name.classList.add(SELECTED_CLASS);
Expand Down Expand Up @@ -2656,13 +2656,24 @@ export namespace DirListing {
checkbox.checked = selected ?? false;
}

let modText = '';
let modHTML = '';
let modTitle = '';
if (model.last_modified) {
modText = Time.formatHuman(new Date(model.last_modified));
// Provide multiple formats, with container queries used to display exactly one
modHTML = ['narrow', 'short', 'long']
.map(
style =>
`<div class='${ITEM_MODIFIED_CLASS}-${style}'>` +
Time.formatHuman(
new Date(model.last_modified),
style as Time.HumanStyle
) +
'</div>'
)
.join('');
modTitle = Time.format(new Date(model.last_modified));
}
modified.textContent = modText;
modified.innerHTML = modHTML;
modified.title = modTitle;
}

Expand Down Expand Up @@ -2732,14 +2743,17 @@ export namespace DirListing {
/**
* Create a node for a header item.
*/
protected createHeaderItemNode(label: string): HTMLElement {
protected createHeaderItemNode(label: string, title?: string): HTMLElement {
const node = document.createElement('div');
const text = document.createElement('span');
const icon = document.createElement('span');
node.className = HEADER_ITEM_CLASS;
text.className = HEADER_ITEM_TEXT_CLASS;
icon.className = HEADER_ITEM_ICON_CLASS;
text.textContent = label;
if (title) {
text.title = title;
}
node.appendChild(text);
node.appendChild(icon);
return node;
Expand Down
64 changes: 60 additions & 4 deletions packages/filebrowser/style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@
}

.jp-DirListing-headerItem.jp-id-name {
flex: 1 0 84px;
flex: 1 1 126px;
}

.jp-DirListing-headerItem.jp-id-modified {
flex: 0 0 112px;
flex: 1 0 70px;
border-left: var(--jp-border-width) solid var(--jp-border-color2);
text-align: right;
}
Expand Down Expand Up @@ -269,7 +269,7 @@
}

.jp-DirListing-itemText {
flex: 1 0 64px;
flex: 1 1 106px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
Expand All @@ -293,9 +293,65 @@
outline: 0;
}

/* This file uses container queries, which are supported by all the
* browsers that JupyterLab works with, but which stylelint cannot
* validate.
*/

.jp-DirListing-itemModified {
flex: 0 0 125px;
flex: 1 0 83px;
text-align: right;
/* stylelint-disable */
container-type: inline-size;
/* stylelint-enable */
}

/* stylelint-disable */
@container (width < 90px) {
/* stylelint-enable */
.jp-DirListing-itemModified-narrow {
display: block;
}

.jp-DirListing-itemModified-short {
display: none;
}

.jp-DirListing-itemModified-long {
display: none;
}
}

/* stylelint-disable */
@container (width >= 90px) and (width <= 110px) {
/* stylelint-enable */
.jp-DirListing-itemModified-narrow {
display: none;
}

.jp-DirListing-itemModified-short {
display: block;
}

.jp-DirListing-itemModified-long {
display: none;
}
}

/* stylelint-disable */
@container (width > 110px) {
/* stylelint-enable */
.jp-DirListing-itemModified-narrow {
display: none;
}

.jp-DirListing-itemModified-short {
display: none;
}

.jp-DirListing-itemModified-long {
display: block;
}
}

.jp-DirListing-itemFileSize {
Expand Down
Loading