Skip to content

Commit

Permalink
Use widget life cycle
Browse files Browse the repository at this point in the history
  • Loading branch information
Frédéric Collonval committed Mar 2, 2021
1 parent 57d080e commit f5bd606
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 175 deletions.
6 changes: 3 additions & 3 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
- [x] Fix discussion on notebook
- Not all discussion are set in the UI
- [x] Fix using ref from commit sha rather than branch to ensure consistency when requesting file content and discussion
- [ ] Use Widget panel and handle life cycle for discussion
- [x] Use Widget panel and handle life cycle for discussion
- [ ] Fix styling
- [ ] Fix use effect on panel
- [ ] Fix notebooks
- Hide unchanged cells (and the comments structure)
- Support added and removed notebooks (currently JSON error as content on one side is "")
- [ ] Hide unchanged cells (and the comments structure)
- [x] Support added and removed notebooks (currently JSON error as content on one side is "")
- [x] Use codemirror as new comment editor
- [ ] Take advantage of builtin feature of MainAreaWidget (spinner)
- [ ] Simplify number of div to include add button on notebook (and to fix hiding it when unchanged cells are collapsed)
Expand Down
56 changes: 0 additions & 56 deletions src/components/PullRequestPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,60 +100,4 @@ export function PullRequestPanel(props: IPullRequestPanelProps): JSX.Element {
)}
</div>
);

// // Show tab window for specific PR
// // FIXME transform to command
// showTab = async (
// data: PullRequestFileModel | PullRequestModel
// ): Promise<void> => {
// let tab = this.getTab(data.id);
// if (tab === null) {
// if (data instanceof PullRequestFileModel) {
// tab = new MainAreaWidget<PullRequestTabWidget>({
// content: new PullRequestTabWidget(
// data,
// this._themeManager,
// this._renderMime
// )
// });
// tab.title.label = data.name;
// } else {
// tab = new MainAreaWidget<PullRequestDescriptionTab>({
// content: new PullRequestDescriptionTab({
// pr: data,
// renderMimeRegistry: this._renderMime
// })
// });
// tab.title.label = data.title;
// }
// tab.id = data.id;
// this._tabs.push(tab);
// }
// if (!tab.isAttached) {
// this._app.shell.add(tab, 'main');
// }
// tab.update();
// this._app.shell.activateById(tab.id);
// };

// private getTab(id: string): Widget | null {
// for (const tab of this._tabs) {
// if (tab.id.toString() === id.toString()) {
// return tab;
// }
// }
// return null;
// }

// getApp() {
// return this._app;
// }

// onUpdateRequest(): void {
// // FIXME - it is not working as expected
// this._browser.update();
// for (const tab of this._tabs) {
// tab.update();
// }
// }
}
126 changes: 39 additions & 87 deletions src/components/diff/CommentThread.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Widget } from '@lumino/widgets';
import { Panel, Widget } from '@lumino/widgets';
import { IComment, IThread } from '../../tokens';
import moment from 'moment';
import { generateNode, requestAPI } from '../../utils';
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { caretDownIcon, caretUpIcon } from '@jupyterlab/ui-components';
import { InputComment } from './InputComment';
import { showErrorMessage } from '@jupyterlab/apputils';
import { CommentWidget } from './CommentWidget';

