Commit graph

324 commits

Author SHA1 Message Date
Ben Gotow f1c0a1615d fix(focus): Remove focusedField in favor of imperative focus, break apart ComposerView
Summary:
- Removes controlled focus in the composer!
  - No React components ever perfom focus in lifecycle methods. Never again.
  - A new `Utils.schedule({action, after, timeout})` helper makes it easy to say "setState or load draft, etc. and then focus"
  - The DraftStore issues a focusDraft action after creating a draft, which causes the MessageList to focus and scroll to the desired composer, which itself decides which field to focus.
  - The MessageList never focuses anything automatically.
- Refactors ComposerView apart — ComposerHeader handles all top fields, DraftSessionContainer handles draft session initialization and exposes props to ComposerView
  - ComposerHeader now uses a KeyCommandRegion (with focusIn and focusOut) to do the expanding and collapsing of the participants fields. May rename that container very soon.
- Removes all CommandRegistry handling of tab and shift-tab. Unless you preventDefault, the browser does it's thing.
- Removes all tabIndexes greater than 1. This is an anti-pattern—assigning everything a tabIndex of 0 tells the browser to move between them based on their order in the DOM, and is almost always what you want.
- Adds "TabGroupRegion" which allows you to create a tab/shift-tabbing group, (so tabbing does not leave the active composer). Can't believe this isn't a browser feature.

Todos:
- Occasionally, clicking out of the composer contenteditable requires two clicks. This is because atomicEdit is restoring selection within the contenteditable and breaking blur.
- Because the ComposerView does not render until it has a draft, we're back to it being white in popout composers for a brief moment. We will fix this another way - all the "return unless draft" statements were untenable.
- Clicking a row in the thread list no longer shifts focus to the message list and focuses the last draft. This will be restored soon.

Test Plan: Broken

Reviewers: juan, evan

Reviewed By: juan, evan

Differential Revision: https://phab.nylas.com/D2814
2016-04-04 15:22:01 -07:00
Ben Gotow c836310fac fix(autolinker): Update regexp to handle reported failure cases 2016-03-31 16:36:23 -07:00
Ben Gotow 0211304f1a fix(inline): Use vw for max-width, use DOM rather than regex 2016-03-31 15:16:22 -07:00
Ben Gotow d49c205dc8 fix(inline): radial progress, merge body with download data on render 2016-03-31 15:16:21 -07:00
Ben Gotow 886328ff7a bump(react): 0.13.2 => 0.14.7
Great breakdown of React changes here:
https://github.com/facebook/react/blob/master/CHANGELOG.md#0140-october-7-2015

Due to deprecation warnings, I don't think this will break third-party extensions unless they were doing really bad things.
2016-03-29 01:43:12 -07:00
Ben Gotow 7b3018699f fix(autolinker): Don't include trailing ? or . in URLs 2016-03-24 16:35:11 -07:00
Ben Gotow 4d65dbf9bf fix(autolinker): Only match top ten tld's when schme not present 2016-03-24 10:14:47 -07:00
Ben Gotow 52e8e57e4a perf(autolinker): Use requestIdleCallback to fix hanging on large bodies 2016-03-23 19:03:21 -07:00
Juan Tejada 9a800bf4ef fix(styles): Fix styles for attachment and upload items 2016-03-23 17:16:25 -07:00
Ben Gotow c265cf0dfa fix(drafts): Formalize draft factory, add reply "behaviors" #1722
Summary:
This diff implements a behavior change described in https://github.com/nylas/N1/issues/1722.

Reply buttons should prefer to focus an existing draft in reply to the same message, if one is pristine, altering it as necessary to switch between reply / reply-all. If no pristine reply is already there, it creates one.

Reply keyboard shortcuts should do the same, but more strictly - the shortcuts should switch between reply / reply-all for an existing draft regardless of whether it's pristine.

This diff also cleans up the DraftStore and moves all the draft creation itself to a new DraftFactory object. This makes it much easier to see what's going on in the DraftStore, and I also refactored away the "newMessageWithContext" method, which was breaking the logic for Reply vs Forward between a bunch of different helper methods and was hard to follow.

Test Plan: They're all wrecked. Will fix after concept is greenlighted

Reviewers: evan, juan

Reviewed By: juan

