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

Read only status notification on ctrl+s #15317

Merged

Conversation

andrewfulton9
Copy link
Contributor

References

adds feature described in #15046

depends on lumino #644 to function

Code changes

Uses contextual information passed from lumino commands _executeKeyBinding via args to modify execution if the save is called from a keybinding to raise a notification notifying a user that the file is read-only and can't be saved

User-facing changes

If a user trys to save read-only document with the keybinding "ctr+s", a notification will briefly pop up notifying them that the document is read-only and cannot be saved.

read-only.notification.mp4

Backwards-incompatible changes

None that I am aware

@jupyterlab-probot
Copy link

Thanks for making a pull request to jupyterlab!
To try out this branch on binder, follow this link: Binder

@krassowski
Copy link
Member

Kicking CI which failed due to npm outage: https://status.npmjs.org/incidents/zdznxkrp22py

@krassowski krassowski closed this Oct 30, 2023
@krassowski krassowski reopened this Oct 30, 2023
Copy link
Member

@krassowski krassowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you look at how hard adding an integration test would be here? I does not need to include a snapshot as there is a dedicated page.notifications galata helper which could be used, as in:

test('Announcements requires user agreement', async ({ page }) => {
const notifications = await page.notifications;
expect(notifications).toHaveLength(1);
expect(notifications[0].message).toEqual(
'Would you like to receive official Jupyter news?\nPlease read the privacy policy.'
);
expect(notifications[0].options.actions).toHaveLength(3);
expect(notifications[0].options.actions[0].label).toEqual(
'Open privacy policy'
);
});

packages/docmanager-extension/src/index.tsx Outdated Show resolved Hide resolved
@andrewfulton9
Copy link
Contributor Author

Could you look at how hard adding an integration test would be here? I does not need to include a snapshot as there is a dedicated page.notifications galata helper which could be used, as in:

test('Announcements requires user agreement', async ({ page }) => {
const notifications = await page.notifications;
expect(notifications).toHaveLength(1);
expect(notifications[0].message).toEqual(
'Would you like to receive official Jupyter news?\nPlease read the privacy policy.'
);
expect(notifications[0].options.actions).toHaveLength(3);
expect(notifications[0].options.actions[0].label).toEqual(
'Open privacy policy'
);
});

@krassowski, I'm a little lost trying to figure out how to make a test notebook read only. Do you have any suggestions on how I should do this?

@krassowski
Copy link
Member

Good question. I think you that setting immutable attribute could work on CI but this would annoy anyone running tests locally as it would require a manual/OS-specific step before running the test. Probably the best option would be adding a mock that forces the "writable" attribute to false. You can follow the existing mocks such as freezeContentLastModified:

export async function freezeContentLastModified(page: Page): Promise<void> {
// Listen for closing connection (may happen when request are still being processed)
let isClosed = false;
const ctxt = page.context();
ctxt.once('close', () => {
isClosed = true;
});
ctxt.browser()?.once('disconnected', () => {
isClosed = true;
});
return page.route(Routes.contents, async (route, request) => {
switch (request.method()) {
case 'GET': {
// Proxy the GET request
const response = await ctxt.request.fetch(request);
if (!response.ok()) {
if (!page.isClosed() && !isClosed) {
return route.fulfill({
status: response.status(),
body: await response.text()
});
}
break;
}
const data = await response.json();
// Modify the last_modified values to be set one day before now.
if (
data['type'] === 'directory' &&
Array.isArray(data['content'])
) {
const now = Date.now();
const aDayAgo = new Date(now - 24 * 3600 * 1000).toISOString();
for (const entry of data['content'] as any[]) {
// Mutate the list in-place
entry['last_modified'] = aDayAgo;
}
}
if (!page.isClosed() && !isClosed) {
return route.fulfill({
status: 200,
body: JSON.stringify(data),
contentType: 'application/json'
});
}
break;
}
default:
return route.continue();
}
});
}

Copy link
Member

@krassowski krassowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test looks good, thank you! Two suggestions/questions on:

  • showing just file name not path
  • throwing an error if command gets executed when it should not be.

galata/src/galata.ts Outdated Show resolved Hide resolved
galata/test/jupyterlab/readonly.test.ts Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it just show the base name? Or is showing the full path valuable here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see it as being a tradeoff between full path being more explicit vs just the file name potentially being more tidy. Personally I would lean towards the more explicit option. You probably have a better understanding of JLab users though, so I'm happy to defer to your opinion. It's also worth noting that the same function and input are being used for the notification for the save-all and save commands though. I could see the full path being better for the save-all notification even if we update the save notification to just use the base name.

packages/docmanager-extension/src/index.tsx Show resolved Hide resolved
andrewfulton9 and others added 2 commits November 15, 2023 14:53
Co-authored-by: Michał Krassowski <5832902+krassowski@users.noreply.github.com>
Copy link
Member

@krassowski krassowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants