1. 21 Sep, 2016 1 commit
    • Robert Knight's avatar
      Simplify the sidebar app side of sidebar <-> host frame messaging · 55093ebb
      Robert Knight authored
      Previously the communication between the sidebar and host frame was
      implemented by a shared AnnotationSync class, with a 'crossframe'
      service which abstracted the event bus on each side.
      
      This design however assumed that both sides wanted to listen to
      the same messages and react to them in similar ways. This is not
      the case, especially given the change to use Redux for state
      management in the sidebar app.
      
      This commit replaces the crossframe service and AnnotationSync class
      with a new 'frameSync' service which implements only the event
      listeners and sidebar -> page RPC calls that are actually needed.
      
      As a result, local annotation tags for annotations loaded via the API
      can now be assigned by the reducer in the Redux store, making this
      easier to test and getting us another step closer to making Annotation
      objects immutable in the sidebar app.
      55093ebb
  2. 19 Sep, 2016 8 commits
  3. 16 Sep, 2016 4 commits
    • Robert Knight's avatar
      Only save pending updates for annotations in the focused group (#111) · 72859c5e
      Robert Knight authored
      Since we discard all pending updates and deletions when switching
      groups, discard create/update notifications about annotations in
      unfocused groups as soon as we receive them.
      
      This fixes the issue where the 'Apply Update' badge counted updates
      from other groups, with the result that clicking the badge did not
      show any changes.
      72859c5e
    • Robert Knight's avatar
      Move the logic that updates the focused group for new annotations (#108) · 7191e4ba
      Robert Knight authored
      Move the logic that updates the focused group for new annotations
      out of the <annotation> component and into a service.
      
      This fixes the issue where the event handler does not get invoked if no
      <annotation> component instance exists for an annotation because it is
      currently scrolled off-screen.
      
      Fixes #105
      7191e4ba
    • Robert Knight's avatar
      Fix stale copies of annotations being reloaded when switching groups (#110) · ead7c07d
      Robert Knight authored
      Previously when switching groups all of the currently loaded annotations
      would be unloaded and then potentially outdated copies of the annotation
      from the drafts store would be reloaded into the annotation store.
      
      This commit fixes that problem by:
      
       1. Only unloading saved annotations when switching groups.
      
       2. Only storing the annotation ID and tag in the drafts service, to
          ensure that we don't try to use it as a complete annotation anywhere
      
      A consequence of (1) is that new, unsaved annotations no-longer briefly
      disappear when switching groups.
      
      This fixes the problem described in #109 where the orphan status of a
      new annotation is lost when switching groups. It does not fix the
      problem where the new annotation immediately becomes an orphan.
      ead7c07d
    • Robert Knight's avatar
      Fix off-screen empty drafts not being removed when a new annotation is created (#107) · e6746f9a
      Robert Knight authored
      The logic to remove new and empty annotations used to live in the
      <annotation> component because that was the only part of the code that
      had access to the state of unsaved changes.
      
      Since <annotation> instances are only created for on-screen annotations,
      this can result in empty drafts not being removed if the empty
      annotation is off-screen.
      
      Now that the canonical content of unsaved annotations is stored in the
      drafts service, we can move the logic outside of the annotation
      component and fix this problem.
      
      Fixes #97
      e6746f9a
  4. 15 Sep, 2016 14 commits
  5. 14 Sep, 2016 5 commits
    • Robert Knight's avatar
      Add tests for reducer utility functions · 386edd12
      Robert Knight authored
      386edd12
    • Robert Knight's avatar
      Reduce boilerplate in annotationUI for exposing action creators and selectors · 2c70aeba
      Robert Knight authored
      Use helper functions to take the set of action creator and selector
      functions exported by each module and expose them on annotationUI.
      2c70aeba
    • Robert Knight's avatar
      Refactor reducers into a map of action type -> update function · ce7f1330
      Robert Knight authored
      Split the large switch statements in each reducer function
      into objects which map action types to state update functions.
      
      These functions are then composed together with a `createReducer`
      helper defined in `reducers/util`
      ce7f1330
    • Robert Knight's avatar
      Add intro documentation to explain how state management works · f913a4b0
      Robert Knight authored
      For the benefit of developers who are not familiar with Redux and
      Elm-style architectures, add documentation at the top of the
      annotationUI module which explains how state is managed in the app.
      f913a4b0
    • Robert Knight's avatar
      Refactor Redux store · ca72ca9a
      Robert Knight authored
      The `annotationUI` module evolved from before we used Redux to manage
      app state and it was getting large and doing too much. This PR splits
      out most of the logic into smaller modules in the `reducers` folder. The
      `annotationUI` module continues to present the same exports as before to
      avoid needing to change too much in one commit. Each module in `reducers/`
      defines:
      
       - An `init` function which returns the initial state relating to some
         aspect of the application
       - A set of action types, relating to that aspect of the application
       - An `update` function which processes those actions
       - A set of action creators, which are helper functions that create
         these actions
       - A set of selector functions, which are helper functions that return
         derived data from this state
      
      There is a root module in reducers/index.js which combines the actions,
      init function and update functions from each module into a single init
      and update function which can be used to initialize the Redux store.
      
      Action creators which require access to the current app state or are
      asynchronous, such as `addAnnotations` return thunks. See
      https://github.com/gaearon/redux-thunk#motivation . Several
      selection-related action creators currently return thunks but can be
      refactored in future into plain actions.
      
      To avoid making this commit too large, annotationUI continues to export
      wrappers around the action creators so that code outside the Redux store
      and tests do not need to be changed.
      ca72ca9a
  6. 13 Sep, 2016 8 commits
    • Robert Knight's avatar
      0.42.0 · 71e95f59
      Robert Knight authored
      71e95f59
    • Robert Knight's avatar
      Update Change Log · ecf45391
      Robert Knight authored
      ecf45391
    • Robert Knight's avatar
      Merge pull request #101 from hypothesis/fix-editor-sort · f59e84b3
      Robert Knight authored
      Add temporary timestamps to new annotations (for sorting)
      f59e84b3
    • Nick Stenning's avatar
      Add temporary timestamps to new annotations (for sorting) · 3b8ea633
      Nick Stenning authored
      Brand new annotations (and page notes) are currently displayed as editor
      widgets in the sidebar alongside all the existing annotation cards. This
      means they need to be sortable.
      
      Sorting by location isn't a problem, because the annotation already
      carries the document location information by the time it gets to
      `addAnnotations`, but sorting by the updated date is, because currently
      the `created` and `updated` fields are only provided when the server
      sends back the saved annotation.
      
      This commit changes that by adding temporary `created` and `updated`
      timestamps to new annotations (those without an ID). These will be
      ignored entirely by the server, and overwritten when the annotation is
      saved.
      
      If for whatever reason `addAnnotations` is called with a new annotation
      that already has these fields, they will not be overwritten.
      
      Fixes (the rest of) #96.
      3b8ea633
    • Robert Knight's avatar
      Merge pull request #100 from hypothesis/fix-unnecessary-sortkey-update · 042dd2f0
      Robert Knight authored
      Don't reset the sortKey unless actually switching tabs
      042dd2f0
    • Nick Stenning's avatar
      Don't reset the sortKey unless actually switching tabs · 2289e1c2
      Nick Stenning authored
      Creating a new annotation or page note would reset the sortKey for the
      sidebar to the default, because doing so can trigger a call to
      `selectTab`.
      
      This change ensures that we shortcut the state update if we're already
      on the correct tab, and don't update `sortKey` in that case.
      2289e1c2
    • Robert Knight's avatar
      Merge pull request #99 from hypothesis/sort-notes-tab · 593ec7c5
      Robert Knight authored
      Sort notes tab by date
      593ec7c5
    • Nick Stenning's avatar
      Sort notes tab by date · 2a11ea12
      Nick Stenning authored
      This commit prevents page notes from being sorted by "Location" (i.e.
      document location), a meaningless property for page notes, which would
      result in them being sorted unpredictably.
      
      Instead, we define a default sort key and a set of allowable sort keys
      for each sidebar tab. When switching between tabs, the sort key is
      updated to the default, and the set of allowable sort keys updated
      depending on the tab.
      
      This results in page notes being sorted (by default) in ascending order
      of their most recent update. Using "updated" rather than "created" is a
      bit dubious, but changing this requires a bit of care to avoid strange
      behaviour on the stream, so I've left that for another time.
      
      N.B. As implemented, the sort key on each tab will be reset to the
      default every time the tab changes. This is less surprising than
      preserving the sort key across tab switches, and doesn't involve any
      requirement to remember system state across tab switches. We can also
      revisit this in the future if it seems wrong.
      
      Fixes #96.
      2a11ea12