Differential Revision: https://phab.nylas.com/D2776
2016-03-22 15:47:51 -07:00
Juan Tejada fce1673aac feat(download-all): Adds download-all button + style updates, more ES6
Summary:
- Adds initial version of download all button
- Converts attachments plugin to ES6 and adds updated styling
- Updates quoted text button
- #905, #1712

Test Plan: - Unit + manual

Reviewers: evan, bengotow

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D2769
2016-03-21 18:23:26 -07:00
Juan Tejada 687597134d feat(selection): Add new display for selection count + update toolbar
Summary:
- New behavior is that the in split mode, you will perform actions on
  the selection via the MessageListToolbar (the toolbar positioned above
  the message list)
- Refactored and moved around a bunch of code to achieve this:
  - Mostly renaming stuff and moving stuff around and removing some
    duplication
  - Update naming of toolbar role to a single role, and update relevant code
  - Converted and refactored a bunch of code into ES6, specifically to reuse the code for the ThreadActionsToolbar at the 2 locations
  - Deprecated MultiselectActionBar in favor of MultiselectToolbar
  - Deprecated old roles
- Punted the animation for the stackable cards in the selection display for now.
- #370

Test Plan: - Manual and unit tests

Reviewers: evan, drew, bengotow

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D2756
2016-03-21 12:20:11 -07:00
Jackie Luo 76d478b677 refactor(ui-variables): Clean UI variables for consistency/usage
Summary: Shortens and simplifies UI variables so that unused variables are no longer present.

Test Plan: Tested locally.

Reviewers: evan, bengotow

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D2738
2016-03-15 11:18:50 -07:00
Ben Gotow 84b9741fa6 fix(autolinker): Additional phone number parsing specs 2016-03-15 11:04:00 -07:00
Ben Gotow 92e8a2a7d4 fix(autolinker): Add more test cases, improv URL regex 2016-03-15 10:47:14 -07:00
Ben Gotow 465831175a rm(autolinker): Use our own very simple autolinker
Summary:
Autolinker is a great open source project but it attempts to parse HTML with regexp, is quite slow, and hangs on specific emails https://github.com/nylas/N1/issues/1540

This is super bad, and also super unnecessary. I think this should do the trick.

Note: I changed the urlRegex in our Utils to be much more liberal. It now matches anything that looks like a URL, not just things with the http:// and https:// prefixes. It's used in the LinkEditor and onboarding screen (detecting auth errors with urls) and I think it should be ok?

Test Plan: Need to write some tests

Reviewers: evan, juan

Reviewed By: juan

Differential Revision: https://phab.nylas.com/D2725
2016-03-14 12:30:54 -07:00
Ben Gotow 0533cf3cb3 fix(labels): Do not re-use mail labels if they're removable 2016-03-10 17:08:42 -08:00
Ben Gotow 21e19cab50 fix(bodies): Message with empty string body showed loading forever 2016-03-10 16:13:17 -08:00
Ben Gotow 716533b9f1 fix(messages): Replace calc with margin to make plugin styling easier 2016-03-10 15:31:05 -08:00
Juan Tejada 76036e82bd fix(gmail-labels): Constraint so threads always belong to all,spam or trash
Summary:
- In Gmail all threads /must/ belong to either All Mail, Trash and Spam, and
  they are mutually exclusive, so we need to make sure that any add/remove
  label operation still guarantees that constraint
- Update ChangeLabelsTask to modify the set of labels to add and remove
  based on this rule
- Update tasksFor archiving, moving to trash and moving to spam so they
  don't affect any other labels in the thread, as gmail does.
- Removing from view /will/ remove any current labels, but will also
  move between all mail and trash as needed
- Remove Inbox, Trash and Spam from the CategoryPicker, as Gmail does

Test Plan: - Unit tests

Reviewers: drew, evan, bengotow

Reviewed By: drew, evan, bengotow