/**
* CommentThread widget properties
Expand All @@ -28,7 +28,7 @@ export interface ICommentThreadProps {
/**
* CommentThread widget
*/
export class CommentThread extends Widget {
export class CommentThread extends Panel {
constructor(props: ICommentThreadProps) {
super();
this.addClass('jp-PullRequestCommentItem');
Expand All @@ -49,17 +49,20 @@ export class CommentThread extends Widget {
set isExpanded(v: boolean) {
if (this._isExpanded !== v) {
this._isExpanded = v;
// Keep the first widget aka the expand button
while (this.widgets.length > 1) {
const latestWidget = this.widgets[this.widgets.length - 1];
latestWidget.parent = null;
latestWidget.dispose();
}
if (this._isExpanded) {
this.addThreadView();
} else {
this._threadsContainer.textContent = '';
this._threadsContainer.appendChild(
generateNode(
'p',
null,
`${this._thread.comments[0].userName} ${this._thread.comments[0].text}`
)
);
const msg = this._thread.comments[0]
? `${this._thread.comments[0].userName} ${this._thread.comments[0].text}`
: 'Start a new discussion';
const node = generateNode('p', null, msg);
this.addWidget(new Widget({ node }));
}
}
}
Expand All @@ -73,76 +76,25 @@ export class CommentThread extends Widget {
set inputShown(v: boolean) {
if (this._inputShown !== v) {
this._inputShown = v;
this._threadsContainer.replaceChild(
this._inputShown ? this.createCommentInput() : this.createReplyButton(),
this._threadsContainer.lastChild
);
}
}

/**
* Create a comment HTML view
*
* @param comment Comment
* @param renderMime Rendermime registry
* @returns The HTML element
*/
protected static createCommentNode(
comment: IComment,
renderMime: IRenderMimeRegistry
): HTMLElement {
const head = generateNode('div', { class: 'jp-PullRequestCommentItem' });
head
.appendChild(
generateNode('div', { class: 'jp-PullRequestCommentItemImg' })
)
.appendChild(
generateNode('img', { src: comment.userPicture, altText: 'Avatar' })
);
const content = head.appendChild(
generateNode('div', { class: 'jp-PullRequestCommentItemContent' })
);
const div = content.appendChild(
generateNode('div', { class: 'jp-PullRequestCommentItemContentTitle' })
);
div.appendChild(generateNode('h2', null, comment.userName));
div.appendChild(
generateNode(
'p',
{ title: new Date(comment.updatedAt).toString() },
moment(comment.updatedAt).fromNow()
)
);

// Add rendered comment
const markdownRenderer = renderMime.createRenderer('text/markdown');
content.appendChild(markdownRenderer.node);
markdownRenderer.renderModel({
data: {
'text/markdown': comment.text
},
trusted: false,
metadata: {},
setData: () => null
});
const latestWidget = this.widgets[this.widgets.length - 1];
latestWidget.parent = null;
latestWidget.dispose();

return head;
this.addWidget(
this._inputShown ? this.createCommentInput() : this.createReplyButton()
);
}
}

/**
* Initialize the widget node
*/
protected initNode(): void {
const expandButton = generateNode('button') as HTMLButtonElement;
this.node
.appendChild(expandButton)
.appendChild(caretUpIcon.element({ tag: 'span' }));
expandButton.appendChild(caretUpIcon.element({ tag: 'span' }));
this.addWidget(new Widget({ node: expandButton }));

this._threadsContainer = generateNode('div', {
class: 'jp-PullRequestComments'
}) as HTMLDivElement;

this.node.appendChild(this._threadsContainer);
this.addThreadView();

// Add event
Expand All @@ -161,16 +113,13 @@ export class CommentThread extends Widget {
* Add the thread view in the widget
*/
protected addThreadView(): void {
this._threadsContainer.textContent = '';
this._thread.comments.forEach(comment => {
this._threadsContainer.appendChild(
CommentThread.createCommentNode(comment, this._renderMime)
);
this.addWidget(new CommentWidget(comment, this._renderMime));
});
if (this._inputShown) {
this._threadsContainer.appendChild(this.createCommentInput());
this.addWidget(this.createCommentInput());
} else {
this._threadsContainer.appendChild(this.createReplyButton());
this.addWidget(this.createReplyButton());
}
}

Expand Down Expand Up @@ -213,12 +162,13 @@ export class CommentThread extends Widget {
}
this._thread.comments.push(comment);

this._threadsContainer.replaceChild(
CommentThread.createCommentNode(comment, this._renderMime),
this._threadsContainer.lastChild
);
const latestWidget = this.widgets[this.widgets.length - 1];
latestWidget.parent = null;
latestWidget.dispose();

this.addWidget(new CommentWidget(comment, this._renderMime));
this._inputShown = false;
this._threadsContainer.appendChild(this.createReplyButton());
this.addWidget(this.createReplyButton());
} catch (reason) {
console.error(reason);
showErrorMessage('Error', 'Failed to add the comment.');
Expand All @@ -238,25 +188,27 @@ export class CommentThread extends Widget {
}
}

private createCommentInput(): HTMLElement {
private createCommentInput(): InputComment {
return new InputComment({
handleSubmit: this.handleAddComment.bind(this),
handleCancel: this.handleCancelComment.bind(this)
}).node;
});
}

private createReplyButton(): HTMLElement {
return generateNode('button', { class: '' }, 'Reply...', {
private createReplyButton(): Widget {
const node = generateNode('button', { class: '' }, 'Reply...', {
click: () => {
this.inputShown = true;
}
});
return new Widget({
node
});
}

private _handleRemove: () => void;
private _inputShown: boolean;
private _isExpanded = true;
private _renderMime: IRenderMimeRegistry;
private _thread: IThread;
private _threadsContainer: HTMLDivElement;
}
66 changes: 66 additions & 0 deletions src/components/diff/CommentWidget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { IRenderMime, IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { Widget } from '@lumino/widgets';
import moment from 'moment';
import { IComment } from '../../tokens';
import { generateNode } from '../../utils';

export class CommentWidget extends Widget {
constructor(comment: IComment, renderMime: IRenderMimeRegistry) {
const markdownRenderer = renderMime.createRenderer('text/markdown');
super({
node: CommentWidget.createNode(comment, markdownRenderer)
});
this._markdownRenderer = markdownRenderer;
this._markdownRenderer.renderModel({
data: {
'text/markdown': comment.text
},
trusted: false,
metadata: {},
setData: () => null
});
}

protected static createNode(
comment: IComment,
markdownRenderer: IRenderMime.IRenderer
): HTMLElement {
const head = generateNode('div', { class: 'jp-PullRequestCommentItem' });
head
.appendChild(
generateNode('div', { class: 'jp-PullRequestCommentItemImg' })
)
.appendChild(
generateNode('img', { src: comment.userPicture, altText: 'Avatar' })
);
const content = head.appendChild(
generateNode('div', { class: 'jp-PullRequestCommentItemContent' })
);
const div = content.appendChild(
generateNode('div', { class: 'jp-PullRequestCommentItemContentTitle' })
);
div.appendChild(generateNode('h2', null, comment.userName));
div.appendChild(
generateNode(
'p',
{ title: new Date(comment.updatedAt).toString() },
moment(comment.updatedAt).fromNow()
)
);

// Add rendered comment
content.appendChild(markdownRenderer.node);

return head;
}

dispose(): void {
if (this.isDisposed) {
return;
}
this._markdownRenderer.dispose();
super.dispose();
}

protected _markdownRenderer: IRenderMime.IRenderer;
}
Loading

0 comments on commit f5bd606

Please sign in to comment.