Change:
Since we open release notes (by default) on each release, there should be a visible way to opt-out. Either a checkbox similar to the Welcome experience, or a markdown command link. re:
I think having a setting to toggle this would be best. The release notes is just a markdown preview so we can't add any UI elements to it, unlike the Welcome page which is different.
We do have a setting already , but we have LOTS of settings. Even though it is markdown, we could still add a command link to the text that would run a new command to toggle the setting.
I don't know, this seems pretty obvious: !
Its friction -- if the release notes pops up and aggravates me, I have to take much extra energy to go looking for the setting (even though it is an easy one to find)
I could see maybe adding a menu item in the ... in the top right, but doubt that is discoverable. Placing it inside of the preview feels a bit odd like an unsubscribe link.
On the constrain of adding UI to the notes: The relnotes manager output already has a patch that runs to and handles . Might the same be used to inject an opt-out checkbox or link inside the header? A common UX to test would be a "Don't show again" link/button we have in notifications (and elsewhere?).
One heuristic could be that if we see the release notes are closed within 5 seconds of them opening, we show a notification asking the user whether they want to see them in the future. The downside is that it trades release note fatigue for notification fatigue
I totally agree. Just not sure of the right UX here.
Here a few different ideas: ! ! This would take some engineering effort as it's not easily supported in plain markdown, but placing a small navigation bar at the bottom so that it's always visible. Downside is if you want to see the release notes it's annoying to see !
I like the checkbox since it's a pretty standard way of doing this... Maybe at the top (2) is best?
When lands, a wording could be "Show release notes for monthly updates." to indicate the monthly frequency to set expectations.
I prefer # 2
Another tweet about this: I prefer because it aligns with how we show the checkbox for the welcome page too.
I prefer # 3 too because it does not interrupt the flow for people reading the release notes Another possible wording based on 's could be "Show release notes for major updates"
Currently is of "application" scope (), meaning that I cannot set it to "false" in section of a file. Can it be scope? It's slightly different from the original topic. Let me know if you want me to open a separate issue for it.
!
Do we want to show it at the top so prominently? Feels like it breaks the layout and we would like users at least glancing at the release notes.
IMO it should at least be under the or under the first paragraph. Agreed that it feels like it breaks the layout.
!
This looks better to me. Thanks

Discussion:
import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; <del> import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; </del> <ins> import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration'; </ins> import { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; <ins> import { DisposableStore } from 'vs/base/common/lifecycle'; </ins> export class ReleaseNotesManager {

private _currentReleaseNotes: WebviewInput | undefined = undefined; private _lastText: string | undefined; <ins> private disposables = new DisposableStore(); </ins> public constructor( @IEnvironmentService private readonly _environmentService: IEnvironmentService,

this._currentReleaseNotes.webview.html = html; } }); <ins> _configurationService.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables); _webviewWorkbenchService.onDidChangeActiveWebviewEditor(this.onDidChangeActiveWebviewEditor, this, this.disposables); </ins> } public async show(version: string): Promise<boolean> {

enableFindWidget: true, }, contentOptions: { <del> localResourceRoots: [] </del> <ins> localResourceRoots: [], allowScripts: true </ins> }, extension: undefined },

{ group: ACTIVE_GROUP, preserveFocus: false }); this._currentReleaseNotes.webview.onDidClickLink(uri => this.onDidClickLink(URI.parse(uri))); <del> this._currentReleaseNotes.onWillDispose(() => { this._currentReleaseNotes = undefined; }); </del> <ins> const disposables = new DisposableStore(); disposables.add(this._currentReleaseNotes.webview.onMessage(e => { if (e.message.type === 'showReleaseNotes') { this._configurationService.updateValue('update.showReleaseNotes', e.message.value); } })); disposables.add(this._currentReleaseNotes.onWillDispose(() => { disposables.dispose(); this._currentReleaseNotes = undefined; })); </ins> this._currentReleaseNotes.webview.html = html; }

const content = await renderMarkdownDocument(text, this._extensionService, this._languageService, false); const colorMap = TokenizationRegistry.getColorMap(); const css = colorMap ? generateTokensCSSForColorMap(colorMap) : ''; <ins> const showReleaseNotes = this._configurationService.getValue<boolean>('update.showReleaseNotes'); </ins> return `<!DOCTYPE html> <html> <head> <base href="https://code.visualstudio.com/raw/"> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> <del> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; style-src 'nonce-${nonce}' https://code.visualstudio.com;"> </del> <ins> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src https: data:; media-src https:; style-src 'nonce-${nonce}' https://code.visualstudio.com; script-src 'nonce-${nonce}';"> </ins> <style nonce="${nonce}"> ${DEFAULT_MARKDOWN_STYLES} ${css} <ins> header { display: flex; align-items: center; padding-top: 1em; } </ins> </style> </head> <del> <body>${content}</body> </del> <ins> <body> <header> <input type="checkbox" id="showReleaseNotes" ${showReleaseNotes ? 'checked' : ''}> <label for="showReleaseNotes">${nls.localize('showOnUpdate', "Show release notes after an update")}</label> </header> ${content} <script nonce="${nonce}"> const vscode = acquireVsCodeApi(); const checkbox = document.getElementById('showReleaseNotes'); window.addEventListener('message', event => { if (event.data.type === 'showReleaseNotes') { checkbox.checked = event.data.value; } }); checkbox.addEventListener('change', event => { vscode.postMessage({ type: 'showReleaseNotes', value: checkbox.checked }, '*'); }); </script> </body> </ins> </html>`; } <ins> private onDidChangeConfiguration(e: IConfigurationChangeEvent): void { if (e.affectsConfiguration('update.showReleaseNotes')) { this.updateWebview(); } } private onDidChangeActiveWebviewEditor(input: WebviewInput | undefined): void { if (input && input === this._currentReleaseNotes) { this.updateWebview(); } } private updateWebview() { if (this._currentReleaseNotes) { this._currentReleaseNotes.webview.postMessage({ type: 'showReleaseNotes', value: this._configurationService.getValue<boolean>('update.showReleaseNotes') }); } } </ins> }