Skip to content

Commit 48ea82a

Browse files
committed
💄
1 parent 2af00d8 commit 48ea82a

File tree

2 files changed

+82
-110
lines changed

2 files changed

+82
-110
lines changed

src/extension.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { SettingsSync } from './settingsSync';
1212
import GitpodServer from './gitpodServer';
1313
import TelemetryReporter from './telemetryReporter';
1414
import { exportLogs } from './exportLogs';
15-
import { registerReleaseNotesView } from './releaseNotes';
15+
import { ReleaseNotes } from './releaseNotes';
1616
import { ExperimentalSettings } from './experiments';
1717

1818
const FIRST_INSTALL_KEY = 'gitpod-desktop.firstInstall';
@@ -24,6 +24,9 @@ export async function activate(context: vscode.ExtensionContext) {
2424
const extensionId = context.extension.id;
2525
const packageJSON = context.extension.packageJSON;
2626

27+
// sync between machines
28+
context.globalState.setKeysForSync([ReleaseNotes.RELEASE_NOTES_LAST_READ_KEY]);
29+
2730
const logger = new Log('Gitpod');
2831
logger.info(`${extensionId}/${packageJSON.version} (${os.release()} ${os.platform()} ${os.arch()}) vscode/${vscode.version} (${vscode.env.appName})`);
2932

@@ -59,12 +62,12 @@ export async function activate(context: vscode.ExtensionContext) {
5962
}
6063
}));
6164

65+
context.subscriptions.push(new ReleaseNotes(context));
66+
6267
if (!context.globalState.get<boolean>(FIRST_INSTALL_KEY, false)) {
6368
await context.globalState.update(FIRST_INSTALL_KEY, true);
6469
telemetry.sendTelemetryEvent('gitpod_desktop_installation', { kind: 'install' });
6570
}
66-
67-
registerReleaseNotesView(context);
6871
}
6972