Differential Revision: https://phab.nylas.com/D2715
2016-03-10 14:13:31 -08:00
Evan Morikawa 47e2ef8436 fix(sidebar): minor sidebar style and padding tweaks 2016-03-10 15:06:59 -05:00
Ben Gotow 7771f8c4f4 fix(bodies): MBP should cache "" so that it updates when new body arrives 2016-03-09 19:14:54 -08:00
Ben Gotow b1ab520d0e fix(bodies): Move loading into component, add retry, loading spinner 2016-03-09 19:14:54 -08:00
Ben Gotow 232dd13660 Revert "fix(autolinker): PR accepted into 0.24.1, fixes #839"
This reverts commit 2a7a97eebc.
2016-03-09 15:21:27 -08:00
Evan Morikawa 571a464f7e fix(search): search perf and fix css issues 2016-03-09 18:12:06 -05:00
Evan Morikawa f8e52e7a0d fix(spec): fix message timestamp spec 2016-03-09 16:44:44 -05:00
Evan Morikawa c616ded318 feat(sidebar): add timestamps to related messages 2016-03-09 16:17:20 -05:00
Evan Morikawa 2d972ea462 fix(sidebar): ui tweaks to narrow sidebar 2016-03-09 15:46:10 -05:00
Juan Tejada 3d4e8054e3 fix(warning): Remove unused Popover require 2016-03-09 12:11:16 -08:00
Evan Morikawa 58004b29a7 feat(sidebar): Add thread list of currently selected participants
Summary:
WIP. I added a collection index to make displaying the threads of a
currently selected participant on the sidebar easy and fast.

The problem is that the `participants` of a thread, while a collection of
`Contact` objects, have no "ids" for those contact objects.

One idea was to create the join table but access contacts by email instead
of id. This required a minor change to the way the data is entered in the
join table.

This means the sidebar can now simply do:

`DatabaseStore.findAll(Thread).where(Thread.attributes.participants.contains('foo@bar.com'))`

While I didn't for this initial test, we could also/instead create the
`Message-Contact` join table. The trick about a Message-Contact table is
that I believe we'd have to create additional columns further specifying
which field we're interested in.

The following two queries:

`DatabaseStore.findAll(Message).where(Message.attributes.to.contains('foo@bar.com'))`

`DatabaseStore.findAll(Message).where(Message.attributes.from.contains('foo@bar.com'))`

would require additional columns in the `Message-Contact` join table
because currently the only columns are `id` and `value`.

In the case of the sidebar use case, I think the Thread participants is
what you want to see anyway.

Unfortunately an email-centric scheme can't distinguish between
`noreply@phab.com <Evan>` and `noreply@phab.com <Juan>`. I actually think
this may be a good thing since I think most people think in terms of email
address as the unique key anyway and for the use case of showing related
emails in the sidebar I'd rather overshow than undershow.

This solution seems to be working pretty well in initial testing, but I
want to see if you guys can think of anything this may subtly screw up
down the line, or if you can think of a simpler way to do this.

Test Plan: todo

Reviewers: juan, bengotow

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D2687
2016-03-09 14:33:31 -05:00
Ben Gotow 3c0b86233d fix(body-processor): Observe the db to clear cache. Fixes #1133
Summary:

Test Plan:

Reviewers:

Subscribers:
2016-03-08 13:14:06 -08:00
Ben Gotow 2a7a97eebc fix(autolinker): PR accepted into 0.24.1, fixes #839 2016-03-08 10:22:08 -08:00
Drew Regitsky 8961781ed5 fix(msg-ctrls): reorder hidden options to reduce accidental error reports 2016-03-07 18:24:31 -08:00
Juan Tejada 37af2ba42c fix(remove-from-view): Fix logic for delete/remove-from-view behavior:
Summary:
- Separate gmail's remove-from-view and delete behaviors and write logic
  for each of those
  - Remove MailboxPerspective::{canArchiveThreads, canTrashThreads,
    removeThreads} and some unecessary code in TaskFactory
  - Instead, add MailboxPerspective::tasksForRemovingFromPerspective (I
    know its a bit of a mouthful)
  - I initially tried to put all of the logic for each execution path
    inside the TaskFactory by checking perspective types, but it made
    more sense to use the polymorphism already in place for the different
    perspective types.
  - There is a default delete/remove-from-view behavior which is
    configurable via simple ruleset objects. The gmail behavior is
    configured in this way.
- Update swipe css classes based on destination of threads
- Fixes #1460:
  - Update logic to display archive/trash buttons and context menu options correctly
    when selected threads can be archived/trashed (not based on
    perspective)
  - Same for swiping
- Add a bunch of specs
- Convert some code to ES6
- TODO write some docs for new functions

Test Plan: Unit tests

