diff --git a/server/issue.go b/server/issue.go index 249e383d..67fc0edc 100644 --- a/server/issue.go +++ b/server/issue.go @@ -25,6 +25,13 @@ type ExtendedIssue struct { ForeignPosition int `json:"position"` } +// ListsIssue for all list issues +type ListsIssue struct { + In []*ExtendedIssue `json:"in"` + My []*ExtendedIssue `json:"my"` + Out []*ExtendedIssue `json:"out"` +} + func newIssue(message, postPermalink, description, postID string) *Issue { return &Issue{ ID: model.NewId(), diff --git a/server/list.go b/server/list.go index 52c9a66b..326a26dd 100644 --- a/server/list.go +++ b/server/list.go @@ -35,12 +35,10 @@ type ListStore interface { PopReference(userID, listID string) (*IssueRef, error) // BumpReference moves the Issue reference for issueID in listID for userID to the beginning of the list BumpReference(userID, issueID, listID string) error - // GetIssueReference gets the IssueRef and position of the issue issueID on user userID's list listID GetIssueReference(userID, issueID, listID string) (*IssueRef, int, error) // GetIssueListAndReference gets the issue list, IssueRef and position for user userID GetIssueListAndReference(userID, issueID string) (string, *IssueRef, int) - // GetList returns the list of IssueRef in listID for userID GetList(userID, listID string) ([]*IssueRef, error) } @@ -135,6 +133,26 @@ func (l *listManager) GetIssueList(userID, listID string) ([]*ExtendedIssue, err return extendedIssues, nil } +func (l *listManager) GetAllList(userID string) (listsIssue *ListsIssue, err error) { + inListIssue, err := l.GetIssueList(userID, InListKey) + if err != nil { + return nil, err + } + myListIssue, err := l.GetIssueList(userID, MyListKey) + if err != nil { + return nil, err + } + outListIssue, err := l.GetIssueList(userID, OutListKey) + if err != nil { + return nil, err + } + return &ListsIssue{ + In: inListIssue, + My: myListIssue, + Out: outListIssue, + }, nil +} + func (l *listManager) CompleteIssue(userID, issueID string) (issue *Issue, foreignID string, listToUpdate string, err error) { issueList, ir, _ := l.store.GetIssueListAndReference(userID, issueID) if ir == nil { diff --git a/server/plugin.go b/server/plugin.go index e9651fa5..aa986f2d 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -23,6 +23,8 @@ const ( // WSEventConfigUpdate is the WebSocket event to update the Todo list's configurations on webapp WSEventConfigUpdate = "config_update" + + ErrorMsgAddIssue = "Unable to add issue" ) // ListManager represents the logic on the lists @@ -33,6 +35,8 @@ type ListManager interface { SendIssue(senderID, receiverID, message, postPermalink, description, postID string) (string, error) // GetIssueList gets the todos on listID for userID GetIssueList(userID, listID string) ([]*ExtendedIssue, error) + // GetAllList get all issues + GetAllList(userID string) (*ListsIssue, error) // CompleteIssue completes the todo issueID for userID, and returns the issue and the foreign ID if any CompleteIssue(userID, issueID string) (issue *Issue, foreignID string, listToUpdate string, err error) // AcceptIssue moves one the todo issueID of userID from inbox to myList, and returns the message and the foreignUserID if any @@ -121,7 +125,7 @@ func (p *Plugin) initializeAPI() { p.router.Use(p.withRecovery) p.router.HandleFunc("/add", p.checkAuth(p.handleAdd)).Methods(http.MethodPost) - p.router.HandleFunc("/list", p.checkAuth(p.handleList)).Methods(http.MethodGet) + p.router.HandleFunc("/lists", p.checkAuth(p.handleLists)).Methods(http.MethodGet) p.router.HandleFunc("/remove", p.checkAuth(p.handleRemove)).Methods(http.MethodPost) p.router.HandleFunc("/complete", p.checkAuth(p.handleComplete)).Methods(http.MethodPost) p.router.HandleFunc("/accept", p.checkAuth(p.handleAccept)).Methods(http.MethodPost) @@ -174,8 +178,9 @@ func (p *Plugin) handleTelemetry(w http.ResponseWriter, r *http.Request) { telemetryRequest, err := GetTelemetryPayloadFromJSON(r.Body) if err != nil { - p.API.LogError("Unable to get telemetry payload from JSON err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusBadRequest, "Unable to get telemetry payload from JSON.", err) + msg := "Unable to get telemetry payload from JSON" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) return } @@ -194,8 +199,9 @@ func (p *Plugin) handleAdd(w http.ResponseWriter, r *http.Request) { addRequest, err := GetAddIssuePayloadFromJSON(r.Body) if err != nil { - p.API.LogError("Unable to get add issue payload from JSON err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusBadRequest, "Unable to get add issue payload from JSON.", err) + msg := "Unable to get add issue payload from JSON" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) return } @@ -209,8 +215,8 @@ func (p *Plugin) handleAdd(w http.ResponseWriter, r *http.Request) { if addRequest.SendTo == "" { _, err = p.listManager.AddIssue(userID, addRequest.Message, addRequest.PostPermalink, addRequest.Description, addRequest.PostID) if err != nil { - p.API.LogError("Unable to add the issue err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to add issue", err) + p.API.LogError(ErrorMsgAddIssue, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, ErrorMsgAddIssue, err) return } @@ -226,16 +232,17 @@ func (p *Plugin) handleAdd(w http.ResponseWriter, r *http.Request) { receiver, appErr := p.API.GetUserByUsername(addRequest.SendTo) if appErr != nil { - p.API.LogError("invalid username, err=" + appErr.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to find user", appErr) + msg := "Unable to find user" + p.API.LogError(msg, "err", appErr.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, appErr) return } if receiver.Id == userID { _, err = p.listManager.AddIssue(userID, addRequest.Message, addRequest.Description, addRequest.PostID, addRequest.PostPermalink) if err != nil { - p.API.LogError("Unable to add issue err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to add issue", err) + p.API.LogError(ErrorMsgAddIssue, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, ErrorMsgAddIssue, err) return } @@ -261,8 +268,9 @@ func (p *Plugin) handleAdd(w http.ResponseWriter, r *http.Request) { issueID, err := p.listManager.SendIssue(userID, receiver.Id, addRequest.Message, addRequest.PostPermalink, addRequest.Description, addRequest.PostID) if err != nil { - p.API.LogError("Unable to send issue err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to send issue", err) + msg := "Unable to send issue" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } @@ -287,31 +295,24 @@ func (p *Plugin) postReplyIfNeeded(postID, message, todo, postPermalink string) } } -func (p *Plugin) handleList(w http.ResponseWriter, r *http.Request) { +func (p *Plugin) handleLists(w http.ResponseWriter, r *http.Request) { userID := r.Header.Get("Mattermost-User-ID") - listInput := r.URL.Query().Get("list") - listID := MyListKey - switch listInput { - case OutFlag: - listID = OutListKey - case InFlag: - listID = InListKey - } - - issues, err := p.listManager.GetIssueList(userID, listID) + allListIssue, err := p.listManager.GetAllList(userID) if err != nil { - p.API.LogError("Unable to get issues for user err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to get issues for user", err) + msg := "Unable to get issues for user" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } - if len(issues) > 0 && r.URL.Query().Get("reminder") == "true" && p.getReminderPreference(userID) { + if allListIssue != nil && len(allListIssue.My) > 0 && r.URL.Query().Get("reminder") == "true" && p.getReminderPreference(userID) { var lastReminderAt int64 lastReminderAt, err = p.getLastReminderTimeForUser(userID) if err != nil { - p.API.LogError("Unable to send reminder err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to send reminder", err) + msg := "Unable to send reminder" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } @@ -324,7 +325,7 @@ func (p *Plugin) handleList(w http.ResponseWriter, r *http.Request) { nt := time.Unix(now/1000, 0).In(timezone) lt := time.Unix(lastReminderAt/1000, 0).In(timezone) if nt.Sub(lt).Hours() >= 1 && (nt.Day() != lt.Day() || nt.Month() != lt.Month() || nt.Year() != lt.Year()) { - p.PostBotDM(userID, "Daily Reminder:\n\n"+issuesListToString(issues)) + p.PostBotDM(userID, "Daily Reminder:\n\n"+issuesListToString(allListIssue.My)) p.trackDailySummary(userID) err = p.saveLastReminderTimeForUser(userID) if err != nil { @@ -333,14 +334,15 @@ func (p *Plugin) handleList(w http.ResponseWriter, r *http.Request) { } } - issuesJSON, err := json.Marshal(issues) + allListIssueJSON, err := json.Marshal(allListIssue) if err != nil { - p.API.LogError("Unable marhsal issues list to json err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable marhsal issues list to json", err) + msg := "Unable marhsal all lists issues to json" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } - _, err = w.Write(issuesJSON) + _, err = w.Write(allListIssueJSON) if err != nil { p.API.LogError("Unable to write json response while listing issues err=" + err.Error()) } @@ -351,8 +353,9 @@ func (p *Plugin) handleEdit(w http.ResponseWriter, r *http.Request) { editRequest, err := GetEditIssuePayloadFromJSON(r.Body) if err != nil { - p.API.LogError("Unable to get edit issue payload from JSON err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusBadRequest, "Unable to get edit issue payload from JSON.", err) + msg := "Unable to get edit issue payload from JSON" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) return } @@ -363,8 +366,9 @@ func (p *Plugin) handleEdit(w http.ResponseWriter, r *http.Request) { foreignUserID, list, oldMessage, err := p.listManager.EditIssue(userID, editRequest.ID, editRequest.Message, editRequest.Description) if err != nil { - p.API.LogError("Unable to edit message: err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to edit issue", err) + msg := "Unable to edit message" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } @@ -391,8 +395,9 @@ func (p *Plugin) handleChangeAssignment(w http.ResponseWriter, r *http.Request) changeRequest, err := GetChangeAssignmentPayloadFromJSON(r.Body) if err != nil { - p.API.LogError("Unable to get change request payload from JSON err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusBadRequest, "Unable to get change request from JSON.", err) + msg := "Unable to get change request payload from JSON" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) return } @@ -403,15 +408,17 @@ func (p *Plugin) handleChangeAssignment(w http.ResponseWriter, r *http.Request) receiver, appErr := p.API.GetUserByUsername(changeRequest.SendTo) if appErr != nil { - p.API.LogError("username not valid, err=" + appErr.Error()) - p.handleErrorWithCode(w, http.StatusNotFound, "Unable to find user", appErr) + msg := "username not valid" + p.API.LogError(msg, "err", appErr.Error()) + p.handleErrorWithCode(w, http.StatusNotFound, msg, appErr) return } issue, oldOwner, err := p.listManager.ChangeAssignment(changeRequest.ID, userID, receiver.Id) if err != nil { - p.API.LogError("Unable to change the assignment of an issue: err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to change the assignment", err) + msg := "Unable to change the assignment of an issue" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } @@ -437,8 +444,9 @@ func (p *Plugin) handleAccept(w http.ResponseWriter, r *http.Request) { acceptRequest, err := GetAcceptRequestPayloadFromJSON(r.Body) if err != nil { - p.API.LogError("Unable to get accept request payload from JSON err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusBadRequest, "Unable to get accept request from JSON.", err) + msg := "Unable to get accept request payload from JSON" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) return } @@ -449,8 +457,9 @@ func (p *Plugin) handleAccept(w http.ResponseWriter, r *http.Request) { todoMessage, sender, err := p.listManager.AcceptIssue(userID, acceptRequest.ID) if err != nil { - p.API.LogError("Unable to accept issue err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to accept issue", err) + msg := "Unable to accept issue" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } @@ -469,8 +478,9 @@ func (p *Plugin) handleComplete(w http.ResponseWriter, r *http.Request) { completeRequest, err := GetCompleteIssuePayloadFromJSON(r.Body) if err != nil { - p.API.LogError("Unable to get complete issue request payload from JSON err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusBadRequest, "Unable to get complete issue request from JSON.", err) + msg := "Unable to get complete issue request payload from JSON" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) return } @@ -481,8 +491,9 @@ func (p *Plugin) handleComplete(w http.ResponseWriter, r *http.Request) { issue, foreignID, listToUpdate, err := p.listManager.CompleteIssue(userID, completeRequest.ID) if err != nil { - p.API.LogError("Unable to complete issue err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to complete issue", err) + msg := "Unable to complete issue" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } @@ -513,8 +524,9 @@ func (p *Plugin) handleRemove(w http.ResponseWriter, r *http.Request) { removeRequest, err := GetRemoveIssuePayloadFromJSON(r.Body) if err != nil { - p.API.LogError("Unable to get remove issue request payload from JSON err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusBadRequest, "Unable to get remove issue request from JSON.", err) + msg := "Unable to get remove issue request payload from JSON" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) return } @@ -525,8 +537,9 @@ func (p *Plugin) handleRemove(w http.ResponseWriter, r *http.Request) { issue, foreignID, isSender, listToUpdate, err := p.listManager.RemoveIssue(userID, removeRequest.ID) if err != nil { - p.API.LogError("Unable to remove issue, err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to remove issue", err) + msg := "Unable to remove issue" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } p.sendRefreshEvent(userID, []string{listToUpdate}) @@ -563,8 +576,9 @@ func (p *Plugin) handleBump(w http.ResponseWriter, r *http.Request) { bumpRequest, err := GetBumpIssuePayloadFromJSON(r.Body) if err != nil { - p.API.LogError("Unable to get bump issue request payload from JSON err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusBadRequest, "Unable to get bump issue request from JSON.", err) + msg := "Unable to get bump issue request payload from JSON" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) return } @@ -575,8 +589,9 @@ func (p *Plugin) handleBump(w http.ResponseWriter, r *http.Request) { todo, foreignUser, foreignIssueID, err := p.listManager.BumpIssue(userID, bumpRequest.ID) if err != nil { - p.API.LogError("Unable to bump issue, err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to bump issue", err) + msg := "Unable to bump issue" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } @@ -610,8 +625,9 @@ func (p *Plugin) handleConfig(w http.ResponseWriter, r *http.Request) { configJSON, err := json.Marshal(clientConfig) if err != nil { - p.API.LogError("Unable to marshal plugin configuration to json err=" + err.Error()) - p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable to marshal plugin configuration to json", err) + msg := "Unable to marshal plugin configuration to json" + p.API.LogError(msg, "err", err.Error()) + p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) return } diff --git a/webapp/src/action_types.js b/webapp/src/action_types.js index 237d7e94..a3fc6e8f 100644 --- a/webapp/src/action_types.js +++ b/webapp/src/action_types.js @@ -13,9 +13,7 @@ export const GET_ASSIGNEE = pluginId + '_get_assignee'; export const SET_EDITING_TODO = pluginId + '_set_editing_todo'; export const REMOVE_EDITING_TODO = pluginId + '_remove_editing_todo'; export const REMOVE_ASSIGNEE = pluginId + '_remove_assignee'; -export const GET_ISSUES = pluginId + '_get_issues'; -export const GET_OUT_ISSUES = pluginId + '_get_out_issues'; -export const GET_IN_ISSUES = pluginId + '_get_in_issues'; +export const GET_ALL_ISSUES = pluginId + '_get_all_issues'; export const RECEIVED_SHOW_RHS_ACTION = pluginId + '_show_rhs'; export const UPDATE_RHS_STATE = pluginId + '_update_rhs_state'; export const SET_RHS_VISIBLE = pluginId + '_set_rhs_visible'; diff --git a/webapp/src/actions.js b/webapp/src/actions.js index 485d1997..2fe99a0a 100644 --- a/webapp/src/actions.js +++ b/webapp/src/actions.js @@ -8,9 +8,6 @@ import { OPEN_TODO_TOAST, CLOSE_TODO_TOAST, RECEIVED_SHOW_RHS_ACTION, - GET_ISSUES, - GET_IN_ISSUES, - GET_OUT_ISSUES, UPDATE_RHS_STATE, SET_RHS_VISIBLE, SET_HIDE_TEAM_SIDEBAR_BUTTONS, @@ -20,6 +17,7 @@ import { CLOSE_ADD_CARD, SET_EDITING_TODO, REMOVE_EDITING_TODO, + GET_ALL_ISSUES, } from './action_types'; import {getPluginServerRoute} from './selectors'; @@ -141,11 +139,10 @@ export const changeAssignee = (id, assignee) => async (dispatch, getState) => { })); }; -export const list = (reminder = false, listName = 'my') => async (dispatch, getState) => { - let resp; +export const fetchAllIssueLists = (reminder = false) => async (dispatch, getState) => { let data; try { - resp = await fetch(getPluginServerRoute(getState()) + '/list?reminder=' + reminder + '&list=' + listName, Client4.getOptions({ + const resp = await fetch(getPluginServerRoute(getState()) + '/lists?reminder=' + reminder, Client4.getOptions({ method: 'get', })); data = await resp.json(); @@ -153,21 +150,8 @@ export const list = (reminder = false, listName = 'my') => async (dispatch, getS return {error}; } - let actionType = GET_ISSUES; - switch (listName) { - case 'my': - actionType = GET_ISSUES; - break; - case 'in': - actionType = GET_IN_ISSUES; - break; - case 'out': - actionType = GET_OUT_ISSUES; - break; - } - dispatch({ - type: actionType, + type: GET_ALL_ISSUES, data, }); @@ -218,10 +202,9 @@ export function setHideTeamSidebar(payload) { } export const updateConfig = () => async (dispatch, getState) => { - let resp; let data; try { - resp = await fetch(getPluginServerRoute(getState()) + '/config', Client4.getOptions({ + const resp = await fetch(getPluginServerRoute(getState()) + '/config', Client4.getOptions({ method: 'get', })); data = await resp.json(); diff --git a/webapp/src/components/post_type_todo/index.js b/webapp/src/components/post_type_todo/index.js index 1cbb7fc9..518b3120 100644 --- a/webapp/src/components/post_type_todo/index.js +++ b/webapp/src/components/post_type_todo/index.js @@ -5,7 +5,7 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {remove, complete, accept, telemetry} from '../../actions'; -import {getSiteURL} from '../../selectors'; +import {getInIssues, getSiteURL} from '../../selectors'; import PostTypeTodo from './post_type_todo'; @@ -13,7 +13,7 @@ function mapStateToProps(state, ownProps) { return { ...ownProps, siteURL: getSiteURL(state), - pendingAnswer: state['plugins-com.mattermost.plugin-todo'].inIssues.some((issue) => issue.id === ownProps.post.props.issueId), + pendingAnswer: getInIssues(state).some((issue) => issue.id === ownProps.post.props.issueId), }; } diff --git a/webapp/src/components/sidebar_buttons/index.js b/webapp/src/components/sidebar_buttons/index.js index 81bd3a10..0fbd3bb4 100644 --- a/webapp/src/components/sidebar_buttons/index.js +++ b/webapp/src/components/sidebar_buttons/index.js @@ -4,15 +4,17 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; -import {list, updateRhsState, telemetry} from '../../actions'; +import {fetchAllIssueLists, updateRhsState, telemetry} from '../../actions'; + +import {getMyIssues, getInIssues, getOutIssues} from '../../selectors'; import SidebarButtons from './sidebar_buttons.jsx'; function mapStateToProps(state) { return { - issues: state['plugins-com.mattermost.plugin-todo'].issues, - inIssues: state['plugins-com.mattermost.plugin-todo'].inIssues, - outIssues: state['plugins-com.mattermost.plugin-todo'].outIssues, + myIssues: getMyIssues(state), + inIssues: getInIssues(state), + outIssues: getOutIssues(state), showRHSPlugin: state['plugins-com.mattermost.plugin-todo'].rhsPluginAction, }; } @@ -20,11 +22,11 @@ function mapStateToProps(state) { function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ - list, + fetchAllIssueLists, updateRhsState, telemetry, }, dispatch), }; } -export default connect(mapStateToProps, mapDispatchToProps)(SidebarButtons); \ No newline at end of file +export default connect(mapStateToProps, mapDispatchToProps)(SidebarButtons); diff --git a/webapp/src/components/sidebar_buttons/sidebar_buttons.jsx b/webapp/src/components/sidebar_buttons/sidebar_buttons.jsx index 0ef2e505..6dc5fc38 100644 --- a/webapp/src/components/sidebar_buttons/sidebar_buttons.jsx +++ b/webapp/src/components/sidebar_buttons/sidebar_buttons.jsx @@ -13,11 +13,10 @@ export default class SidebarButtons extends React.PureComponent { theme: PropTypes.object.isRequired, isTeamSidebar: PropTypes.bool, showRHSPlugin: PropTypes.func.isRequired, - issues: PropTypes.arrayOf(PropTypes.object), - inIssues: PropTypes.arrayOf(PropTypes.object), - outIssues: PropTypes.arrayOf(PropTypes.object), + myIssues: PropTypes.array.isRequired, + inIssues: PropTypes.array.isRequired, + outIssues: PropTypes.array.isRequired, actions: PropTypes.shape({ - list: PropTypes.func.isRequired, updateRhsState: PropTypes.func.isRequired, telemetry: PropTypes.func.isRequired, }).isRequired, @@ -49,9 +48,9 @@ export default class SidebarButtons extends React.PureComponent { container = style.containerTeam; } - const issues = this.props.issues || []; - const inIssues = this.props.inIssues || []; - const outIssues = this.props.outIssues || []; + const myIssues = this.props.myIssues; + const inIssues = this.props.inIssues; + const outIssues = this.props.outIssues; return (
@@ -68,7 +67,7 @@ export default class SidebarButtons extends React.PureComponent { }} > - {' ' + issues.length} + {' ' + myIssues.length } - {' ' + inIssues.length} + {' ' + inIssues.length } - {' ' + outIssues.length} + {' ' + outIssues.length }
diff --git a/webapp/src/components/sidebar_right/index.js b/webapp/src/components/sidebar_right/index.js index 8eb8f512..568d43ee 100644 --- a/webapp/src/components/sidebar_right/index.js +++ b/webapp/src/components/sidebar_right/index.js @@ -4,17 +4,17 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; -import {getIssues, getInIssues, getOutIssues, getSiteURL, getTodoToast} from '../../selectors'; -import {remove, list, openAssigneeModal, openAddCard, closeAddCard, complete, bump, accept, telemetry, setRhsVisible} from '../../actions'; +import {getSiteURL, getTodoToast, getMyIssues, getInIssues, getOutIssues} from '../../selectors'; +import {remove, fetchAllIssueLists, openAssigneeModal, openAddCard, closeAddCard, complete, bump, accept, telemetry, setRhsVisible} from '../../actions'; import SidebarRight from './sidebar_right.jsx'; function mapStateToProps(state) { return { - todos: getIssues(state), + myIssues: getMyIssues(state), + inIssues: getInIssues(state), + outIssues: getOutIssues(state), todoToast: getTodoToast(state), - inTodos: getInIssues(state), - outTodos: getOutIssues(state), siteURL: getSiteURL(state), rhsState: state['plugins-com.mattermost.plugin-todo'].rhsState, }; @@ -27,7 +27,7 @@ function mapDispatchToProps(dispatch) { complete, accept, bump, - list, + fetchAllIssueLists, openAddCard, closeAddCard, openAssigneeModal, diff --git a/webapp/src/components/sidebar_right/sidebar_right.jsx b/webapp/src/components/sidebar_right/sidebar_right.jsx index 5d059ff1..6eda2d25 100644 --- a/webapp/src/components/sidebar_right/sidebar_right.jsx +++ b/webapp/src/components/sidebar_right/sidebar_right.jsx @@ -51,9 +51,9 @@ const InListName = 'in'; export default class SidebarRight extends React.PureComponent { static propTypes = { - todos: PropTypes.arrayOf(PropTypes.object), - inTodos: PropTypes.arrayOf(PropTypes.object), - outTodos: PropTypes.arrayOf(PropTypes.object), + myIssues: PropTypes.array.isRequired, + inIssues: PropTypes.array.isRequired, + outIssues: PropTypes.array.isRequired, todoToast: PropTypes.object, theme: PropTypes.object.isRequired, siteURL: PropTypes.string.isRequired, @@ -63,7 +63,7 @@ export default class SidebarRight extends React.PureComponent { complete: PropTypes.func.isRequired, accept: PropTypes.func.isRequired, bump: PropTypes.func.isRequired, - list: PropTypes.func.isRequired, + fetchAllIssueLists: PropTypes.func.isRequired, openAddCard: PropTypes.func.isRequired, closeAddCard: PropTypes.func.isRequired, openAssigneeModal: PropTypes.func.isRequired, @@ -101,9 +101,7 @@ export default class SidebarRight extends React.PureComponent { componentDidMount() { document.addEventListener('keydown', this.handleKeypress); - this.props.actions.list(false, 'my'); - this.props.actions.list(false, 'in'); - this.props.actions.list(false, 'out'); + this.props.actions.fetchAllIssueLists(); this.props.actions.setVisible(true); } @@ -125,18 +123,6 @@ export default class SidebarRight extends React.PureComponent { } } - getInIssues() { - return this.props.inTodos.length; - } - - getOutIssues() { - return this.props.outTodos.length; - } - - getMyIssues() { - return this.props.todos.length; - } - addTodoItem() { this.props.actions.openAddCard(''); } @@ -154,12 +140,12 @@ export default class SidebarRight extends React.PureComponent { switch (this.state.list) { case MyListName: - todos = this.props.todos || []; + todos = this.props.myIssues; addButton = 'Add Todo'; - inboxList = this.props.inTodos || []; + inboxList = this.props.inIssues; break; case OutListName: - todos = this.props.outTodos || []; + todos = this.props.outIssues; listHeading = 'Sent Todos'; addButton = 'Request a Todo from someone'; break; diff --git a/webapp/src/index.js b/webapp/src/index.js index 39acc44a..2593d500 100644 --- a/webapp/src/index.js +++ b/webapp/src/index.js @@ -6,7 +6,7 @@ import Root from './components/root'; import AssigneeModal from './components/assignee_modal'; import SidebarRight from './components/sidebar_right'; -import {openAddCard, list, setShowRHSAction, telemetry, updateConfig, setHideTeamSidebar} from './actions'; +import {openAddCard, setShowRHSAction, telemetry, updateConfig, setHideTeamSidebar, fetchAllIssueLists} from './actions'; import reducer from './reducer'; import PostTypeTodo from './components/post_type_todo'; import TeamSidebar from './components/team_sidebar'; @@ -48,32 +48,6 @@ export default class Plugin { 'Open your list of Todo issues', ); - const getFrontendListName = (backendListName) => { - let frontendListName = 'my'; - switch (backendListName) { - case '': - frontendListName = 'my'; - break; - case '_in': - frontendListName = 'in'; - break; - case '_out': - frontendListName = 'out'; - break; - default: - frontendListName = 'my'; - break; - } - return frontendListName; - }; - - const refresh = ({data: {lists}}) => lists.forEach((listName) => store.dispatch(list(false, getFrontendListName(listName)))); - const refreshAll = () => { - store.dispatch(list(false)); - store.dispatch(list(false, 'in')); - store.dispatch(list(false, 'out')); - }; - const iconURL = getPluginServerRoute(store.getState()) + '/public/app-bar-icon.png'; registry.registerAppBarComponent( iconURL, @@ -81,12 +55,13 @@ export default class Plugin { 'Open your list of Todo issues', ); + const refresh = () => { + store.dispatch(fetchAllIssueLists()); + }; registry.registerWebSocketEventHandler(`custom_${pluginId}_refresh`, refresh); - registry.registerReconnectHandler(refreshAll); + registry.registerReconnectHandler(refresh); - store.dispatch(list(true)); - store.dispatch(list(false, 'in')); - store.dispatch(list(false, 'out')); + store.dispatch(fetchAllIssueLists(true)); // register websocket event to track config changes const configUpdate = ({data}) => { @@ -100,7 +75,7 @@ export default class Plugin { activityFunc = () => { const now = new Date().getTime(); if (now - lastActivityTime > activityTimeout) { - store.dispatch(list(true)); + store.dispatch(fetchAllIssueLists(true)); } lastActivityTime = now; }; diff --git a/webapp/src/reducer.js b/webapp/src/reducer.js index b186be16..259d6820 100644 --- a/webapp/src/reducer.js +++ b/webapp/src/reducer.js @@ -9,11 +9,9 @@ import { CLOSE_TODO_TOAST, OPEN_ADD_CARD, CLOSE_ADD_CARD, - GET_ISSUES, SET_EDITING_TODO, REMOVE_EDITING_TODO, - GET_IN_ISSUES, - GET_OUT_ISSUES, + GET_ALL_ISSUES, RECEIVED_SHOW_RHS_ACTION, UPDATE_RHS_STATE, SET_RHS_VISIBLE, @@ -86,28 +84,10 @@ const postID = (state = '', action) => { } }; -const issues = (state = [], action) => { +const allIssues = (state = {my: [], in: [], out: []}, action) => { switch (action.type) { - case GET_ISSUES: - return action.data; - default: - return state; - } -}; - -const inIssues = (state = [], action) => { - switch (action.type) { - case GET_IN_ISSUES: - return action.data; - default: - return state; - } -}; - -const outIssues = (state = [], action) => { - switch (action.type) { - case GET_OUT_ISSUES: - return action.data; + case GET_ALL_ISSUES: + return action.data ?? state; default: return state; } @@ -156,9 +136,7 @@ export default combineReducers({ todoToast, editingTodo, postID, - issues, - inIssues, - outIssues, + allIssues, rhsState, rhsPluginAction, isRhsVisible, diff --git a/webapp/src/selectors.js b/webapp/src/selectors.js index b76ef174..cba00e8b 100644 --- a/webapp/src/selectors.js +++ b/webapp/src/selectors.js @@ -25,9 +25,10 @@ export const getMessage = (state) => { } return post.message; }; -export const getIssues = (state) => getPluginState(state).issues; -export const getInIssues = (state) => getPluginState(state).inIssues; -export const getOutIssues = (state) => getPluginState(state).outIssues; +export const getMyIssues = (state) => getAllIssues(state).my; +export const getInIssues = (state) => getAllIssues(state).in; +export const getOutIssues = (state) => getAllIssues(state).out; +export const getAllIssues = (state) => getPluginState(state).allIssues; export const getCurrentTeamRoute = (state) => { const basePath = getSiteURL(state); const teamName = state.entities.teams.teams[state.entities.teams.currentTeamId].name;