Skip to content
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

Split selection into two store modules and refactor complex rootSelectors #2787

Merged
merged 6 commits into from
Dec 9, 2020

Conversation

lyzadanger
Copy link
Contributor

@lyzadanger lyzadanger commented Dec 4, 2020

Motivation for these changes: we're about to add on to filtering capabilities in the app and the selection module has long been over-stretched and its responsibilities unclear. Managing yet more filtering in this single module seemed unwise. Also, there was some complex logic encapsulated in some rootSelectors for the benefit of some components and hooks that were smelly: they were causing store modules (and their states) to be too coupled.

This PR:

  • splits selection into two modules: selection and filters
  • Removes some selectors that were unused
  • Removes the large rootSelectors threadState, filterState and hasAppliedFilter in exchange for smaller supporting selectors to accomplish those computations. Components (FilterStatus, SidebarView) and a hook (useRootThread) now have more logic in them to munge these state objects together, instead of relying on the monster rootSelectors.
  • Restructures the threading integration tests to use the useRootThread hook instead of calling threadAnnotations directly.

This is a large diff. I'll add copious commenting and point out some large swaths that aren't new code, just relocated code. It may also be useful to walk through the commits.

Supports hypothesis/product-backlog#1161

@codecov
Copy link

codecov bot commented Dec 4, 2020

Codecov Report

Merging #2787 (dd36aa3) into master (6e64cc7) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #2787   +/-   ##
=======================================
  Coverage   97.74%   97.74%           
=======================================
  Files         202      203    +1     
  Lines        7664     7674   +10     
  Branches     1694     1694           
=======================================
+ Hits         7491     7501   +10     
  Misses        173      173           
Impacted Files Coverage Δ
src/sidebar/store/index.js 100.00% <ø> (ø)
src/sidebar/util/thread-annotations.js 100.00% <ø> (ø)
src/sidebar/components/filter-status.js 98.61% <100.00%> (+0.12%) ⬆️
src/sidebar/components/hooks/use-root-thread.js 100.00% <100.00%> (ø)
src/sidebar/components/sidebar-view.js 100.00% <100.00%> (ø)
src/sidebar/store/modules/annotations.js 97.70% <100.00%> (+0.02%) ⬆️
src/sidebar/store/modules/filters.js 100.00% <100.00%> (ø)
src/sidebar/store/modules/selection.js 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6e64cc7...dd36aa3. Read the comment docs.

Copy link
Contributor

@LMS007 LMS007 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid improvement in readability and separation of logic. I had some questions below, once sorted out, I think we can merge.


function init(settings) {
return {
filters: {},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry if this is the dumbest question yet, but what is "filters" for?

Copy link
Contributor Author

@lyzadanger lyzadanger Dec 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A most not-at-ALL-dumb question! I entirely forgot to explain!

I've prototyped some filtering for the Notebook on another branch. This current work you see here is to prepare the path for implementing that type of filtering. The imminent features will make use of this object.

Right now, it does precisely nothing!

It could be argued that this object shouldn't even be in this changeset. I'll see how easy it is to remove for now.

Copy link
Contributor

@LMS007 LMS007 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good by me Lyza.

@robertknight robertknight self-assigned this Dec 7, 2020
@robertknight
Copy link
Member

I assigned myself at Lyza's request to take another look over a few details. See https://hypothes-is.slack.com/archives/C1M8NH76X/p1607357690172800.

Copy link
Member

@robertknight robertknight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Lyza,

I've had a look over this. At a high level the changes look good. I did flag an issue about the overhead added by calling useStore many times within a single component, but I think we can address that separately.

One issue I did find is that the change to the way threadAnnotations is called has broken its memoization. Every time useRootThread is called it builds a new thread. See the test case I added in the comments.

/**
* @typedef Focus
* @prop {boolean} configured - Focus config contains valid `user` and
* is good to go
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the configured state be derived from other state? If so, it may be preferable to eliminate it to prevent issues where its value is inconsistent with the rest of the state (eg. configured is true but some other state is missing).

If it is not possible to derive it, it would be useful to clarify here why not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Permission to address this in next change set? filters will be touched immediately again for implementing a user filter in the notebook, and this is a pre-existing issue (and this diff is hugemongous).

Copy link
Member

@robertknight robertknight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is good to go now, but please have a look over a couple of comments in this review and also notes from my previous one.

The `selection` store module has become overlong and
its responsibilities aren't clear. We know we'll be
adding some more filtering capabilities to the app
in the next short while, and that would make
`selection` even more complex and heavy.

Split into two store modules: `selection` and
`filters`.

Temporarily re-implement `rootSelector`s that
are needed for generating thread and filter
state for components.
Refactor the computation of "filter state", that
is, all of the store state that impacts what
constitutes applied filters on annotations.
Eliminate the enormous `threadState` `rootSelector`
and re-implement as multiple selectors. Refactor
`useRootThread` and threading integration tests
to account for these changes.
Refactor selectors for evaluating `hasAppliedFilter`
to remove cross-module state dependencies.
Remove unused selector and tidy up reference ordering
Also convert `selectionState` to use `createSelector` to avoid it
returning a different reference on each call.
@lyzadanger lyzadanger merged commit 945825d into master Dec 9, 2020
@lyzadanger lyzadanger deleted the filter-store branch December 9, 2020 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants