diff --git a/server/plugin/api.go b/server/plugin/api.go index 3ef3eda4f..97857fa0a 100644 --- a/server/plugin/api.go +++ b/server/plugin/api.go @@ -56,6 +56,18 @@ type PRDetails struct { Reviews []*github.PullRequestReview `json:"reviews"` } +type FilteredNotification struct { + github.Notification + HTMLURL string `json:"html_url"` +} + +type SidebarContent struct { + Reviews []*github.Issue `json:"reviews"` + PRs []*github.Issue `json:"prs"` + Assignments []*github.Issue `json:"assignments"` + Unreads []*FilteredNotification `json:"unreads"` +} + type Context struct { Ctx context.Context UserID string @@ -133,15 +145,11 @@ func (p *Plugin) initializeAPI() { apiRouter.HandleFunc("/user", p.checkAuth(p.attachContext(p.getGitHubUser), ResponseTypeJSON)).Methods(http.MethodPost) apiRouter.HandleFunc("/todo", p.checkAuth(p.attachUserContext(p.postToDo), ResponseTypeJSON)).Methods(http.MethodPost) - apiRouter.HandleFunc("/reviews", p.checkAuth(p.attachUserContext(p.getReviews), ResponseTypePlain)).Methods(http.MethodGet) - apiRouter.HandleFunc("/yourprs", p.checkAuth(p.attachUserContext(p.getYourPrs), ResponseTypePlain)).Methods(http.MethodGet) apiRouter.HandleFunc("/prsdetails", p.checkAuth(p.attachUserContext(p.getPrsDetails), ResponseTypePlain)).Methods(http.MethodPost) apiRouter.HandleFunc("/searchissues", p.checkAuth(p.attachUserContext(p.searchIssues), ResponseTypePlain)).Methods(http.MethodGet) - apiRouter.HandleFunc("/yourassignments", p.checkAuth(p.attachUserContext(p.getYourAssignments), ResponseTypePlain)).Methods(http.MethodGet) apiRouter.HandleFunc("/createissue", p.checkAuth(p.attachUserContext(p.createIssue), ResponseTypePlain)).Methods(http.MethodPost) apiRouter.HandleFunc("/createissuecomment", p.checkAuth(p.attachUserContext(p.createIssueComment), ResponseTypePlain)).Methods(http.MethodPost) apiRouter.HandleFunc("/mentions", p.checkAuth(p.attachUserContext(p.getMentions), ResponseTypePlain)).Methods(http.MethodGet) - apiRouter.HandleFunc("/unreads", p.checkAuth(p.attachUserContext(p.getUnreads), ResponseTypePlain)).Methods(http.MethodGet) apiRouter.HandleFunc("/labels", p.checkAuth(p.attachUserContext(p.getLabels), ResponseTypePlain)).Methods(http.MethodGet) apiRouter.HandleFunc("/milestones", p.checkAuth(p.attachUserContext(p.getMilestones), ResponseTypePlain)).Methods(http.MethodGet) apiRouter.HandleFunc("/assignees", p.checkAuth(p.attachUserContext(p.getAssignees), ResponseTypePlain)).Methods(http.MethodGet) @@ -149,6 +157,7 @@ func (p *Plugin) initializeAPI() { apiRouter.HandleFunc("/settings", p.checkAuth(p.attachUserContext(p.updateSettings), ResponseTypePlain)).Methods(http.MethodPost) apiRouter.HandleFunc("/issue", p.checkAuth(p.attachUserContext(p.getIssueByNumber), ResponseTypePlain)).Methods(http.MethodGet) apiRouter.HandleFunc("/pr", p.checkAuth(p.attachUserContext(p.getPrByNumber), ResponseTypePlain)).Methods(http.MethodGet) + apiRouter.HandleFunc("/sidebar-content", p.checkAuth(p.attachUserContext(p.getSidebarContent), ResponseTypePlain)).Methods(http.MethodGet) apiRouter.HandleFunc("/config", checkPluginRequest(p.getConfig)).Methods(http.MethodGet) apiRouter.HandleFunc("/token", checkPluginRequest(p.getToken)).Methods(http.MethodGet) @@ -658,22 +667,16 @@ func (p *Plugin) getMentions(c *UserContext, w http.ResponseWriter, r *http.Requ p.writeJSON(w, result.Issues) } -func (p *Plugin) getUnreads(c *UserContext, w http.ResponseWriter, r *http.Request) { +func (p *Plugin) getUnreadsData(c *UserContext) []*FilteredNotification { githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo) notifications, _, err := githubClient.Activity.ListNotifications(c.Ctx, &github.NotificationListOptions{}) if err != nil { c.Log.WithError(err).Warnf("Failed to list notifications") - return + return nil } - type filteredNotification struct { - github.Notification - - HTMLUrl string `json:"html_url"` - } - - filteredNotifications := []*filteredNotification{} + filteredNotifications := []*FilteredNotification{} for _, n := range notifications { if n.GetReason() == notificationReasonSubscribed { continue @@ -691,16 +694,16 @@ func (p *Plugin) getUnreads(c *UserContext, w http.ResponseWriter, r *http.Reque subjectURL = n.GetSubject().GetLatestCommentURL() } - filteredNotifications = append(filteredNotifications, &filteredNotification{ + filteredNotifications = append(filteredNotifications, &FilteredNotification{ Notification: *n, - HTMLUrl: fixGithubNotificationSubjectURL(subjectURL, issueNum), + HTMLURL: fixGithubNotificationSubjectURL(subjectURL, issueNum), }) } - p.writeJSON(w, filteredNotifications) + return filteredNotifications } -func (p *Plugin) getReviews(c *UserContext, w http.ResponseWriter, r *http.Request) { +func (p *Plugin) getReviewsData(c *UserContext) []*github.Issue { config := p.getConfiguration() githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo) @@ -710,13 +713,13 @@ func (p *Plugin) getReviews(c *UserContext, w http.ResponseWriter, r *http.Reque result, _, err := githubClient.Search.Issues(c.Ctx, query, &github.SearchOptions{}) if err != nil { c.Log.WithError(err).With(logger.LogContext{"query": query}).Warnf("Failed to search for review") - return + return nil } - p.writeJSON(w, result.Issues) + return result.Issues } -func (p *Plugin) getYourPrs(c *UserContext, w http.ResponseWriter, r *http.Request) { +func (p *Plugin) getYourPrsData(c *UserContext) []*github.Issue { config := p.getConfiguration() githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo) @@ -726,10 +729,10 @@ func (p *Plugin) getYourPrs(c *UserContext, w http.ResponseWriter, r *http.Reque result, _, err := githubClient.Search.Issues(c.Ctx, query, &github.SearchOptions{}) if err != nil { c.Log.WithError(err).With(logger.LogContext{"query": query}).Warnf("Failed to search for PRs") - return + return nil } - p.writeJSON(w, result.Issues) + return result.Issues } func (p *Plugin) getPrsDetails(c *UserContext, w http.ResponseWriter, r *http.Request) { @@ -974,7 +977,7 @@ func (p *Plugin) createIssueComment(c *UserContext, w http.ResponseWriter, r *ht p.writeJSON(w, result) } -func (p *Plugin) getYourAssignments(c *UserContext, w http.ResponseWriter, r *http.Request) { +func (p *Plugin) getYourAssignmentsData(c *UserContext) []*github.Issue { config := p.getConfiguration() githubClient := p.githubConnectUser(c.Context.Ctx, c.GHInfo) @@ -984,10 +987,24 @@ func (p *Plugin) getYourAssignments(c *UserContext, w http.ResponseWriter, r *ht result, _, err := githubClient.Search.Issues(c.Ctx, query, &github.SearchOptions{}) if err != nil { c.Log.WithError(err).With(logger.LogContext{"query": query}).Warnf("Failed to search for assignments") - return + return nil } - p.writeJSON(w, result.Issues) + return result.Issues +} + +func (p *Plugin) getSidebarData(c *UserContext) *SidebarContent { + return &SidebarContent{ + Assignments: p.getYourAssignmentsData(c), + PRs: p.getYourPrsData(c), + Reviews: p.getReviewsData(c), + Unreads: p.getUnreadsData(c), + } +} + +func (p *Plugin) getSidebarContent(c *UserContext, w http.ResponseWriter, r *http.Request) { + sidebarContent := p.getSidebarData(c) + p.writeJSON(w, sidebarContent) } func (p *Plugin) postToDo(c *UserContext, w http.ResponseWriter, r *http.Request) { diff --git a/server/plugin/api_test.go b/server/plugin/api_test.go index 8aaa5bd89..a6e932dd5 100644 --- a/server/plugin/api_test.go +++ b/server/plugin/api_test.go @@ -86,7 +86,7 @@ func TestPlugin_ServeHTTP(t *testing.T) { httpTest: httpTestString, request: testutils.Request{ Method: http.MethodGet, - URL: "/api/v1/reviews", + URL: "/api/v1/sidebar-content", Body: nil, }, expectedResponse: testutils.ExpectedResponse{ diff --git a/server/plugin/plugin.go b/server/plugin/plugin.go index 5dc367947..107592d0e 100644 --- a/server/plugin/plugin.go +++ b/server/plugin/plugin.go @@ -15,6 +15,7 @@ import ( "github.com/google/go-github/v41/github" "github.com/gorilla/mux" pluginapi "github.com/mattermost/mattermost-plugin-api" + "github.com/mattermost/mattermost-plugin-api/experimental/bot/logger" "github.com/mattermost/mattermost-plugin-api/experimental/bot/poster" "github.com/mattermost/mattermost-plugin-api/experimental/telemetry" "github.com/mattermost/mattermost-server/v6/model" @@ -783,13 +784,64 @@ func (p *Plugin) isOrganizationLocked() bool { } func (p *Plugin) sendRefreshEvent(userID string) { + eventLogger := logger.New(p.API).With(logger.LogContext{ + "userid": userID, + }) + + ctx, cancel := context.WithTimeout(context.Background(), requestTimeout) + + context := &Context{ + Ctx: ctx, + UserID: userID, + Log: eventLogger, + } + + defer cancel() + + info, apiErr := p.getGitHubUserInfo(context.UserID) + if apiErr != nil { + p.API.LogWarn("Failed to get github user info", "error", apiErr.Error()) + return + } + + context.Log = context.Log.With(logger.LogContext{ + "github username": info.GitHubUsername, + }) + + userContext := &UserContext{ + Context: *context, + GHInfo: info, + } + + sidebarContent := p.getSidebarData(userContext) + + contentMap, err := convertContentToMap(sidebarContent) + if err != nil { + p.API.LogWarn("Failed to convert sidebar content to map", "error", apiErr.Error()) + return + } + p.API.PublishWebSocketEvent( wsEventRefresh, - nil, + contentMap, &model.WebsocketBroadcast{UserId: userID}, ) } +func convertContentToMap(sidebarContent *SidebarContent) (map[string]interface{}, error) { + var m map[string]interface{} + bytes, err := json.Marshal(&sidebarContent) + if err != nil { + return nil, err + } + + if err = json.Unmarshal(bytes, &m); err != nil { + return nil, err + } + + return m, nil +} + // getUsername returns the GitHub username for a given Mattermost user, // if the user is connected to GitHub via this plugin. // Otherwise it return the Mattermost username. It will be escaped via backticks. diff --git a/webapp/src/action_types/index.js b/webapp/src/action_types/index.js index 88da0997b..f2e9d307f 100644 --- a/webapp/src/action_types/index.js +++ b/webapp/src/action_types/index.js @@ -5,13 +5,9 @@ import {id as pluginId} from '../manifest'; export default { RECEIVED_REPOSITORIES: pluginId + '_received_repositories', - RECEIVED_REVIEWS: pluginId + '_received_reviews', RECEIVED_REVIEWS_DETAILS: pluginId + '_received_reviews_details', - RECEIVED_YOUR_PRS: pluginId + '_received_your_prs', RECEIVED_YOUR_PRS_DETAILS: pluginId + '_received_your_prs_details', - RECEIVED_YOUR_ASSIGNMENTS: pluginId + '_received_your_assignments', RECEIVED_MENTIONS: pluginId + '_received_mentions', - RECEIVED_UNREADS: pluginId + '_received_unreads', RECEIVED_CONNECTED: pluginId + '_received_connected', RECEIVED_CONFIGURATION: pluginId + '_received_configuration', RECEIVED_GITHUB_USER: pluginId + '_received_github_user', @@ -23,4 +19,5 @@ export default { CLOSE_ATTACH_COMMENT_TO_ISSUE_MODAL: pluginId + '_close_attach_modal', OPEN_ATTACH_COMMENT_TO_ISSUE_MODAL: pluginId + '_open_attach_modal', RECEIVED_ATTACH_COMMENT_RESULT: pluginId + '_received_attach_comment', + RECEIVED_SIDEBAR_CONTENT: pluginId + '_received_sidebar_content', }; diff --git a/webapp/src/actions/index.js b/webapp/src/actions/index.js index 1788ae959..16998eccb 100644 --- a/webapp/src/actions/index.js +++ b/webapp/src/actions/index.js @@ -42,29 +42,6 @@ function checkAndHandleNotConnected(data) { }; } -export function getReviews() { - return async (dispatch, getState) => { - let data; - try { - data = await Client.getReviews(); - } catch (error) { - return {error}; - } - - const connected = await checkAndHandleNotConnected(data)(dispatch, getState); - if (!connected) { - return {error: data}; - } - - dispatch({ - type: ActionTypes.RECEIVED_REVIEWS, - data, - }); - - return {data}; - }; -} - export function getReviewsDetails(prList) { return async (dispatch, getState) => { let data; @@ -111,11 +88,11 @@ export function getRepos() { }; } -export function getYourPrs() { +export function getSidebarContent() { return async (dispatch, getState) => { let data; try { - data = await Client.getYourPrs(); + data = await Client.getSidebarContent(); } catch (error) { return {error}; } @@ -126,7 +103,7 @@ export function getYourPrs() { } dispatch({ - type: ActionTypes.RECEIVED_YOUR_PRS, + type: ActionTypes.RECEIVED_SIDEBAR_CONTENT, data, }); @@ -211,29 +188,6 @@ export function getMilestoneOptions(repo) { }; } -export function getYourAssignments() { - return async (dispatch, getState) => { - let data; - try { - data = await Client.getYourAssignments(); - } catch (error) { - return {error}; - } - - const connected = await checkAndHandleNotConnected(data)(dispatch, getState); - if (!connected) { - return {error: data}; - } - - dispatch({ - type: ActionTypes.RECEIVED_YOUR_ASSIGNMENTS, - data, - }); - - return {data}; - }; -} - export function getMentions() { return async (dispatch, getState) => { let data; @@ -257,29 +211,6 @@ export function getMentions() { }; } -export function getUnreads() { - return async (dispatch, getState) => { - let data; - try { - data = await Client.getUnreads(); - } catch (error) { - return {error}; - } - - const connected = await checkAndHandleNotConnected(data)(dispatch, getState); - if (!connected) { - return {error: data}; - } - - dispatch({ - type: ActionTypes.RECEIVED_UNREADS, - data, - }); - - return {data}; - }; -} - const GITHUB_USER_GET_TIMEOUT_MILLISECONDS = 1000 * 60 * 60; // 1 hour export function getGitHubUser(userID) { diff --git a/webapp/src/client/client.js b/webapp/src/client/client.js index 25d6f3f9c..06f09b78a 100644 --- a/webapp/src/client/client.js +++ b/webapp/src/client/client.js @@ -15,30 +15,16 @@ export default class Client { return this.doGet(`${this.url}/connected?reminder=${reminder}`); } - getReviews = async () => { - return this.doGet(`${this.url}/reviews`); - } - - getYourPrs = async () => { - return this.doGet(`${this.url}/yourprs`); - } + getSidebarContent = async () => this.doGet(`${this.url}/sidebar-content`); getPrsDetails = async (prList) => { return this.doPost(`${this.url}/prsdetails`, prList); } - getYourAssignments = async () => { - return this.doGet(`${this.url}/yourassignments`); - } - getMentions = async () => { return this.doGet(`${this.url}/mentions`); } - getUnreads = async () => { - return this.doGet(`${this.url}/unreads`); - } - getGitHubUser = async (userID) => { return this.doPost(`${this.url}/user`, {user_id: userID}); } diff --git a/webapp/src/components/sidebar_buttons/index.js b/webapp/src/components/sidebar_buttons/index.js index 0ebdff14f..862a1d02c 100644 --- a/webapp/src/components/sidebar_buttons/index.js +++ b/webapp/src/components/sidebar_buttons/index.js @@ -4,7 +4,7 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; -import {getConnected, getReviews, getUnreads, getYourAssignments, getYourPrs, updateRhsState} from '../../actions'; +import {getConnected, updateRhsState, getSidebarContent} from '../../actions'; import {id as pluginId} from '../../manifest'; @@ -14,10 +14,10 @@ function mapStateToProps(state) { return { connected: state[`plugins-${pluginId}`].connected, clientId: state[`plugins-${pluginId}`].clientId, - reviews: state[`plugins-${pluginId}`].reviews, - yourPrs: state[`plugins-${pluginId}`].yourPrs, - yourAssignments: state[`plugins-${pluginId}`].yourAssignments, - unreads: state[`plugins-${pluginId}`].unreads, + reviews: state[`plugins-${pluginId}`].sidebarContent.reviews, + yourPrs: state[`plugins-${pluginId}`].sidebarContent.prs, + yourAssignments: state[`plugins-${pluginId}`].sidebarContent.assignments, + unreads: state[`plugins-${pluginId}`].sidebarContent.unreads, enterpriseURL: state[`plugins-${pluginId}`].enterpriseURL, showRHSPlugin: state[`plugins-${pluginId}`].rhsPluginAction, }; @@ -27,11 +27,8 @@ function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ getConnected, - getReviews, - getUnreads, - getYourPrs, - getYourAssignments, updateRhsState, + getSidebarContent, }, dispatch), }; } diff --git a/webapp/src/components/sidebar_buttons/sidebar_buttons.jsx b/webapp/src/components/sidebar_buttons/sidebar_buttons.jsx index 9b4c8ed9b..1601b5f31 100644 --- a/webapp/src/components/sidebar_buttons/sidebar_buttons.jsx +++ b/webapp/src/components/sidebar_buttons/sidebar_buttons.jsx @@ -22,10 +22,7 @@ export default class SidebarButtons extends React.PureComponent { showRHSPlugin: PropTypes.func.isRequired, actions: PropTypes.shape({ getConnected: PropTypes.func.isRequired, - getReviews: PropTypes.func.isRequired, - getUnreads: PropTypes.func.isRequired, - getYourPrs: PropTypes.func.isRequired, - getYourAssignments: PropTypes.func.isRequired, + getSidebarContent: PropTypes.func.isRequired, updateRhsState: PropTypes.func.isRequired, }).isRequired, }; @@ -64,10 +61,7 @@ export default class SidebarButtons extends React.PureComponent { this.setState({refreshing: true}); await Promise.all([ - this.props.actions.getReviews(), - this.props.actions.getUnreads(), - this.props.actions.getYourPrs(), - this.props.actions.getYourAssignments(), + this.props.actions.getSidebarContent(), ]); this.setState({refreshing: false}); } diff --git a/webapp/src/components/sidebar_right/index.jsx b/webapp/src/components/sidebar_right/index.jsx index 746b27bed..a2f41ea3b 100644 --- a/webapp/src/components/sidebar_right/index.jsx +++ b/webapp/src/components/sidebar_right/index.jsx @@ -38,10 +38,10 @@ function mapPrsToDetails(prs, details) { function mapStateToProps(state) { return { username: state[`plugins-${pluginId}`].username, - reviews: mapPrsToDetails(state[`plugins-${pluginId}`].reviews, state[`plugins-${pluginId}`].reviewsDetails), - yourPrs: mapPrsToDetails(state[`plugins-${pluginId}`].yourPrs, state[`plugins-${pluginId}`].yourPrsDetails), - yourAssignments: state[`plugins-${pluginId}`].yourAssignments, - unreads: state[`plugins-${pluginId}`].unreads, + reviews: mapPrsToDetails(state[`plugins-${pluginId}`].sidebarContent.reviews, state[`plugins-${pluginId}`].reviewsDetails), + yourPrs: mapPrsToDetails(state[`plugins-${pluginId}`].sidebarContent.prs, state[`plugins-${pluginId}`].yourPrsDetails), + yourAssignments: state[`plugins-${pluginId}`].sidebarContent.assignments, + unreads: state[`plugins-${pluginId}`].sidebarContent.unreads, enterpriseURL: state[`plugins-${pluginId}`].enterpriseURL, org: state[`plugins-${pluginId}`].organization, rhsState: state[`plugins-${pluginId}`].rhsState, diff --git a/webapp/src/components/sidebar_right/sidebar_right.jsx b/webapp/src/components/sidebar_right/sidebar_right.jsx index 162efdf00..9af17b5a3 100644 --- a/webapp/src/components/sidebar_right/sidebar_right.jsx +++ b/webapp/src/components/sidebar_right/sidebar_right.jsx @@ -111,27 +111,27 @@ export default class SidebarRight extends React.PureComponent { switch (this.props.rhsState) { case RHSStates.PRS: - githubItems = this.props.yourPrs; + githubItems = this.props.yourPrs || []; title = 'Your Open Pull Requests'; listUrl = baseURL + '/pulls?q=is%3Aopen+is%3Apr+author%3A' + this.props.username + '+archived%3Afalse' + orgQuery; break; case RHSStates.REVIEWS: - githubItems = this.props.reviews; + githubItems = this.props.reviews || []; listUrl = baseURL + '/pulls?q=is%3Aopen+is%3Apr+review-requested%3A' + this.props.username + '+archived%3Afalse' + orgQuery; title = 'Pull Requests Needing Review'; break; case RHSStates.UNREADS: - githubItems = this.props.unreads; + githubItems = this.props.unreads || []; title = 'Unread Messages'; listUrl = baseURL + '/notifications'; break; case RHSStates.ASSIGNMENTS: - githubItems = this.props.yourAssignments; + githubItems = this.props.yourAssignments || []; title = 'Your Assignments'; listUrl = baseURL + '/pulls?q=is%3Aopen+archived%3Afalse+assignee%3A' + this.props.username + orgQuery; break; diff --git a/webapp/src/constants/index.js b/webapp/src/constants/index.js index c51ee9128..36c127c79 100644 --- a/webapp/src/constants/index.js +++ b/webapp/src/constants/index.js @@ -11,3 +11,8 @@ export const RHSStates = { UNREADS: 'unreads', ASSIGNMENTS: 'assignments', }; + +export const JitterForReconnectAPICall = { + MAX_TIME_IN_SEC: 1, + MIN_TIME_IN_SEC: 10, +}; diff --git a/webapp/src/reducers/index.js b/webapp/src/reducers/index.js index 0ebcf5192..815d7ee63 100644 --- a/webapp/src/reducers/index.js +++ b/webapp/src/reducers/index.js @@ -77,15 +77,6 @@ function clientId(state = '', action) { } } -function reviews(state = [], action) { - switch (action.type) { - case ActionTypes.RECEIVED_REVIEWS: - return action.data; - default: - return state; - } -} - function reviewsDetails(state = [], action) { switch (action.type) { case ActionTypes.RECEIVED_REVIEWS_DETAILS: @@ -95,9 +86,9 @@ function reviewsDetails(state = [], action) { } } -function yourPrs(state = [], action) { +function sidebarContent(state = [], action) { switch (action.type) { - case ActionTypes.RECEIVED_YOUR_PRS: + case ActionTypes.RECEIVED_SIDEBAR_CONTENT: return action.data; default: return state; @@ -122,15 +113,6 @@ function yourPrsDetails(state = [], action) { } } -function yourAssignments(state = [], action) { - switch (action.type) { - case ActionTypes.RECEIVED_YOUR_ASSIGNMENTS: - return action.data; - default: - return state; - } -} - function mentions(state = [], action) { switch (action.type) { case ActionTypes.RECEIVED_MENTIONS: @@ -140,15 +122,6 @@ function mentions(state = [], action) { } } -function unreads(state = [], action) { - switch (action.type) { - case ActionTypes.RECEIVED_UNREADS: - return action.data; - default: - return state; - } -} - function githubUsers(state = {}, action) { switch (action.type) { case ActionTypes.RECEIVED_GITHUB_USER: { @@ -238,14 +211,10 @@ export default combineReducers({ userSettings, configuration, clientId, - reviews, reviewsDetails, - yourPrs, yourRepos, yourPrsDetails, - yourAssignments, mentions, - unreads, githubUsers, rhsPluginAction, rhsState, @@ -253,4 +222,5 @@ export default combineReducers({ createIssueModal, attachCommentToIssueModalVisible, attachCommentToIssueModalForPostId, + sidebarContent, }); diff --git a/webapp/src/websocket/index.js b/webapp/src/websocket/index.js index 15021af57..c4fe49e37 100644 --- a/webapp/src/websocket/index.js +++ b/webapp/src/websocket/index.js @@ -2,18 +2,16 @@ // See LICENSE.txt for license information. import ActionTypes from '../action_types'; -import Constants from '../constants'; +import Constants, {JitterForReconnectAPICall} from '../constants'; import { getConnected, - getReviews, - getUnreads, - getYourAssignments, - getYourPrs, + getSidebarContent, openCreateIssueModalWithoutPost, } from '../actions'; import {id as pluginId} from '../manifest'; +let timeoutId; export function handleConnect(store) { return (msg) => { if (!msg.data) { @@ -66,21 +64,28 @@ export function handleReconnect(store, reminder = false) { return async () => { const {data} = await getConnected(reminder)(store.dispatch, store.getState); if (data && data.connected) { - getReviews()(store.dispatch, store.getState); - getUnreads()(store.dispatch, store.getState); - getYourPrs()(store.dispatch, store.getState); - getYourAssignments()(store.dispatch, store.getState); + if (typeof timeoutId === 'number') { + clearTimeout(timeoutId); + } + + const rand = Math.floor(Math.random() * (JitterForReconnectAPICall.MAX_TIME_IN_SEC - JitterForReconnectAPICall.MIN_TIME_IN_SEC + 1)) + JitterForReconnectAPICall.MIN_TIME_IN_SEC; //eslint-disable-line no-mixed-operators + timeoutId = setTimeout(() => { + getSidebarContent()(store.dispatch, store.getState); + timeoutId = undefined; //eslint-disable-line no-undefined + }, rand * 1000); } }; } export function handleRefresh(store) { - return () => { + return (msg) => { if (store.getState()[`plugins-${pluginId}`].connected) { - getReviews()(store.dispatch, store.getState); - getUnreads()(store.dispatch, store.getState); - getYourPrs()(store.dispatch, store.getState); - getYourAssignments()(store.dispatch, store.getState); + const {data} = msg; + + store.dispatch({ + type: ActionTypes.RECEIVED_SIDEBAR_CONTENT, + data, + }); } }; }