@@ -19,42 +19,9 @@ export class Panel {
1919 private readonly _extensionPath : string ;
2020 private _disposables : vscode . Disposable [ ] = [ ] ;
2121
22- public static createOrShow ( context : vscode . ExtensionContext , codingSrv : CodingServer ) {
23- const { extensionUri, extensionPath } = context ;
24- const column = vscode . window . activeTextEditor
25- ? vscode . window . activeTextEditor . viewColumn
26- : undefined ;
27-
28- // If we already have a panel, show it.
29- if ( Panel . currentPanel ) {
30- Panel . currentPanel . _panel . reveal ( column ) ;
31- return ;
32- }
33-
34- // Otherwise, create a new panel.
35- const panel = vscode . window . createWebviewPanel (
36- Panel . viewType ,
37- 'Coding' ,
38- column || vscode . ViewColumn . One ,
39- {
40- // Enable javascript in the webview
41- enableScripts : true ,
42-
43- localResourceRoots : [ vscode . Uri . joinPath ( extensionUri , 'out' ) ] ,
44- } ,
45- ) ;
46-
47- Panel . currentPanel = new Panel ( panel , codingSrv , extensionUri , extensionPath ) ;
48- }
49-
50- public static revive (
51- panel : vscode . WebviewPanel ,
52- codingSrv : CodingServer ,
53- extensionUri : vscode . Uri ,
54- extensionPath : string ,
55- ) {
56- Panel . currentPanel = new Panel ( panel , codingSrv , extensionUri , extensionPath ) ;
57- }
22+ private _waitForReady : Promise < void > ;
23+ private _onIsReady : vscode . EventEmitter < void > = new vscode . EventEmitter ( ) ;
24+ protected readonly MESSAGE_UNHANDLED : string = 'message not handled' ;
5825
5926 private constructor (
6027 panel : vscode . WebviewPanel ,
@@ -86,123 +53,174 @@ export class Panel {
8653 ) ;
8754
8855 // Handle messages from the webview
89- this . _panel . webview . onDidReceiveMessage (
90- async ( message : IRequestMessage < any > ) => {
91- const { command, args } = message ;
92- try {
93- switch ( command ) {
94- case 'alert' :
95- vscode . window . showErrorMessage ( args ) ;
96- return ;
97- case 'mr.close' :
98- await this . _codingSrv . closeMR ( args ) ;
99- this . replyMessage ( message ) ;
100- break ;
101- case 'mr.approve' :
102- await this . _codingSrv . approveMR ( args ) ;
103- this . replyMessage ( message ) ;
104- break ;
105- case 'mr.disapprove' :
106- await this . _codingSrv . disapproveMR ( args ) ;
107- this . replyMessage ( message ) ;
108- break ;
109- case 'mr.merge' :
110- await this . _codingSrv . mergeMR ( args ) ;
111- this . replyMessage ( message ) ;
112- break ;
113- case 'mr.update.title' :
114- await this . _codingSrv . updateMRTitle ( args . iid , args . title ) ;
115- this . replyMessage ( message ) ;
116- break ;
117- case 'mr.add.comment' :
118- const commentRes = await this . _codingSrv . commentMR ( args . id , args . comment ) ;
119- this . broadcast ( command , commentRes . data ) ;
120- break ;
121- case 'mr.get.activities' :
122- const getActivitiesRes = await this . _codingSrv . getMRActivities ( args ) ;
123- this . replyMessage ( message , getActivitiesRes . data ) ;
124- break ;
125- case 'mr.update.reviewers' : {
126- try {
127- const [ iid , selected ] : [ string , number [ ] ] = args ;
128- const {
129- data : { list : memberList } ,
130- } = await codingSrv . getProjectMembers ( ) ;
131- const list = memberList
132- . filter ( ( i ) => i . user . global_key !== codingSrv . session ?. user ?. global_key )
133- . map ( ( i ) => ( {
134- label : i . user . name ,
135- description : i . user . global_key ,
136- picked : selected . includes ( i . user . id ) ,
137- userId : i . user . id ,
138- } ) ) ;
139- const selection = await vscode . window . showQuickPick ( list , {
140- canPickMany : true ,
141- ignoreFocusOut : true ,
142- } ) ;
143-
144- if ( ! selection ) {
145- return ;
146- }
147-
148- const s = selection . map ( ( i ) => i . userId ) ;
149- const added = s . filter ( ( i ) => ! selected . includes ( i ) ) ;
150- const removed = selected . filter ( ( i ) => ! s . includes ( i ) ) ;
151- const tasks = [ ] ;
152- if ( added . length ) {
153- tasks . push ( codingSrv . addMRReviewers ( iid , added ) ) ;
154- }
155- if ( removed . length ) {
156- tasks . push ( codingSrv . removeMRReviewers ( iid , removed ) ) ;
157- }
158-
159- await Promise . all ( tasks ) ;
160- const resp = await codingSrv . getMRReviewers ( iid ) ;
161- this . broadcast ( command , resp . data ) ;
162- } catch ( err ) { }
163- break ;
164- }
165- case `mr.update.desc` : {
166- try {
167- const [ iid , content ] = args ;
168- const resp = await codingSrv . updateMRDesc ( iid , content ) ;
169- this . broadcast ( command , [ iid , resp . data ] ) ;
170- } catch ( e ) { }
171- break ;
172- }
173- default :
174- break ;
175- }
176- } catch ( err ) {
177- this . throwError ( message , err . msg ) ;
178- vscode . window . showErrorMessage ( formatErrorMessage ( err . msg ) ) ;
179- }
56+ this . _panel . webview ?. onDidReceiveMessage (
57+ async ( message ) => {
58+ await this . _onDidReceiveMessage ( message ) ;
18059 } ,
18160 null ,
18261 this . _disposables ,
18362 ) ;
63+
64+ this . _waitForReady = new Promise ( ( resolve ) => {
65+ const disposable = this . _onIsReady . event ( ( ) => {
66+ disposable . dispose ( ) ;
67+ resolve ( ) ;
68+ } ) ;
69+ } ) ;
18470 }
18571
186- public replyMessage ( originalMessage : IRequestMessage < any > , message ?: any ) {
72+ protected async _onDidReceiveMessage ( message : IRequestMessage < any > ) {
73+ const { command, args } = message ;
74+ try {
75+ switch ( command ) {
76+ case 'alert' :
77+ vscode . window . showErrorMessage ( args ) ;
78+ return ;
79+ case 'mr.close' :
80+ await this . _codingSrv . closeMR ( args ) ;
81+ this . _replyMessage ( message , { } ) ;
82+ break ;
83+ case 'mr.approve' :
84+ await this . _codingSrv . approveMR ( args ) ;
85+ this . _replyMessage ( message , { } ) ;
86+ break ;
87+ case 'mr.disapprove' :
88+ await this . _codingSrv . disapproveMR ( args ) ;
89+ this . _replyMessage ( message , { } ) ;
90+ break ;
91+ case 'mr.merge' :
92+ await this . _codingSrv . mergeMR ( args ) ;
93+ this . _replyMessage ( message , { } ) ;
94+ break ;
95+ case 'mr.update.title' :
96+ await this . _codingSrv . updateMRTitle ( args . iid , args . title ) ;
97+ this . _replyMessage ( message , { } ) ;
98+ break ;
99+ case 'mr.add.comment' :
100+ const commentRes = await this . _codingSrv . commentMR ( args . id , args . comment ) ;
101+ this . _replyMessage ( message , commentRes . data ) ;
102+ break ;
103+ case 'mr.get.activities' :
104+ const getActivitiesRes = await this . _codingSrv . getMRActivities ( args ) ;
105+ this . _replyMessage ( message , getActivitiesRes . data ) ;
106+ break ;
107+ case 'mr.update.reviewers' : {
108+ try {
109+ const [ iid , selected ] : [ string , number [ ] ] = args ;
110+ const {
111+ data : { list : memberList } ,
112+ } = await this . _codingSrv . getProjectMembers ( ) ;
113+ const list = memberList
114+ . filter ( ( i ) => i . user . global_key !== this . _codingSrv . session ?. user ?. global_key )
115+ . map ( ( i ) => ( {
116+ label : i . user . name ,
117+ description : i . user . global_key ,
118+ picked : selected . includes ( i . user . id ) ,
119+ userId : i . user . id ,
120+ } ) ) ;
121+ const selection = await vscode . window . showQuickPick ( list , {
122+ canPickMany : true ,
123+ ignoreFocusOut : true ,
124+ } ) ;
125+
126+ if ( ! selection ) {
127+ return ;
128+ }
129+
130+ const s = selection . map ( ( i ) => i . userId ) ;
131+ const added = s . filter ( ( i ) => ! selected . includes ( i ) ) ;
132+ const removed = selected . filter ( ( i ) => ! s . includes ( i ) ) ;
133+ const tasks = [ ] ;
134+ if ( added . length ) {
135+ tasks . push ( this . _codingSrv . addMRReviewers ( iid , added ) ) ;
136+ }
137+ if ( removed . length ) {
138+ tasks . push ( this . _codingSrv . removeMRReviewers ( iid , removed ) ) ;
139+ }
140+
141+ await Promise . all ( tasks ) ;
142+ const resp = await this . _codingSrv . getMRReviewers ( iid ) ;
143+ this . broadcast ( command , resp . data ) ;
144+ } catch ( err ) { }
145+ break ;
146+ }
147+ case `mr.update.desc` : {
148+ try {
149+ const { iid, content } = args ;
150+ const resp = await this . _codingSrv . updateMRDesc ( iid , content ) ;
151+ this . _replyMessage ( message , resp . data ) ;
152+ } catch ( e ) { }
153+ break ;
154+ }
155+ default :
156+ return this . MESSAGE_UNHANDLED ;
157+ }
158+ } catch ( err ) {
159+ this . _throwError ( message , err . msg ) ;
160+ vscode . window . showErrorMessage ( formatErrorMessage ( err . msg ) ) ;
161+ }
162+ }
163+
164+ protected async _postMessage ( message : any ) {
165+ // Without the following ready check, we can end up in a state where the message handler in the webview
166+ // isn't ready for any of the messages we post.
167+ await this . _waitForReady ;
168+ this . _panel . webview ?. postMessage ( {
169+ res : message ,
170+ } ) ;
171+ }
172+
173+ protected async _replyMessage ( originalMessage : IRequestMessage < any > , message : any = { } ) {
187174 const reply : IReplyMessage = {
188175 seq : originalMessage . req ,
189176 res : message ,
190177 } ;
191- this . _panel . webview . postMessage ( reply ) ;
178+ this . _panel . webview ? .postMessage ( reply ) ;
192179 }
193180
194- public throwError ( originalMessage : IRequestMessage < any > , error : any ) {
181+ protected async _throwError ( originalMessage : IRequestMessage < any > , error : any ) {
195182 const reply : IReplyMessage = {
196183 seq : originalMessage . req ,
197184 err : error ,
198185 } ;
199- this . _panel . webview . postMessage ( reply ) ;
186+ this . _panel . webview ?. postMessage ( reply ) ;
187+ }
188+
189+ public static createOrShow ( context : vscode . ExtensionContext , codingSrv : CodingServer ) {
190+ const { extensionUri, extensionPath } = context ;
191+ const column = vscode . window . activeTextEditor
192+ ? vscode . window . activeTextEditor . viewColumn
193+ : undefined ;
194+
195+ // If we already have a panel, show it.
196+ if ( Panel . currentPanel ) {
197+ Panel . currentPanel . _panel . reveal ( column ) ;
198+ return ;
199+ }
200+
201+ // Otherwise, create a new panel.
202+ const panel = vscode . window . createWebviewPanel (
203+ Panel . viewType ,
204+ 'Coding' ,
205+ column || vscode . ViewColumn . One ,
206+ {
207+ // Enable javascript in the webview
208+ enableScripts : true ,
209+
210+ localResourceRoots : [ vscode . Uri . joinPath ( extensionUri , 'out' ) ] ,
211+ } ,
212+ ) ;
213+
214+ Panel . currentPanel = new Panel ( panel , codingSrv , extensionUri , extensionPath ) ;
200215 }
201216
202- public doRefactor ( ) {
203- // Send a message to the webview webview.
204- // You can send any JSON serializable data.
205- this . _panel . webview . postMessage ( { command : 'refactor' } ) ;
217+ public static revive (
218+ panel : vscode . WebviewPanel ,
219+ codingSrv : CodingServer ,
220+ extensionUri : vscode . Uri ,
221+ extensionPath : string ,
222+ ) {
223+ Panel . currentPanel = new Panel ( panel , codingSrv , extensionUri , extensionPath ) ;
206224 }
207225
208226 public broadcast ( command : string , res : any ) {
@@ -232,21 +250,21 @@ export class Panel {
232250 // Vary the webview's content based on where it is located in the editor.
233251 switch ( this . _panel . viewColumn ) {
234252 case vscode . ViewColumn . Two :
235- this . _updateForCat ( webview ) ;
253+ this . _updateForPanel ( webview ) ;
236254 return ;
237255
238256 case vscode . ViewColumn . Three :
239- this . _updateForCat ( webview ) ;
257+ this . _updateForPanel ( webview ) ;
240258 return ;
241259
242260 case vscode . ViewColumn . One :
243261 default :
244- this . _updateForCat ( webview ) ;
262+ this . _updateForPanel ( webview ) ;
245263 return ;
246264 }
247265 }
248266
249- private _updateForCat ( webview : vscode . Webview ) {
267+ private _updateForPanel ( webview : vscode . Webview ) {
250268 this . _panel . title = `Merge Request Overview` ;
251269 this . _panel . webview . html = this . _getHtmlForWebview ( webview ) ;
252270 }
0 commit comments