7073
export async function deactivate() {

src/releaseNotes.ts

Lines changed: 76 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -7,74 +7,59 @@ import fetch, { Response } from 'node-fetch';
77
import * as vscode from 'vscode';
88
import { load } from 'js-yaml';
99
import { CacheHelper } from './common/cache';
10+
import { Disposable, disposeAll } from './common/dispose';
1011

11-
const LAST_READ_RELEASE_NOTES_ID = 'gitpod.lastReadReleaseNotesId';
12-
13-
export function registerReleaseNotesView(context: vscode.ExtensionContext) {
14-
const cacheHelper = new CacheHelper(context);
12+
export class ReleaseNotes extends Disposable {
13+
public static readonly viewType = 'gitpodReleaseNotes';
14+
public static readonly websiteHost = 'https://www.gitpod.io';
15+
public static readonly RELEASE_NOTES_LAST_READ_KEY = 'gitpod.lastReadReleaseNotesId';
1516

16-
async function shouldShowReleaseNotes(lastReadId: string | undefined) {
17-
const releaseId = await getLastPublish(cacheHelper);
18-
console.log(`gitpod release notes lastReadId: ${lastReadId}, latestReleaseId: ${releaseId}`);
19-
return releaseId !== lastReadId;
20-
}
17+
private panel: vscode.WebviewPanel | undefined;
18+
private panelDisposables: vscode.Disposable[] = [];
19+
private lastReadId: string | undefined;
20+
private cacheHelper = new CacheHelper(this.context);
2121

22-
context.subscriptions.push(
23-
vscode.commands.registerCommand('gitpod.showReleaseNotes', () => {
24-
ReleaseNotesPanel.createOrShow(context, cacheHelper);
25-
})
26-
);
22+
constructor(
23+
private readonly context: vscode.ExtensionContext,
24+
) {
25+
super();
2726

28-
// sync between machines
29-
context.globalState.setKeysForSync([LAST_READ_RELEASE_NOTES_ID]);
27+
this.lastReadId = this.context.globalState.get<string>(ReleaseNotes.RELEASE_NOTES_LAST_READ_KEY);
3028

31-
const lastReadId = context.globalState.get<string>(LAST_READ_RELEASE_NOTES_ID);
32-
shouldShowReleaseNotes(lastReadId).then(shouldShow => {
33-
if (shouldShow) {
34-
ReleaseNotesPanel.createOrShow(context, cacheHelper);
35-
}
36-
});
37-
}
29+
this._register(vscode.commands.registerCommand('gitpod.showReleaseNotes', () => this.createOrShow()));
3830

39-
function getResponseCacheTime(resp: Response) {
40-
const v = resp.headers.get('Cache-Control');
41-
if (!v) {
42-
return undefined;
31+
this.showIfNewRelease(this.lastReadId);
4332
}
44-
const t = /max-age=(\d+)/.exec(v);
45-
if (!t) {
46-
return undefined;
33+
34+
private async getLastPublish() {
35+
const url = `${ReleaseNotes.websiteHost}/changelog/latest`;
36+
return this.cacheHelper.getOrRefresh(url, async () => {
37+
const resp = await fetch(url);
38+
if (!resp.ok) {
39+
throw new Error(`Getting latest releaseId failed: ${resp.statusText}`);
40+
}
41+
const { releaseId } = JSON.parse(await resp.text());
42+
return {
43+
value: releaseId as string,
44+
ttl: this.getResponseCacheTime(resp),
45+
};
46+
});
4747
}
48-
return Number(t[1]);
49-
}
5048

51-
async function getLastPublish(cacheHelper: CacheHelper) {
52-
const url = `${websiteHost}/changelog/latest`;
53-
return cacheHelper.getOrRefresh(url, async () => {
54-
const resp = await fetch(url);
55-
if (!resp.ok) {
56-
throw new Error(`Getting latest releaseId failed: ${resp.statusText}`);
49+
private getResponseCacheTime(resp: Response) {
50+
const cacheControlHeader = resp.headers.get('Cache-Control');
51+
if (!cacheControlHeader) {
52+
return undefined;
5753
}
58-
const { releaseId } = JSON.parse(await resp.text());
59-
return {
60-
value: releaseId as string,
61-
ttl: getResponseCacheTime(resp),
62-
};
63-
});
64-
65-
}
66-
67-
const websiteHost = 'https://www.gitpod.io';
68-
69-
class ReleaseNotesPanel {
70-
public static currentPanel: ReleaseNotesPanel | undefined;
71-
public static readonly viewType = 'gitpodReleaseNotes';
72-
private readonly panel: vscode.WebviewPanel;
73-
private lastReadId: string | undefined;
74-
private _disposables: vscode.Disposable[] = [];
54+
const match = /max-age=(\d+)/.exec(cacheControlHeader);
55+
if (!match) {
56+
return undefined;
57+
}
58+
return parseInt(match[1], 10);
59+
}
7560

7661
private async loadChangelog(releaseId: string) {
77-
const url = `${websiteHost}/changelog/raw-markdown?releaseId=${releaseId}`;
62+
const url = `${ReleaseNotes.websiteHost}/changelog/raw-markdown?releaseId=${releaseId}`;
7863
const md = await this.cacheHelper.getOrRefresh(url, async () => {
7964
const resp = await fetch(url);
8065
if (!resp.ok) {
@@ -83,7 +68,7 @@ class ReleaseNotesPanel {
8368
const md = await resp.text();
8469
return {
8570
value: md,
86-
ttl: getResponseCacheTime(resp),
71+
ttl: this.getResponseCacheTime(resp),
8772
};
8873
});
8974

@@ -122,12 +107,14 @@ class ReleaseNotesPanel {
122107
].join('\n\n');
123108
}
124109

125-
public async updateHtml(releaseId?: string) {
126-
if (!releaseId) {
127-
releaseId = await getLastPublish(this.cacheHelper);
110+
public async updateHtml() {
111+
if (!this.panel?.visible) {
112+
return;
128113
}
114+
115+
const releaseId = await this.getLastPublish();
129116
const mdContent = await this.loadChangelog(releaseId);
130-
const html = await vscode.commands.executeCommand('markdown.api.render', mdContent) as string;
117+
const html = await vscode.commands.executeCommand<string>('markdown.api.render', mdContent);
131118
this.panel.webview.html = `<!DOCTYPE html>
132119
<html lang="en">
133120
<head>
@@ -143,72 +130,54 @@ class ReleaseNotesPanel {
143130
${html}
144131
</body>
145132
</html>`;
146-
if (!this.lastReadId || releaseId > this.lastReadId) {
147-
await this.context.globalState.update(LAST_READ_RELEASE_NOTES_ID, releaseId);
133+
if (releaseId !== this.lastReadId) {
134+
await this.context.globalState.update(ReleaseNotes.RELEASE_NOTES_LAST_READ_KEY, releaseId);
148135
this.lastReadId = releaseId;
149136
}
150137
}
151138

152-
public static createOrShow(context: vscode.ExtensionContext, cacheHelper: CacheHelper) {
153-
const column = vscode.window.activeTextEditor
154-
? vscode.window.activeTextEditor.viewColumn
155-
: undefined;
139+
private async showIfNewRelease(lastReadId: string | undefined) {
140+
const releaseId = await this.getLastPublish();
141+
console.log(`gitpod release notes lastReadId: ${lastReadId}, latestReleaseId: ${releaseId}`);
142+
if (releaseId !== lastReadId) {
143+
this.createOrShow();
144+
}
145+
}
156146

157-
if (ReleaseNotesPanel.currentPanel) {
158-
ReleaseNotesPanel.currentPanel.panel.reveal(column);
147+
public createOrShow() {
148+
if (this.panel) {
149+
this.panel.reveal();
159150
return;
160151
}
161152

162-
const panel = vscode.window.createWebviewPanel(
163-
ReleaseNotesPanel.viewType,
153+
this.panel = vscode.window.createWebviewPanel(
154+
ReleaseNotes.viewType,
164155
'Gitpod Release Notes',
165-
column || vscode.ViewColumn.One,
156+
vscode.ViewColumn.Beside,
166157
{ enableScripts: true },
167158
);
168-
169-
ReleaseNotesPanel.currentPanel = new ReleaseNotesPanel(context, cacheHelper, panel);
170-
}
171-
172-
public static revive(context: vscode.ExtensionContext, cacheHelper: CacheHelper, panel: vscode.WebviewPanel) {
173-
ReleaseNotesPanel.currentPanel = new ReleaseNotesPanel(context, cacheHelper, panel);
174-
}
175-
176-
private constructor(
177-
private readonly context: vscode.ExtensionContext,
178-
private readonly cacheHelper: CacheHelper,
179-
panel: vscode.WebviewPanel
180-
) {
181-
this.lastReadId = this.context.globalState.get<string>(LAST_READ_RELEASE_NOTES_ID);
182-
this.panel = panel;
183-
184-
this.updateHtml();
185-
186-
this.panel.onDidDispose(() => this.dispose(), null, this._disposables);
159+
this.panel.onDidDispose(() => {
160+
disposeAll(this.panelDisposables);
161+
this.panel = undefined;
162+
this.panelDisposables = [];
163+
}, null, this.panelDisposables);
187164
this.panel.onDidChangeViewState(
188-
() => {
189-
if (this.panel.visible) {
190-
this.updateHtml();
191-
}
192-
},
165+
() => this.updateHtml(),
193166
null,
194-
this._disposables
167+
this.panelDisposables
195168
);
169+
this.updateHtml();
196170
}
197171

198-
public dispose() {
199-
ReleaseNotesPanel.currentPanel = undefined;
200-
this.panel.dispose();
201-
while (this._disposables.length) {
202-
const x = this._disposables.pop();
203-
if (x) {
204-
x.dispose();
205-
}
206-
}
172+
override dispose() {
173+
super.dispose();
174+
disposeAll(this.panelDisposables);
175+
this.panel?.dispose();
207176
}
208177
}
209178

210179
// Align with https://github.com/gitpod-io/openvscode-server/blob/494f7eba3615344ee634e6bec0b20a1903e5881d/src/vs/workbench/contrib/markdown/browser/markdownDocumentRenderer.ts#L14
211-
export const DEFAULT_MARKDOWN_STYLES = `
180+
const DEFAULT_MARKDOWN_STYLES = `
212181
body {
213182
padding: 10px 20px;
214183
line-height: 22px;

0 commit comments

Comments
 (0)