From 68557ab7f5f616c3a8b97f96aca4285c66236add Mon Sep 17 00:00:00 2001 From: Corentin Mors Date: Mon, 4 May 2020 08:42:33 +0200 Subject: [PATCH 1/2] WIP: Implement comment notifications --- src/background/index.ts | 82 +++++++++++++++++++++++---- src/background/types.ts | 34 ++++++++++- src/popup/App.tsx | 14 ++--- src/popup/components/MergeRequest.tsx | 8 ++- src/popup/helpers.ts | 2 +- 5 files changed, 117 insertions(+), 23 deletions(-) diff --git a/src/background/index.ts b/src/background/index.ts index f8bb4c7..5e0c458 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -3,26 +3,18 @@ import { browser } from 'webextension-polyfill-ts'; import { Gitlab } from 'gitlab'; // All Resources import { getSettings } from './utils/getSettings'; import { fetchMRExtraInfo } from './utils/fetchMRExtraInfo'; -import { MergeRequests, GetSettingsResponse, MergeRequestsDetails } from './types'; +import { MergeRequests, GetSettingsResponse, ReviewRequests, ReviewGiven, StoredData, ReviewChanges } from './types'; let ERROR_TRACKER: Error | null; const pollMR = (cb: Callback) => { - interface ReviewRequests { - mrAssigned: MergeRequestsDetails[]; - mrToReview: number; - } - - interface ReviewGiven { - mrGiven: MergeRequestsDetails[]; - mrReviewed: number; - } - interface AsyncResults { getSettings: GetSettingsResponse; gitlabApi: Gitlab; reviewRequests: ReviewRequests; givenRequests: ReviewGiven; + getStoredData: StoredData; + computeChanges: ReviewChanges; saveLocalStorage: void; } @@ -142,12 +134,70 @@ const pollMR = (cb: Callback) => { }); } ], + getStoredData: [ + 'reviewRequests', + 'givenRequests', + (_results, cb) => { + browser.storage.local + .get(['mrAssigned', 'mrGiven', 'mrToReview', 'mrReviewed', 'reviewChanges']) + .then((data) => cb(null, data as StoredData)) + .catch((error) => cb(error)); + } + ], + computeChanges: [ + 'reviewRequests', + 'givenRequests', + 'getStoredData', + (results, cb) => { + /** Get all comments (stored and received) */ + const storedCommentsAssigned = results.getStoredData.mrAssigned.flatMap((mr) => mr.comments); + const storedCommentsGiven = results.getStoredData.mrGiven.flatMap((mr) => mr.comments); + + const receivedCommentsAssigned = results.reviewRequests.mrAssigned.flatMap((mr) => mr.comments); + const receivedCommentsGiven = results.givenRequests.mrGiven.flatMap((mr) => mr.comments); + + /** Filter only new comments */ + const newCommentsAssigned = receivedCommentsAssigned + .filter((comment) => !storedCommentsAssigned.some((y) => comment.id === y.id)) + .concat(results.getStoredData.reviewChanges?.newCommentsAssigned); + + const newCommentsGiven = receivedCommentsGiven + .filter((comment) => !storedCommentsGiven.some((y) => comment.id === y.id)) + .concat(results.getStoredData.reviewChanges?.newCommentsGiven); + + /** Filter only new comments tagging user */ + const ownerName = 'username'; // to be changed + const PATTERN = new RegExp(`@${ownerName}`); + const receivedCommentsAssignedTagged = receivedCommentsAssigned.filter((comment) => + PATTERN.test(comment.body) + ); + const newCommentsGivenTagged = newCommentsGiven.filter((comment) => PATTERN.test(comment.body)); + + console.log(receivedCommentsAssignedTagged, newCommentsGivenTagged); + + /** Prepare notification (?) */ + // TBD + + /** Send result */ + const computedChanges = { + newCommentsAssigned, + newCommentsGiven, + notifications: [] + }; + + // console.log(computedChanges); + + return cb(null, computedChanges); + } + ], saveLocalStorage: [ 'reviewRequests', 'givenRequests', + 'computeChanges', (results, cb) => { const { mrAssigned, mrToReview } = results.reviewRequests; const { mrGiven, mrReviewed } = results.givenRequests; + const reviewChanges = results.computeChanges; const lastUpdateDateUnix = new Date().getTime(); browser.storage.local @@ -156,6 +206,7 @@ const pollMR = (cb: Callback) => { mrToReview, mrGiven, mrReviewed, + reviewChanges, lastUpdateDateUnix }) .then(() => cb()) @@ -189,7 +240,14 @@ browser.runtime.onMessage.addListener((message) => { } return Promise.resolve( - browser.storage.local.get(['mrAssigned', 'mrGiven', 'mrToReview', 'mrReviewed', 'lastUpdateDateUnix']) + browser.storage.local.get([ + 'mrAssigned', + 'mrGiven', + 'mrToReview', + 'mrReviewed', + 'reviewChanges', + 'lastUpdateDateUnix' + ]) ); } diff --git a/src/background/types.ts b/src/background/types.ts index d0763db..97d545c 100644 --- a/src/background/types.ts +++ b/src/background/types.ts @@ -4,7 +4,7 @@ export interface MergeRequests { title: string; description: string; project_id: number; - created_at: number; + created_at: string; source_branch: string; merge_status: string; web_url: string; @@ -37,10 +37,42 @@ export interface User { } export interface Comment { + id: number; + created_at: string; + updated_at: string; system: boolean; + author: User; + body: string; + noteable_id: number; + noteable_idd: number; + // missing types here +} + +export interface Notification { + content: string; } export interface GetSettingsResponse { token: string; address: string; } + +export interface ReviewRequests { + mrAssigned: MergeRequestsDetails[]; + mrToReview: number; +} + +export interface ReviewGiven { + mrGiven: MergeRequestsDetails[]; + mrReviewed: number; +} + +export interface ReviewChanges { + newCommentsAssigned: Comment[]; + newCommentsGiven: Comment[]; + notifications: Notification[]; +} + +export interface StoredData extends ReviewRequests, ReviewGiven { + reviewChanges: ReviewChanges; +} diff --git a/src/popup/App.tsx b/src/popup/App.tsx index d20be34..1337c8d 100644 --- a/src/popup/App.tsx +++ b/src/popup/App.tsx @@ -18,7 +18,7 @@ import Octicon, { Sync, Gear } from '@primer/octicons-react'; import { MergeRequest } from './components/MergeRequest'; import emptyInbox from './assets/empty_inbox.svg'; import './style.css'; -import { MergeRequestsDetails } from '../background/types'; +import { MergeRequestsDetails, StoredData, Comment } from '../background/types'; import { getHumanReadableDate } from './helpers'; const App = () => { @@ -35,11 +35,7 @@ const App = () => { let type = 'getMRs'; - interface SendMsgResponse { - mrAssigned: MergeRequestsDetails[]; - mrToReview: number; - mrGiven: MergeRequestsDetails[]; - mrReviewed: number; + interface SendMsgResponse extends StoredData { lastUpdateDateUnix: number; } interface SendMsgError { @@ -68,10 +64,13 @@ const App = () => { } let mrNewList: MergeRequestsDetails[]; + let commentsNewList: Comment[]; if (type === 'getMRs') { mrNewList = response.mrAssigned; + commentsNewList = response.reviewChanges.newCommentsAssigned; } else { mrNewList = response.mrGiven; + commentsNewList = response.reviewChanges.newCommentsGiven; } console.log('Displayed list', mrNewList); @@ -79,7 +78,8 @@ const App = () => { updateList(); } else { const listItems = mrNewList.map((mr) => { - return ; + const comments = commentsNewList.filter((comment) => comment.noteable_id === mr.id); + return ; }); updateList({listItems}); diff --git a/src/popup/components/MergeRequest.tsx b/src/popup/components/MergeRequest.tsx index 40fbd30..ce1ca12 100644 --- a/src/popup/components/MergeRequest.tsx +++ b/src/popup/components/MergeRequest.tsx @@ -3,14 +3,17 @@ import { BranchName, FilterList, Flex, Box, Link, Label } from '@primer/componen import Octicon, { GitMerge, IssueClosed, IssueOpened, Clock, CommentDiscussion } from '@primer/octicons-react'; import { Avatars } from './Avatars'; import { calculateTimeElapsed } from '../helpers'; -import { MergeRequestsDetails } from '../../background/types'; +import { MergeRequestsDetails, Comment } from '../../background/types'; interface Props { mr: MergeRequestsDetails; + comments: Comment[]; } export const MergeRequest = (props: Props) => { const mr = props.mr; + const newCommentsCount = props.comments.length; + const hasNewComments = newCommentsCount > 0; let mrApproved = false; if (mr.approvals.user_has_approved) { @@ -50,7 +53,8 @@ export const MergeRequest = (props: Props) => { )}