-
Notifications
You must be signed in to change notification settings - Fork 64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix(Issue#202): counts in one request #225
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this improvement @jufab 👍
I have a few comments and one request to minimize the fetching of lists from the frontend
server/plugin.go
Outdated
p.API.LogError("Unable marhsal count issue list to json err=" + err.Error()) | ||
p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable marhsal count issue list to json", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: to de-duplicate some string creation here. Same with the block above this one
p.API.LogError("Unable marhsal count issue list to json err=" + err.Error()) | |
p.handleErrorWithCode(w, http.StatusInternalServerError, "Unable marhsal count issue list to json", err) | |
msg := "Unable marshal count issue list to json" | |
p.API.LogError(msg, "err", err.Error()) | |
p.handleErrorWithCode(w, http.StatusInternalServerError, msg, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see now that this is copied from the function above. I'm still thinking we can make this change here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just modified all the error messages the same way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mickmister What are your opinions on moving the log statement inside the "handleErrorWithCode" function instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@raghavaggarwal2308 That sounds fine but we would want to change every call to handleErrorWithCode
as well to avoid double logging. And that's definitely out of scope of this PR
server/plugin.go
Outdated
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: extra newline at the end of this function and listStore.CountIssues
. This is something we should have the linter configured to enforce, but I'm not sure if we have this particular convention enforced anywhere
server/store.go
Outdated
return &CountIssue{ | ||
In: len(inList), | ||
My: len(myList), | ||
Out: len(outList), | ||
}, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might as well just return the actual lists right? Then the frontend doesn't need to do any other requests
@jufab Just added a few minor comments, other than that LGTM. You still need to fix the comments provided by @mickmister |
Sorry for that but I revised my MR proposal with this single request version for counters and display |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work on this @jufab. Thanks for addressing the changes 👍
I have a few more requests on this. There are some conventions that have changed on the frontend to cater towards the new data being transferred, though I think previous component props had a nice separation of concerns. Please let me know your thoughts @jufab
server/issue.go
Outdated
// CountIssue for all counter issues | ||
type CountIssue struct { | ||
In int `json:"in"` | ||
My int `json:"my"` | ||
Out int `json:"out"` | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't used anywhere anymore so we should remove this type definition
// CountIssue for all counter issues | |
type CountIssue struct { | |
In int `json:"in"` | |
My int `json:"my"` | |
Out int `json:"out"` | |
} |
server/plugin.go
Outdated
@@ -116,6 +118,7 @@ func (p *Plugin) initializeAPI() { | |||
|
|||
p.router.HandleFunc("/add", p.checkAuth(p.handleAdd)).Methods(http.MethodPost) | |||
p.router.HandleFunc("/list", p.checkAuth(p.handleList)).Methods(http.MethodGet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this endpoint anymore? Or are we still calling this in some cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need so i delete it but getIssueList is used by command
msg := "Unable to get telemetry payload from JSON" | ||
p.API.LogError(msg, "err", err.Error()) | ||
p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I was unclear about my request before. We shouldn't edit the log statements in functions unrelated to this PR's purpose. We can clean this up in a separate effort/PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry too. should I put everything back the way it was before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes everything that is not related to the main feature/effort of the PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we do change the logging back the way it was for places unrelated the purpose of the PR, but I don't want to drag this PR on for that reason
webapp/src/action_types.js
Outdated
@@ -15,6 +15,8 @@ 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_COUNT_ISSUES = pluginId + '_get_count_issues'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will also be removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
webapp/src/actions.js
Outdated
@@ -174,6 +175,25 @@ export const list = (reminder = false, listName = 'my') => async (dispatch, getS | |||
return {data}; | |||
}; | |||
|
|||
export const fetchAllIssue = () => async (dispatch, getState) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export const fetchAllIssue = () => async (dispatch, getState) => { | |
export const fetchAllIssueLists = () => async (dispatch, getState) => { |
issues: state['plugins-com.mattermost.plugin-todo'].issues, | ||
inIssues: state['plugins-com.mattermost.plugin-todo'].inIssues, | ||
outIssues: state['plugins-com.mattermost.plugin-todo'].outIssues, | ||
allIssues: state['plugins-com.mattermost.plugin-todo'].allIssues, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense to keep the convention of feeding the component the issues the way we were doing before:
function mapStateToProps(state) {
const allIssues = getAllIssues(state); // from selectors.js
return {
myIssues: allIssues.my, // note that I changed the prop to be `myIssues`
inIssues: allIssues.in,
outIssues: allIssues.out,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though as mentioned elsewhere, we can use individual selectors for the in issues. The main reason I'm thinking this, is it simplifies what the component needs to worry about
webapp/src/reducer.js
Outdated
@@ -113,6 +114,15 @@ const outIssues = (state = [], action) => { | |||
} | |||
}; | |||
|
|||
const allIssues = (state = {}, action) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's handle the undefined state issue here instead of elsewhere
const allIssues = (state = {}, action) => { | |
const allIssuesInitialState = { | |
my: [], | |
in: [], | |
out: [], | |
}; | |
const allIssues = (state = allIssuesInitialState, action) => { |
|
||
import SidebarRight from './sidebar_right.jsx'; | ||
|
||
function mapStateToProps(state) { | ||
return { | ||
todos: getIssues(state), | ||
allIssues: state['plugins-com.mattermost.plugin-todo'].allIssues, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use the selectors whenever possible. Reading the previous code, I think we can continue using the getInIssues
etc. selectors to make the consumer code less complicated. The selector would call the getAllIssues
selector and return allIssues.in
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also like the convention of myTodos
rather than just todos
webapp/src/index.js
Outdated
const refresh = () => { | ||
store.dispatch(fetchAllIssue()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have the websocket message that gets sent from the server contain the lists, rather than fetching them here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's after
registry.registerWebSocketEventHandler(`custom_${pluginId}_refresh`, refresh);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what this means. Are you saying it's not possible to deliver the data in the websocket message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is the definition of the function that is then executed in the websocket.
webapp/src/selectors.js
Outdated
export const getIssues = (state) => getPluginState(state).issues; | ||
export const getInIssues = (state) => getPluginState(state).inIssues; | ||
export const getOutIssues = (state) => getPluginState(state).outIssues; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These selectors should probably be doing this now:
export const getIssues = (state) => getPluginState(state).issues; | |
export const getInIssues = (state) => getPluginState(state).inIssues; | |
export const getOutIssues = (state) => getPluginState(state).outIssues; | |
export const getIssues = (state) => getAllIssues(state).my; | |
export const getInIssues = (state) => getAllIssues(state).in; | |
export const getOutIssues = (state) => getAllIssues(state).out; |
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #225 +/- ##
=========================================
- Coverage 6.42% 6.30% -0.13%
=========================================
Files 11 11
Lines 1712 1746 +34
=========================================
Hits 110 110
- Misses 1594 1628 +34
Partials 8 8
☔ View full report in Codecov by Sentry. |
I think I resolved all comment 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @jufab! I have just a few more suggestions
webapp/src/selectors.js
Outdated
export const getIssues = (state) => getPluginState(state).issues; | ||
export const getInIssues = (state) => getPluginState(state).inIssues; | ||
export const getOutIssues = (state) => getPluginState(state).outIssues; | ||
export const getIssues = (state) => getAllIssues(state).my; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we rename this to getMyIssues
?
export const getIssues = (state) => getAllIssues(state).my; | |
export const getMyIssues = (state) => getAllIssues(state).my; |
if err != nil { | ||
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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. I think we are changing the logic here, but I think we are actually fixing a bug. LGTM 👍
@@ -329,7 +319,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)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is a good bug fix here too. Nice work 👍
@@ -150,12 +152,12 @@ export default class SidebarRight extends React.PureComponent { | |||
|
|||
switch (this.state.list) { | |||
case MyListName: | |||
todos = this.props.allIssues.my || []; | |||
todos = this.props.myIssues || []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These empty arrays are going to cause re-renders. But this.props.myIssues
should always be defined anyway right? So these actually don't have an effect. Either way I think that this component shouldn't be responsible for this check
@@ -122,15 +124,15 @@ export default class SidebarRight extends React.PureComponent { | |||
} | |||
|
|||
getInIssues() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getInIssues() { | |
getInIssuesCount() { |
It looks like these 3 functions aren't actually called though. I think we can just remove them
@@ -51,7 +51,9 @@ const InListName = 'in'; | |||
|
|||
export default class SidebarRight extends React.PureComponent { | |||
static propTypes = { | |||
allIssues: PropTypes.arrayOf(PropTypes.object), | |||
myIssues: PropTypes.array, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -13,7 +13,9 @@ export default class SidebarButtons extends React.PureComponent { | |||
theme: PropTypes.object.isRequired, | |||
isTeamSidebar: PropTypes.bool, | |||
showRHSPlugin: PropTypes.func.isRequired, | |||
allIssues: PropTypes.object, | |||
myIssues: PropTypes.array, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
myIssues: PropTypes.array, | |
myIssues: PropTypes.array.isRequired, |
@@ -63,7 +67,7 @@ export default class SidebarButtons extends React.PureComponent { | |||
}} | |||
> | |||
<i className='icon icon-check'/> | |||
{' ' + allIssues && allIssues.my ? allIssues.my.length : 0} | |||
{' ' + myIssues ? myIssues.length : 0} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think myIssues
will always be defined right?
@jufab Is this ready for another review? Just wondering |
yes ready 😊 |
Do I have something else to do? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks @jufab!
msg := "Unable to get telemetry payload from JSON" | ||
p.API.LogError(msg, "err", err.Error()) | ||
p.handleErrorWithCode(w, http.StatusBadRequest, msg, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we do change the logging back the way it was for places unrelated the purpose of the PR, but I don't want to drag this PR on for that reason
Summary
I made a counter resource and used it for display counter on the team sidebar.
Ticket Link
Fixes #202