@@ -7,74 +7,59 @@ import fetch, { Response } from 'node-fetch';
7
7
import * as vscode from 'vscode' ;
8
8
import { load } from 'js-yaml' ;
9
9
import { CacheHelper } from './common/cache' ;
10
+ import { Disposable , disposeAll } from './common/dispose' ;
10
11
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' ;
15
16
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 ) ;
21
21
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 ( ) ;
27
26
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 ) ;
30
28
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 ( ) ) ) ;
38
30
39
- function getResponseCacheTime ( resp : Response ) {
40
- const v = resp . headers . get ( 'Cache-Control' ) ;
41
- if ( ! v ) {
42
- return undefined ;
31
+ this . showIfNewRelease ( this . lastReadId ) ;
43
32
}
44
- const t = / m a x - a g e = ( \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
+ } ) ;
47
47
}
48
- return Number ( t [ 1 ] ) ;
49
- }
50
48
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 ;
57
53
}
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 = / m a x - a g e = ( \d + ) / . exec ( cacheControlHeader ) ;
55
+ if ( ! match ) {
56
+ return undefined ;
57
+ }
58
+ return parseInt ( match [ 1 ] , 10 ) ;
59
+ }
75
60
76
61
private async loadChangelog ( releaseId : string ) {
77
- const url = `${ websiteHost } /changelog/raw-markdown?releaseId=${ releaseId } ` ;
62
+ const url = `${ ReleaseNotes . websiteHost } /changelog/raw-markdown?releaseId=${ releaseId } ` ;
78
63
const md = await this . cacheHelper . getOrRefresh ( url , async ( ) => {
79
64
const resp = await fetch ( url ) ;
80
65
if ( ! resp . ok ) {
@@ -83,7 +68,7 @@ class ReleaseNotesPanel {
83
68
const md = await resp . text ( ) ;
84
69
return {
85
70
value : md ,
86
- ttl : getResponseCacheTime ( resp ) ,
71
+ ttl : this . getResponseCacheTime ( resp ) ,
87
72
} ;
88
73
} ) ;
89
74
@@ -122,12 +107,14 @@ class ReleaseNotesPanel {
122
107
] . join ( '\n\n' ) ;
123
108
}
124
109
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 ;
128
113
}
114
+
115
+ const releaseId = await this . getLastPublish ( ) ;
129
116
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 ) ;
131
118
this . panel . webview . html = `<!DOCTYPE html>
132
119
<html lang="en">
133
120
<head>
@@ -143,72 +130,54 @@ class ReleaseNotesPanel {
143
130
${ html }
144
131
</body>
145
132
</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 ) ;
148
135
this . lastReadId = releaseId ;
149
136
}
150
137
}
151
138
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
+ }
156
146
157
- if ( ReleaseNotesPanel . currentPanel ) {
158
- ReleaseNotesPanel . currentPanel . panel . reveal ( column ) ;
147
+ public createOrShow ( ) {
148
+ if ( this . panel ) {
149
+ this . panel . reveal ( ) ;
159
150
return ;
160
151
}
161
152
162
- const panel = vscode . window . createWebviewPanel (
163
- ReleaseNotesPanel . viewType ,
153
+ this . panel = vscode . window . createWebviewPanel (
154
+ ReleaseNotes . viewType ,
164
155
'Gitpod Release Notes' ,
165
- column || vscode . ViewColumn . One ,
156
+ vscode . ViewColumn . Beside ,
166
157
{ enableScripts : true } ,
167
158
) ;
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 ) ;
187
164
this . panel . onDidChangeViewState (
188
- ( ) => {
189
- if ( this . panel . visible ) {
190
- this . updateHtml ( ) ;
191
- }
192
- } ,
165
+ ( ) => this . updateHtml ( ) ,
193
166
null ,
194
- this . _disposables
167
+ this . panelDisposables
195
168
) ;
169
+ this . updateHtml ( ) ;
196
170
}
197
171
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 ( ) ;
207
176
}
208
177
}
209
178
210
179
// 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 = `
212
181
body {
213
182
padding: 10px 20px;
214
183
line-height: 22px;
0 commit comments