Reviewers: drew, evan, bengotow

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D2682
2016-03-07 18:16:37 -08:00
Ben Gotow a8a0154c44 fix(MessageContainer): Fix state, prevent from getting different messages. #1175
Summary:
This fixes a serious issue where drafts could appear to be sending if
they were located in the same index of the message list as a draft which was
previously sending.

Under the hood this was due to two bad programming choices:

1) State based on props in MessageContainer requires correct implementation of
   componentWillReceiveProps. This is definitely an anti-pattern.

2) Using item index rather than clientId as the key for items in the MessageList
   caused containers to be given a different message prop when one was inserted,
   rather than just shifting the existing ones down and inserting a new one.

Test Plan: Not sure how to test this really...

Reviewers: drew, juan

Differential Revision: https://phab.nylas.com/D2673
2016-03-03 12:10:03 -08:00
Evan Morikawa 9a576015ed fix(find-in-thread): minor rename fixes 2016-03-02 15:00:01 -08:00
Evan Morikawa 800f3a041b feat(find-in-thread): add the ability to find in a thread
Summary: Find in thread

Test Plan: todo

Reviewers: bengotow, juan

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D2660
2016-03-02 14:46:27 -08:00
Ben Gotow 53446f91ae fix(hidden-messages): Address diff feedback from @jstejada 2016-03-02 10:28:32 -08:00
Ben Gotow f413386b80 feat(hidden-messages): Filter trash/spam messages. Fixes #1135
Summary:
By default, the messages in a thread are now filtered to exclude
ones moved to trash or spam. You can choose to view those messages by clicking
the new bar in the message list.

When you view your spam or trash, we only show the messages on those threads
that have been marked as spam/trash.

Test Plan: Run a couple new tests

Reviewers: juan, evan

Reviewed By: evan

Differential Revision: https://phab.nylas.com/D2662
2016-03-02 10:05:17 -08:00
Drew Regitsky 8f184f2896 fix(message-controls): add accountId to debug values copied to clipboard 2016-02-26 15:13:33 -08:00
Ben Gotow 6ec0045677 💄(print): Fix #1425 2016-02-26 14:40:16 -08:00
Drew Regitsky 00109f28ef fix(message-controls): update email address for reporting 2016-02-26 12:29:11 -08:00
Drew Regitsky b93182920f feat(message-controls): Option to copy message IDs/metadata to clipboard 2016-02-26 12:26:20 -08:00
Evan Morikawa 4158e598e0 fix(tracking): tracking pixel won't register if it's from you 2016-02-24 12:55:00 -08:00
Evan Morikawa 9dd7a9600a fix(tracking): fix link tracking and read receipt plugins
Fix broken links in link tracking and read receipts

Fix bug in email frame where it wouldn't adjust the height even when
content changed

MessageItem bodies automatically clear the MessageBodyProcessor cache when
the message contents (including metadata) change.

Remove unused Account stuff from nylas-observables

Plugins appIds properly read if there's an environment set
2016-02-24 12:30:12 -08:00
Evan Morikawa dd6cefc3f8 fix(read-receipts): Style fixes to link tracking and read receipts 2016-02-23 18:58:07 -08:00
Evan Morikawa 9d11da4a5e feat(read-receipts): show status on MessageItem 2016-02-23 18:58:07 -08:00
Ben Gotow 592374c0dc feat(swipe-to-*): Gesture support and animation in thread list
Summary:
This diff does two things:
- It adds a new SwipeContainer that makes it easy to implement swipe gestures. This is built into listTabular, so you can create a list and define onSwipeLeft/Right to enable gestures.

- It adds support for basic add/remove animations to the thread list. This works by adding a CSS transition to `top` and also leaving removed rows around for a specified time. (these times need to match.) Pretty much just cloned the core idea from TimeoutTransitionGroup.

Test Plan: No tests yet

Reviewers: evan, juan

Reviewed By: evan

Differential Revision: https://phab.nylas.com/D2581
2016-02-19 18:22:28 -08:00
Ben Gotow 95aba56979 fix(sending): Tiny fix for strange vertical space when sending 2016-02-19 15:31:51 -08:00
Ben Gotow 98529dc7a8 fix(participants): Update specs to reflect that spacing is now in CSS 2016-02-19 10:28:02 -08:00