@theia/plugin-ext 1.61.0 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/common/plugin-api-rpc-model.d.ts +2 -2
- package/lib/common/plugin-api-rpc-model.d.ts.map +1 -1
- package/lib/common/plugin-api-rpc.d.ts +3 -2
- package/lib/common/plugin-api-rpc.d.ts.map +1 -1
- package/lib/common/plugin-api-rpc.js.map +1 -1
- package/lib/main/browser/comments/comment-thread-widget.d.ts +64 -15
- package/lib/main/browser/comments/comment-thread-widget.d.ts.map +1 -1
- package/lib/main/browser/comments/comment-thread-widget.js +93 -49
- package/lib/main/browser/comments/comment-thread-widget.js.map +1 -1
- package/lib/main/browser/comments/{comments-context-key-service.d.ts → comments-context.d.ts} +2 -7
- package/lib/main/browser/comments/comments-context.d.ts.map +1 -0
- package/lib/main/browser/comments/{comments-context-key-service.js → comments-context.js} +8 -25
- package/lib/main/browser/comments/comments-context.js.map +1 -0
- package/lib/main/browser/comments/comments-contribution.d.ts +2 -2
- package/lib/main/browser/comments/comments-contribution.d.ts.map +1 -1
- package/lib/main/browser/comments/comments-contribution.js +8 -8
- package/lib/main/browser/comments/comments-contribution.js.map +1 -1
- package/lib/main/browser/comments/comments-main.d.ts +28 -3
- package/lib/main/browser/comments/comments-main.d.ts.map +1 -1
- package/lib/main/browser/comments/comments-main.js.map +1 -1
- package/lib/main/browser/custom-editors/custom-editor-opener.d.ts.map +1 -1
- package/lib/main/browser/custom-editors/custom-editor-opener.js +6 -1
- package/lib/main/browser/custom-editors/custom-editor-opener.js.map +1 -1
- package/lib/main/browser/documents-main.d.ts +2 -1
- package/lib/main/browser/documents-main.d.ts.map +1 -1
- package/lib/main/browser/documents-main.js +13 -9
- package/lib/main/browser/documents-main.js.map +1 -1
- package/lib/main/browser/main-context.d.ts.map +1 -1
- package/lib/main/browser/main-context.js +3 -1
- package/lib/main/browser/main-context.js.map +1 -1
- package/lib/main/browser/menus/menus-contribution-handler.d.ts +7 -13
- package/lib/main/browser/menus/menus-contribution-handler.d.ts.map +1 -1
- package/lib/main/browser/menus/menus-contribution-handler.js +64 -51
- package/lib/main/browser/menus/menus-contribution-handler.js.map +1 -1
- package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts +5 -30
- package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts.map +1 -1
- package/lib/main/browser/menus/plugin-menu-command-adapter.js +7 -110
- package/lib/main/browser/menus/plugin-menu-command-adapter.js.map +1 -1
- package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts +4 -4
- package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts.map +1 -1
- package/lib/main/browser/menus/vscode-theia-menu-mappings.js +7 -10
- package/lib/main/browser/menus/vscode-theia-menu-mappings.js.map +1 -1
- package/lib/main/browser/plugin-ext-frontend-module.d.ts.map +1 -1
- package/lib/main/browser/plugin-ext-frontend-module.js +2 -4
- package/lib/main/browser/plugin-ext-frontend-module.js.map +1 -1
- package/lib/main/browser/terminal-main.d.ts.map +1 -1
- package/lib/main/browser/terminal-main.js +4 -1
- package/lib/main/browser/terminal-main.js.map +1 -1
- package/lib/main/browser/text-editor-model-service.d.ts +1 -3
- package/lib/main/browser/text-editor-model-service.d.ts.map +1 -1
- package/lib/main/browser/text-editor-model-service.js +0 -5
- package/lib/main/browser/text-editor-model-service.js.map +1 -1
- package/lib/main/browser/view/tree-view-widget.d.ts +2 -2
- package/lib/main/browser/view/tree-view-widget.d.ts.map +1 -1
- package/lib/main/browser/view/tree-view-widget.js +5 -4
- package/lib/main/browser/view/tree-view-widget.js.map +1 -1
- package/lib/plugin/comments.d.ts +2 -2
- package/lib/plugin/comments.d.ts.map +1 -1
- package/lib/plugin/comments.js.map +1 -1
- package/lib/plugin/terminal-ext.d.ts +2 -1
- package/lib/plugin/terminal-ext.d.ts.map +1 -1
- package/lib/plugin/terminal-ext.js +13 -3
- package/lib/plugin/terminal-ext.js.map +1 -1
- package/package.json +29 -29
- package/src/common/plugin-api-rpc-model.ts +2 -2
- package/src/common/plugin-api-rpc.ts +3 -2
- package/src/main/browser/comments/comment-thread-widget.tsx +177 -85
- package/src/main/browser/comments/{comments-context-key-service.ts → comments-context.ts} +1 -20
- package/src/main/browser/comments/comments-contribution.ts +5 -5
- package/src/main/browser/comments/comments-main.ts +5 -4
- package/src/main/browser/custom-editors/custom-editor-opener.tsx +5 -1
- package/src/main/browser/documents-main.ts +19 -10
- package/src/main/browser/main-context.ts +3 -1
- package/src/main/browser/menus/menus-contribution-handler.ts +68 -49
- package/src/main/browser/menus/plugin-menu-command-adapter.ts +13 -120
- package/src/main/browser/menus/vscode-theia-menu-mappings.ts +4 -6
- package/src/main/browser/plugin-ext-frontend-module.ts +2 -4
- package/src/main/browser/style/comments.css +9 -1
- package/src/main/browser/terminal-main.ts +4 -1
- package/src/main/browser/text-editor-model-service.ts +1 -6
- package/src/main/browser/view/tree-view-widget.tsx +7 -6
- package/src/plugin/comments.ts +4 -4
- package/src/plugin/terminal-ext.ts +14 -3
- package/lib/main/browser/comments/comments-context-key-service.d.ts.map +0 -1
- package/lib/main/browser/comments/comments-context-key-service.js.map +0 -1
|
@@ -27,16 +27,20 @@ import * as React from '@theia/core/shared/react';
|
|
|
27
27
|
import { MouseTargetType } from '@theia/editor/lib/browser';
|
|
28
28
|
import { CommentsService } from './comments-service';
|
|
29
29
|
import {
|
|
30
|
-
|
|
30
|
+
CommandMenu,
|
|
31
31
|
CommandRegistry,
|
|
32
32
|
CompoundMenuNode,
|
|
33
|
+
isObject,
|
|
34
|
+
DisposableCollection,
|
|
33
35
|
MenuModelRegistry,
|
|
34
36
|
MenuPath
|
|
35
37
|
} from '@theia/core/lib/common';
|
|
36
|
-
import {
|
|
38
|
+
import { CommentsContext } from './comments-context';
|
|
37
39
|
import { RefObject } from '@theia/core/shared/react';
|
|
38
40
|
import * as monaco from '@theia/monaco-editor-core';
|
|
39
41
|
import { createRoot, Root } from '@theia/core/shared/react-dom/client';
|
|
42
|
+
import { CommentAuthorInformation } from '@theia/plugin';
|
|
43
|
+
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
|
|
40
44
|
|
|
41
45
|
/*---------------------------------------------------------------------------------------------
|
|
42
46
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -64,7 +68,8 @@ export class CommentThreadWidget extends BaseWidget {
|
|
|
64
68
|
private _commentThread: CommentThread,
|
|
65
69
|
private commentService: CommentsService,
|
|
66
70
|
protected readonly menus: MenuModelRegistry,
|
|
67
|
-
protected readonly
|
|
71
|
+
protected readonly commentsContext: CommentsContext,
|
|
72
|
+
protected readonly contextKeyService: ContextKeyService,
|
|
68
73
|
protected readonly commands: CommandRegistry
|
|
69
74
|
) {
|
|
70
75
|
super();
|
|
@@ -84,14 +89,9 @@ export class CommentThreadWidget extends BaseWidget {
|
|
|
84
89
|
return;
|
|
85
90
|
}
|
|
86
91
|
}));
|
|
87
|
-
this.
|
|
92
|
+
this.commentsContext.commentIsEmpty.set(true);
|
|
88
93
|
this.toDispose.push(this.zoneWidget.editor.onMouseDown(e => this.onEditorMouseDown(e)));
|
|
89
|
-
|
|
90
|
-
const commentForm = this.commentFormRef.current;
|
|
91
|
-
if (commentForm) {
|
|
92
|
-
commentForm.update();
|
|
93
|
-
}
|
|
94
|
-
}));
|
|
94
|
+
|
|
95
95
|
this.toDispose.push(this._commentThread.onDidChangeCanReply(_canReply => {
|
|
96
96
|
const commentForm = this.commentFormRef.current;
|
|
97
97
|
if (commentForm) {
|
|
@@ -102,9 +102,14 @@ export class CommentThreadWidget extends BaseWidget {
|
|
|
102
102
|
this.update();
|
|
103
103
|
}));
|
|
104
104
|
this.contextMenu = this.menus.getMenu(COMMENT_THREAD_CONTEXT);
|
|
105
|
-
this.contextMenu.children.
|
|
106
|
-
if (
|
|
107
|
-
this.
|
|
105
|
+
this.contextMenu.children.forEach(node => {
|
|
106
|
+
if (node.onDidChange) {
|
|
107
|
+
this.toDispose.push(node.onDidChange(() => {
|
|
108
|
+
const commentForm = this.commentFormRef.current;
|
|
109
|
+
if (commentForm) {
|
|
110
|
+
commentForm.update();
|
|
111
|
+
}
|
|
112
|
+
}));
|
|
108
113
|
}
|
|
109
114
|
});
|
|
110
115
|
}
|
|
@@ -288,6 +293,7 @@ export class CommentThreadWidget extends BaseWidget {
|
|
|
288
293
|
{this._commentThread.comments?.map((comment, index) => <ReviewComment
|
|
289
294
|
key={index}
|
|
290
295
|
contextKeyService={this.contextKeyService}
|
|
296
|
+
commentsContext={this.commentsContext}
|
|
291
297
|
menus={this.menus}
|
|
292
298
|
comment={comment}
|
|
293
299
|
commentForm={this.commentFormRef}
|
|
@@ -296,6 +302,7 @@ export class CommentThreadWidget extends BaseWidget {
|
|
|
296
302
|
/>)}
|
|
297
303
|
</div>
|
|
298
304
|
<CommentForm contextKeyService={this.contextKeyService}
|
|
305
|
+
commentsContext={this.commentsContext}
|
|
299
306
|
commands={this.commands}
|
|
300
307
|
commentThread={this._commentThread}
|
|
301
308
|
menus={this.menus}
|
|
@@ -312,7 +319,8 @@ namespace CommentForm {
|
|
|
312
319
|
menus: MenuModelRegistry,
|
|
313
320
|
commentThread: CommentThread;
|
|
314
321
|
commands: CommandRegistry;
|
|
315
|
-
contextKeyService:
|
|
322
|
+
contextKeyService: ContextKeyService;
|
|
323
|
+
commentsContext: CommentsContext;
|
|
316
324
|
widget: CommentThreadWidget;
|
|
317
325
|
}
|
|
318
326
|
|
|
@@ -322,16 +330,16 @@ namespace CommentForm {
|
|
|
322
330
|
}
|
|
323
331
|
|
|
324
332
|
export class CommentForm<P extends CommentForm.Props = CommentForm.Props> extends React.Component<P, CommentForm.State> {
|
|
325
|
-
private readonly menu: CompoundMenuNode;
|
|
326
333
|
private inputRef: RefObject<HTMLTextAreaElement> = React.createRef<HTMLTextAreaElement>();
|
|
327
334
|
private inputValue: string = '';
|
|
328
335
|
private readonly getInput = () => this.inputValue;
|
|
336
|
+
private toDisposeOnUnmount = new DisposableCollection();
|
|
329
337
|
private readonly clearInput: () => void = () => {
|
|
330
338
|
const input = this.inputRef.current;
|
|
331
339
|
if (input) {
|
|
332
340
|
this.inputValue = '';
|
|
333
341
|
input.value = this.inputValue;
|
|
334
|
-
this.props.
|
|
342
|
+
this.props.commentsContext.commentIsEmpty.set(true);
|
|
335
343
|
}
|
|
336
344
|
};
|
|
337
345
|
|
|
@@ -364,11 +372,15 @@ export class CommentForm<P extends CommentForm.Props = CommentForm.Props> extend
|
|
|
364
372
|
}, 100);
|
|
365
373
|
}
|
|
366
374
|
|
|
375
|
+
override componentWillUnmount(): void {
|
|
376
|
+
this.toDisposeOnUnmount.dispose();
|
|
377
|
+
}
|
|
378
|
+
|
|
367
379
|
private readonly onInput: (event: React.FormEvent) => void = (event: React.FormEvent) => {
|
|
368
380
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
369
381
|
const value = (event.target as any).value;
|
|
370
382
|
if (this.inputValue.length === 0 || value.length === 0) {
|
|
371
|
-
this.props.
|
|
383
|
+
this.props.commentsContext.commentIsEmpty.set(value.length === 0);
|
|
372
384
|
}
|
|
373
385
|
this.inputValue = value;
|
|
374
386
|
};
|
|
@@ -383,48 +395,106 @@ export class CommentForm<P extends CommentForm.Props = CommentForm.Props> extend
|
|
|
383
395
|
this.setState = newState => {
|
|
384
396
|
setState(newState);
|
|
385
397
|
};
|
|
386
|
-
|
|
387
|
-
this.menu = this.props.menus.getMenu(COMMENT_THREAD_CONTEXT);
|
|
388
|
-
this.menu.children.map(node => node instanceof ActionMenuNode && node.when).forEach(exp => {
|
|
389
|
-
if (typeof exp === 'string') {
|
|
390
|
-
this.props.contextKeyService.setExpression(exp);
|
|
391
|
-
}
|
|
392
|
-
});
|
|
393
398
|
}
|
|
394
399
|
|
|
395
|
-
|
|
396
|
-
|
|
400
|
+
/**
|
|
401
|
+
* Renders the comment form with textarea, actions, and reply button.
|
|
402
|
+
*
|
|
403
|
+
* @returns The rendered comment form
|
|
404
|
+
*/
|
|
405
|
+
protected renderCommentForm(): React.ReactNode {
|
|
406
|
+
const { commentThread, commentsContext, contextKeyService, menus } = this.props;
|
|
397
407
|
const hasExistingComments = commentThread.comments && commentThread.comments.length > 0;
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
408
|
+
|
|
409
|
+
// Determine when to show the expanded form:
|
|
410
|
+
// - When state.expanded is true (user clicked the reply button)
|
|
411
|
+
// - When there are no existing comments (new thread)
|
|
412
|
+
const shouldShowExpanded = this.state.expanded || (commentThread.comments && commentThread.comments.length === 0);
|
|
413
|
+
|
|
414
|
+
return commentThread.canReply ? (
|
|
415
|
+
<div className={`comment-form${shouldShowExpanded ? ' expand' : ''}`}>
|
|
416
|
+
<div className={'theia-comments-input-message-container'}>
|
|
417
|
+
<textarea className={'theia-comments-input-message theia-input'}
|
|
418
|
+
spellCheck={false}
|
|
419
|
+
placeholder={hasExistingComments ? 'Reply...' : 'Type a new comment'}
|
|
420
|
+
onInput={this.onInput}
|
|
421
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
422
|
+
onBlur={(event: any) => {
|
|
423
|
+
if (event.target.value.length > 0) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (event.relatedTarget && event.relatedTarget.className === 'comments-button comments-text-button theia-button') {
|
|
427
|
+
this.state = { expanded: false };
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
this.collapse();
|
|
431
|
+
}}
|
|
432
|
+
ref={this.inputRef}>
|
|
433
|
+
</textarea>
|
|
434
|
+
</div>
|
|
435
|
+
<CommentActions menu={menus.getMenu(COMMENT_THREAD_CONTEXT)}
|
|
436
|
+
menuPath={[]}
|
|
437
|
+
contextKeyService={contextKeyService}
|
|
438
|
+
commentsContext={commentsContext}
|
|
439
|
+
commentThread={commentThread}
|
|
440
|
+
getInput={this.getInput}
|
|
441
|
+
clearInput={this.clearInput}
|
|
442
|
+
/>
|
|
443
|
+
<button className={'review-thread-reply-button'} title={'Reply...'} onClick={this.expand}>Reply...</button>
|
|
417
444
|
</div>
|
|
418
|
-
|
|
419
|
-
contextKeyService={contextKeyService}
|
|
420
|
-
commands={commands}
|
|
421
|
-
commentThread={commentThread}
|
|
422
|
-
getInput={this.getInput}
|
|
423
|
-
clearInput={this.clearInput}
|
|
424
|
-
/>
|
|
425
|
-
<button className={'review-thread-reply-button'} title={'Reply...'} onClick={this.expand}>Reply...</button>
|
|
426
|
-
</div> : null;
|
|
445
|
+
) : null;
|
|
427
446
|
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Renders the author information section.
|
|
450
|
+
*
|
|
451
|
+
* @param authorInfo The author information to display
|
|
452
|
+
* @returns The rendered author information section
|
|
453
|
+
*/
|
|
454
|
+
protected renderAuthorInfo(authorInfo: CommentAuthorInformation): React.ReactNode {
|
|
455
|
+
return (
|
|
456
|
+
<div className={'avatar-container'}>
|
|
457
|
+
{authorInfo.iconPath && (
|
|
458
|
+
<img className={'avatar'} src={authorInfo.iconPath.toString()} />
|
|
459
|
+
)}
|
|
460
|
+
</div>
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
override render(): React.ReactNode {
|
|
465
|
+
const { commentThread } = this.props;
|
|
466
|
+
|
|
467
|
+
if (!commentThread.canReply) {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// If there's author info, wrap in a container with author info on the left
|
|
472
|
+
if (isCommentAuthorInformation(commentThread.canReply)) {
|
|
473
|
+
return (
|
|
474
|
+
<div className={'review-comment'}>
|
|
475
|
+
{this.renderAuthorInfo(commentThread.canReply)}
|
|
476
|
+
<div className={'review-comment-contents'}>
|
|
477
|
+
<div className={'comment-title monaco-mouse-cursor-text'}>
|
|
478
|
+
<strong className={'author'}>{commentThread.canReply.name}</strong>
|
|
479
|
+
</div>
|
|
480
|
+
{this.renderCommentForm()}
|
|
481
|
+
</div>
|
|
482
|
+
</div>
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Otherwise, just return the comment form
|
|
487
|
+
return (
|
|
488
|
+
<div className={'review-comment'}>
|
|
489
|
+
<div className={'review-comment-contents'}>
|
|
490
|
+
{this.renderCommentForm()}
|
|
491
|
+
</div>
|
|
492
|
+
</div>);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function isCommentAuthorInformation(item: unknown): item is CommentAuthorInformation {
|
|
497
|
+
return isObject(item) && 'name' in item;
|
|
428
498
|
}
|
|
429
499
|
|
|
430
500
|
namespace ReviewComment {
|
|
@@ -432,7 +502,8 @@ namespace ReviewComment {
|
|
|
432
502
|
menus: MenuModelRegistry,
|
|
433
503
|
comment: Comment;
|
|
434
504
|
commentThread: CommentThread;
|
|
435
|
-
contextKeyService:
|
|
505
|
+
contextKeyService: ContextKeyService;
|
|
506
|
+
commentsContext: CommentsContext;
|
|
436
507
|
commands: CommandRegistry;
|
|
437
508
|
commentForm: RefObject<CommentForm>;
|
|
438
509
|
}
|
|
@@ -469,10 +540,10 @@ export class ReviewComment<P extends ReviewComment.Props = ReviewComment.Props>
|
|
|
469
540
|
protected hideHover = () => this.setState({ hover: false });
|
|
470
541
|
|
|
471
542
|
override render(): React.ReactNode {
|
|
472
|
-
const { comment, commentForm, contextKeyService, menus, commands, commentThread } = this.props;
|
|
543
|
+
const { comment, commentForm, contextKeyService, commentsContext, menus, commands, commentThread } = this.props;
|
|
473
544
|
const commentUniqueId = comment.uniqueIdInThread;
|
|
474
545
|
const { hover } = this.state;
|
|
475
|
-
|
|
546
|
+
commentsContext.comment.set(comment.contextValue);
|
|
476
547
|
return <div className={'review-comment'}
|
|
477
548
|
tabIndex={-1}
|
|
478
549
|
aria-label={`${comment.userName}, ${comment.body.value}`}
|
|
@@ -489,14 +560,18 @@ export class ReviewComment<P extends ReviewComment.Props = ReviewComment.Props>
|
|
|
489
560
|
<span className={'isPending'}>{comment.label}</span>
|
|
490
561
|
<div className={'theia-comments-inline-actions-container'}>
|
|
491
562
|
<div className={'theia-comments-inline-actions'} role={'toolbar'}>
|
|
492
|
-
{hover && menus.getMenu(COMMENT_TITLE).children.map((node, index) => node
|
|
493
|
-
<CommentsInlineAction key={index} {...{
|
|
563
|
+
{hover && menus.getMenuNode(COMMENT_TITLE) && menus.getMenu(COMMENT_TITLE).children.map((node, index): React.ReactNode => CommandMenu.is(node) &&
|
|
564
|
+
<CommentsInlineAction key={index} {...{
|
|
565
|
+
node, nodePath: [...COMMENT_TITLE, node.id], commands, commentThread, commentUniqueId,
|
|
566
|
+
contextKeyService, commentsContext
|
|
567
|
+
}} />)}
|
|
494
568
|
</div>
|
|
495
569
|
</div>
|
|
496
570
|
</div>
|
|
497
571
|
<CommentBody value={comment.body.value}
|
|
498
572
|
isVisible={comment.mode === undefined || comment.mode === CommentMode.Preview} />
|
|
499
573
|
<CommentEditContainer contextKeyService={contextKeyService}
|
|
574
|
+
commentsContext={commentsContext}
|
|
500
575
|
menus={menus}
|
|
501
576
|
comment={comment}
|
|
502
577
|
commentThread={commentThread}
|
|
@@ -540,7 +615,8 @@ export class CommentBody extends React.Component<CommentBody.Props> {
|
|
|
540
615
|
|
|
541
616
|
namespace CommentEditContainer {
|
|
542
617
|
export interface Props {
|
|
543
|
-
contextKeyService:
|
|
618
|
+
contextKeyService: ContextKeyService;
|
|
619
|
+
commentsContext: CommentsContext;
|
|
544
620
|
menus: MenuModelRegistry,
|
|
545
621
|
comment: Comment;
|
|
546
622
|
commentThread: CommentThread;
|
|
@@ -572,7 +648,7 @@ export class CommentEditContainer extends React.Component<CommentEditContainer.P
|
|
|
572
648
|
}
|
|
573
649
|
|
|
574
650
|
override render(): React.ReactNode {
|
|
575
|
-
const { menus, comment, commands, commentThread, contextKeyService } = this.props;
|
|
651
|
+
const { menus, comment, commands, commentThread, contextKeyService, commentsContext } = this.props;
|
|
576
652
|
if (!(comment.mode === CommentMode.Editing)) {
|
|
577
653
|
return false;
|
|
578
654
|
}
|
|
@@ -586,7 +662,7 @@ export class CommentEditContainer extends React.Component<CommentEditContainer.P
|
|
|
586
662
|
</div>
|
|
587
663
|
</div>
|
|
588
664
|
<div className={'form-actions'}>
|
|
589
|
-
{menus.getMenu(COMMENT_CONTEXT).children.map((node, index) => {
|
|
665
|
+
{menus.getMenu(COMMENT_CONTEXT).children.map((node, index): React.ReactNode => {
|
|
590
666
|
const onClick = () => {
|
|
591
667
|
commands.executeCommand(node.id, {
|
|
592
668
|
commentControlHandle: commentThread.controllerHandle,
|
|
@@ -595,8 +671,11 @@ export class CommentEditContainer extends React.Component<CommentEditContainer.P
|
|
|
595
671
|
text: this.inputRef.current ? this.inputRef.current.value : ''
|
|
596
672
|
});
|
|
597
673
|
};
|
|
598
|
-
return node
|
|
599
|
-
<CommentAction key={index} {...{
|
|
674
|
+
return CommandMenu.is(node) &&
|
|
675
|
+
<CommentAction key={index} {...{
|
|
676
|
+
node, nodePath: [...COMMENT_CONTEXT, node.id], comment,
|
|
677
|
+
commands, onClick, contextKeyService, commentsContext, commentThread
|
|
678
|
+
}} />;
|
|
600
679
|
}
|
|
601
680
|
)}
|
|
602
681
|
</div>
|
|
@@ -606,18 +685,23 @@ export class CommentEditContainer extends React.Component<CommentEditContainer.P
|
|
|
606
685
|
|
|
607
686
|
namespace CommentsInlineAction {
|
|
608
687
|
export interface Props {
|
|
609
|
-
|
|
688
|
+
nodePath: MenuPath,
|
|
689
|
+
node: CommandMenu;
|
|
610
690
|
commentThread: CommentThread;
|
|
611
691
|
commentUniqueId: number;
|
|
612
692
|
commands: CommandRegistry;
|
|
613
|
-
contextKeyService:
|
|
693
|
+
contextKeyService: ContextKeyService;
|
|
694
|
+
commentsContext: CommentsContext;
|
|
614
695
|
}
|
|
615
696
|
}
|
|
616
697
|
|
|
617
698
|
export class CommentsInlineAction extends React.Component<CommentsInlineAction.Props> {
|
|
618
699
|
override render(): React.ReactNode {
|
|
619
|
-
const { node, commands, contextKeyService, commentThread, commentUniqueId } = this.props;
|
|
620
|
-
if (node.
|
|
700
|
+
const { node, nodePath, commands, contextKeyService, commentThread, commentUniqueId } = this.props;
|
|
701
|
+
if (node.isVisible(nodePath, contextKeyService, undefined, {
|
|
702
|
+
thread: commentThread,
|
|
703
|
+
commentUniqueId
|
|
704
|
+
})) {
|
|
621
705
|
return false;
|
|
622
706
|
}
|
|
623
707
|
return <div className='theia-comments-inline-action'>
|
|
@@ -625,9 +709,8 @@ export class CommentsInlineAction extends React.Component<CommentsInlineAction.P
|
|
|
625
709
|
title={node.label}
|
|
626
710
|
onClick={() => {
|
|
627
711
|
commands.executeCommand(node.id, {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
commentUniqueId
|
|
712
|
+
thread: commentThread,
|
|
713
|
+
commentUniqueId: commentUniqueId
|
|
631
714
|
});
|
|
632
715
|
}} />
|
|
633
716
|
</div>;
|
|
@@ -636,8 +719,9 @@ export class CommentsInlineAction extends React.Component<CommentsInlineAction.P
|
|
|
636
719
|
|
|
637
720
|
namespace CommentActions {
|
|
638
721
|
export interface Props {
|
|
639
|
-
contextKeyService:
|
|
640
|
-
|
|
722
|
+
contextKeyService: ContextKeyService;
|
|
723
|
+
commentsContext: CommentsContext;
|
|
724
|
+
menuPath: MenuPath,
|
|
641
725
|
menu: CompoundMenuNode;
|
|
642
726
|
commentThread: CommentThread;
|
|
643
727
|
getInput: () => string;
|
|
@@ -647,30 +731,34 @@ namespace CommentActions {
|
|
|
647
731
|
|
|
648
732
|
export class CommentActions extends React.Component<CommentActions.Props> {
|
|
649
733
|
override render(): React.ReactNode {
|
|
650
|
-
const { contextKeyService,
|
|
734
|
+
const { contextKeyService, commentsContext, menuPath, menu, commentThread, getInput, clearInput } = this.props;
|
|
651
735
|
return <div className={'form-actions'}>
|
|
652
|
-
{menu.children.map((node, index) => node
|
|
736
|
+
{menu.children.map((node, index) => CommandMenu.is(node) &&
|
|
653
737
|
<CommentAction key={index}
|
|
654
|
-
|
|
738
|
+
nodePath={menuPath}
|
|
655
739
|
node={node}
|
|
656
740
|
onClick={() => {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
741
|
+
node.run(
|
|
742
|
+
[...menuPath, menu.id], {
|
|
743
|
+
thread: commentThread,
|
|
660
744
|
text: getInput()
|
|
661
745
|
});
|
|
662
746
|
clearInput();
|
|
663
747
|
}}
|
|
748
|
+
commentThread={commentThread}
|
|
664
749
|
contextKeyService={contextKeyService}
|
|
750
|
+
commentsContext={commentsContext}
|
|
665
751
|
/>)}
|
|
666
752
|
</div>;
|
|
667
753
|
}
|
|
668
754
|
}
|
|
669
755
|
namespace CommentAction {
|
|
670
756
|
export interface Props {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
757
|
+
commentThread: CommentThread;
|
|
758
|
+
contextKeyService: ContextKeyService;
|
|
759
|
+
commentsContext: CommentsContext;
|
|
760
|
+
nodePath: MenuPath,
|
|
761
|
+
node: CommandMenu;
|
|
674
762
|
onClick: () => void;
|
|
675
763
|
}
|
|
676
764
|
}
|
|
@@ -678,11 +766,15 @@ namespace CommentAction {
|
|
|
678
766
|
export class CommentAction extends React.Component<CommentAction.Props> {
|
|
679
767
|
override render(): React.ReactNode {
|
|
680
768
|
const classNames = ['comments-button', 'comments-text-button', 'theia-button'];
|
|
681
|
-
const { node,
|
|
682
|
-
if (node.
|
|
769
|
+
const { node, nodePath, contextKeyService, onClick, commentThread } = this.props;
|
|
770
|
+
if (!node.isVisible(nodePath, contextKeyService, undefined, {
|
|
771
|
+
thread: commentThread
|
|
772
|
+
})) {
|
|
683
773
|
return false;
|
|
684
774
|
}
|
|
685
|
-
const isEnabled =
|
|
775
|
+
const isEnabled = node.isEnabled(nodePath, {
|
|
776
|
+
thread: commentThread
|
|
777
|
+
});
|
|
686
778
|
if (!isEnabled) {
|
|
687
779
|
classNames.push(DISABLED_CLASS);
|
|
688
780
|
}
|
|
@@ -16,16 +16,13 @@
|
|
|
16
16
|
|
|
17
17
|
import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
|
|
18
18
|
import { ContextKeyService, ContextKey } from '@theia/core/lib/browser/context-key-service';
|
|
19
|
-
import { Emitter } from '@theia/core/lib/common';
|
|
20
19
|
|
|
21
20
|
@injectable()
|
|
22
|
-
export class
|
|
21
|
+
export class CommentsContext {
|
|
23
22
|
|
|
24
23
|
@inject(ContextKeyService)
|
|
25
24
|
protected readonly contextKeyService: ContextKeyService;
|
|
26
25
|
protected readonly contextKeys: Set<string> = new Set();
|
|
27
|
-
protected readonly onDidChangeEmitter = new Emitter<void>();
|
|
28
|
-
readonly onDidChange = this.onDidChangeEmitter.event;
|
|
29
26
|
protected _commentIsEmpty: ContextKey<boolean>;
|
|
30
27
|
protected _commentController: ContextKey<string | undefined>;
|
|
31
28
|
protected _comment: ContextKey<string | undefined>;
|
|
@@ -48,21 +45,5 @@ export class CommentsContextKeyService {
|
|
|
48
45
|
this._commentController = this.contextKeyService.createKey<string | undefined>('commentController', undefined);
|
|
49
46
|
this._comment = this.contextKeyService.createKey<string | undefined>('comment', undefined);
|
|
50
47
|
this._commentIsEmpty = this.contextKeyService.createKey<boolean>('commentIsEmpty', true);
|
|
51
|
-
this.contextKeyService.onDidChange(event => {
|
|
52
|
-
if (event.affects(this.contextKeys)) {
|
|
53
|
-
this.onDidChangeEmitter.fire();
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
48
|
}
|
|
57
|
-
|
|
58
|
-
setExpression(expression: string): void {
|
|
59
|
-
this.contextKeyService.parseKeys(expression)?.forEach(key => {
|
|
60
|
-
this.contextKeys.add(key);
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
match(expression: string | undefined): boolean {
|
|
65
|
-
return !expression || this.contextKeyService.match(expression);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
49
|
}
|
|
@@ -24,9 +24,9 @@ import { CommentsService, CommentInfoMain } from './comments-service';
|
|
|
24
24
|
import { CommentThread } from '../../../common/plugin-api-rpc-model';
|
|
25
25
|
import { CommandRegistry, DisposableCollection, MenuModelRegistry } from '@theia/core/lib/common';
|
|
26
26
|
import { URI } from '@theia/core/shared/vscode-uri';
|
|
27
|
-
import { CommentsContextKeyService } from './comments-context-key-service';
|
|
28
27
|
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
|
|
29
28
|
import { Uri } from '@theia/plugin';
|
|
29
|
+
import { CommentsContext } from './comments-context';
|
|
30
30
|
|
|
31
31
|
/*---------------------------------------------------------------------------------------------
|
|
32
32
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -43,7 +43,7 @@ export class CommentsContribution {
|
|
|
43
43
|
private emptyThreadsToAddQueue: [number, EditorMouseEvent | undefined][] = [];
|
|
44
44
|
|
|
45
45
|
@inject(MenuModelRegistry) protected readonly menus: MenuModelRegistry;
|
|
46
|
-
@inject(
|
|
46
|
+
@inject(CommentsContext) protected readonly commentsContext: CommentsContext;
|
|
47
47
|
@inject(ContextKeyService) protected readonly contextKeyService: ContextKeyService;
|
|
48
48
|
@inject(CommandRegistry) protected readonly commands: CommandRegistry;
|
|
49
49
|
|
|
@@ -193,10 +193,10 @@ export class CommentsContribution {
|
|
|
193
193
|
if (editor) {
|
|
194
194
|
const provider = this.commentService.getCommentController(owner);
|
|
195
195
|
if (provider) {
|
|
196
|
-
this.
|
|
196
|
+
this.commentsContext.commentController.set(provider.id);
|
|
197
197
|
}
|
|
198
|
-
const zoneWidget = new CommentThreadWidget(editor, owner, thread, this.commentService, this.menus, this.
|
|
199
|
-
zoneWidget.display({ afterLineNumber: thread.range?.startLineNumber
|
|
198
|
+
const zoneWidget = new CommentThreadWidget(editor, owner, thread, this.commentService, this.menus, this.commentsContext, this.contextKeyService, this.commands);
|
|
199
|
+
zoneWidget.display({ afterLineNumber: thread.range?.startLineNumber || 0, heightInLines: 5 });
|
|
200
200
|
const currentEditor = this.getCurrentEditor();
|
|
201
201
|
if (currentEditor) {
|
|
202
202
|
currentEditor.onDispose(() => zoneWidget.dispose());
|
|
@@ -40,6 +40,7 @@ import { RPCProtocol } from '../../../common/rpc-protocol';
|
|
|
40
40
|
import { interfaces } from '@theia/core/shared/inversify';
|
|
41
41
|
import { generateUuid } from '@theia/core/lib/common/uuid';
|
|
42
42
|
import { CommentsContribution } from './comments-contribution';
|
|
43
|
+
import { CommentAuthorInformation } from '@theia/plugin';
|
|
43
44
|
|
|
44
45
|
/*---------------------------------------------------------------------------------------------
|
|
45
46
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
@@ -139,7 +140,7 @@ export class CommentThreadImpl implements CommentThread, Disposable {
|
|
|
139
140
|
private readonly onDidChangeStateEmitter = new Emitter<CommentThreadState | undefined>();
|
|
140
141
|
readonly onDidChangeState = this.onDidChangeStateEmitter.event;
|
|
141
142
|
|
|
142
|
-
private readonly onDidChangeCanReplyEmitter = new Emitter<boolean>();
|
|
143
|
+
private readonly onDidChangeCanReplyEmitter = new Emitter<boolean | CommentAuthorInformation>();
|
|
143
144
|
readonly onDidChangeCanReply = this.onDidChangeCanReplyEmitter.event;
|
|
144
145
|
|
|
145
146
|
private _isDisposed: boolean;
|
|
@@ -148,12 +149,12 @@ export class CommentThreadImpl implements CommentThread, Disposable {
|
|
|
148
149
|
return this._isDisposed;
|
|
149
150
|
}
|
|
150
151
|
|
|
151
|
-
private _canReply: boolean = true;
|
|
152
|
-
get canReply(): boolean {
|
|
152
|
+
private _canReply: boolean | CommentAuthorInformation = true;
|
|
153
|
+
get canReply(): boolean | CommentAuthorInformation {
|
|
153
154
|
return this._canReply;
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
set canReply(canReply: boolean) {
|
|
157
|
+
set canReply(canReply: boolean | CommentAuthorInformation) {
|
|
157
158
|
this._canReply = canReply;
|
|
158
159
|
this.onDidChangeCanReplyEmitter.fire(this._canReply);
|
|
159
160
|
}
|
|
@@ -54,7 +54,11 @@ export class CustomEditorOpener implements OpenHandler {
|
|
|
54
54
|
if (DiffUris.isDiffUri(uri)) {
|
|
55
55
|
const [left, right] = DiffUris.decode(uri);
|
|
56
56
|
if (this.matches(selector, right) && this.matches(selector, left)) {
|
|
57
|
-
|
|
57
|
+
if (getDefaultHandler(right, this.preferenceService) === this.editor.viewType) {
|
|
58
|
+
priority = defaultHandlerPriority;
|
|
59
|
+
} else {
|
|
60
|
+
priority = this.getPriority();
|
|
61
|
+
}
|
|
58
62
|
}
|
|
59
63
|
} else if (this.matches(selector, uri)) {
|
|
60
64
|
if (getDefaultHandler(uri, this.preferenceService) === this.editor.viewType) {
|