Commit graph

299 commits

Author SHA1 Message Date
Friedrich von Never 32efb09825 Settings: add 24-hour clock support 2016-06-06 14:31:57 -07:00
Jackie Luo 6713827e65 fix(email-frame): Allow events to bubble correctly and pass iframe 2016-05-27 15:18:12 -07:00
Juan Tejada a4ee61eadc fix(mail-merge): Refactor mass sending procedure
Summary:
This diff introduces several updates to mail merge to improve the procedure for sending a list of drafts.
Specifically, sending mass email will now:

- Clear mail merge metadata on the drafts that will actually be sent
- Upload attached files only /once/, and reuse those files on the drafts that will actually be sent
- Minimize database writes for new drafts being created
- Will queue a SendManyDraftsTask that will subsequently queue the necessary SendDraftTasks and keep track of them, and notify of any failed tasks

TODO:
- Add state to MailMerge plugin for failed sends and ability to attempt to re send them

Test Plan: - TODO

Reviewers: evan, bengotow, jackie

Reviewed By: bengotow, jackie

Subscribers: jackie

Differential Revision: https://phab.nylas.com/D2973
2016-05-24 17:22:09 -07:00
Ben Gotow 26d4361bfb bump(electron): Fix remaining deprecated requires, move to 1.0.1 2016-05-12 13:59:23 -07:00
Robert Stanfield be48fc4305 The horizontal scrollbar was not showing up when viewing an email (#2028) 2016-05-06 16:44:30 -07:00
Evan Morikawa 1498bcfac6 fix(lint): final linter fixes
fix(lint): final set of linter fixes
2016-05-06 16:32:34 -07:00
Ben Gotow 41ae914b9d fix(lint): Various linter fixes 2016-05-06 16:23:48 -07:00
Ben Gotow 42ef0e98a4 fix(lint): Various linter issues 2016-05-06 16:06:16 -07:00
Evan Morikawa 837627aa39 feat(babel6): 1,774 linter errors 2016-05-06 11:55:46 -07:00
Evan Morikawa 7f50074c0d feat(babel6): Convert to use new es6 require syntax 2016-05-06 11:54:55 -07:00
Evan Morikawa e2f9104766 feat(babel6): Initial babel conversion 2016-05-06 11:54:38 -07:00
Ben Gotow 74232d5b7e fix(tracking): Use colors for link/read receipts, fix parsing 2016-05-02 15:59:17 -07:00
Ben Gotow 4c537cbf8e fix(emoji): Replace message emoji in DOM, not in html string 2016-05-02 12:33:08 -07:00
Ben Gotow 05be74ec04 fix(read-receipts): Remove tracking pixels when composing drafts 2016-04-28 17:08:54 -07:00
John McNair dccf4f3ad3 Parse Office 365 names (#2016)
Office 365 likes to format email addresses as follows:
Last Name, First Name (Some Description) <email@address.org>

This causes Contact.firstName() (and hence sometimes displayName()) to return
"Last Name," which looks a bit odd in the message/thread views.

The intent of the commit is to correctly parse these names so that (using the
above example):
- firstName = "First Name"
- lastName = "Last Name (Some Description)"
- fullName = "First Name Last Name (Some Description)"

These behavioral changes only impact names containing a ','.

I don't know that this really provides exhaustive coverage of Office 365, and
keeping the description as part of the last name is not completely guilt free,
but it's not any worse than the previous state of affairs which also has
the description in the same field but combined instead with (misplaced)
first name data.
2016-04-27 10:26:23 -07:00
Ben Gotow 8944e10ae9 fix(autolinker): Don't match emails that are also URLs #2071 2016-04-26 19:03:43 -07:00
Ben Gotow c5a77fa854 fix(autolinker): Use getAttribute('href') because href is magic 2016-04-26 17:01:15 -07:00
Ben Gotow aa42040813 fix(autolinker): Always override title attribute #2056 2016-04-26 16:49:33 -07:00
Ben Gotow a48ddd51f8 refactor(menus): Major prune of keymaps/commands, real conditional menus
Summary:
Keymaps & menus CSON => JSON, remove AtomKeymaps, CommandRegistry use of CSS selectors, use Mousetrap instead

Important Notes:

- The `application:` prefix is reserved for commands which are handled in the application process. Don't use it for other things. You will not receive the events in the window.

- Maintaining dynamic menus seems to come with quite an overhead, because Electron updates the entire menu every time. In the future, we'll need https://github.com/electron/electron/issues/528 to really make things nice. I will be tracking this upstream.

- The format for keyboard shortcuts has changed. `cmd-X` is now `command+shift+x`

Test Plan: Run tests

Reviewers: juan, evan

Reviewed By: evan

Differential Revision: https://phab.nylas.com/D2917
2016-04-24 12:16:25 -05:00
Ben Gotow bb71529322 fix(attachments): Don't show the paperclip for inline attachments < 3k (signatures, etc.) 2016-04-20 10:44:32 -07:00
Ben Gotow 36ab9d593b feat(unread/spam): New items in the sidebar for unread and spam
Summary:
Adds a new unified "Spam" folder and a unified "Unread" view,
which shows all the messages in your inbox which are unread.

Test Plan: Run tests

Reviewers: evan, juan

Reviewed By: juan

Differential Revision: https://phab.nylas.com/D2901
2016-04-19 11:32:33 -07:00
Ben Gotow 0b4527bb03 fix(autoscale): Apply vw when width and height are not present 2016-04-07 18:02:04 -07:00
Juan Tejada cb46f8a9d8 fix(contact-sidebar): Don't render <select> when no contacts available 2016-04-07 09:57:53 -07:00
Juan Tejada 4c250640fe fix(react): Fix several warnings in missing imports 2016-04-05 14:53:37 -07:00
Ben Gotow d1b1c5bea2 fix(quoted-text): Correctly update container height 2016-04-05 14:27:54 -07:00
Ben Gotow b4434f6617 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 3d8133ff8d fix(inline): Use vw for max-width, use DOM rather than regex 2016-03-31 15:16:22 -07:00
Ben Gotow 78681f6ed1 fix(inline): radial progress, merge body with download data on render 2016-03-31 15:16:21 -07:00
Ben Gotow 39768fd9d4 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 75ff8282a8 perf(autolinker): Use requestIdleCallback to fix hanging on large bodies 2016-03-23 19:03:21 -07:00
Juan Tejada 9413459311 fix(styles): Fix styles for attachment and upload items 2016-03-23 17:16:25 -07:00
Ben Gotow 92bff6ca5a 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 96846d4052 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 e83bf2bbec 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
Ben Gotow c76582194a 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 7c2fd2a91b fix(labels): Do not re-use mail labels if they're removable 2016-03-10 17:08:42 -08:00
Ben Gotow 038032d68e fix(bodies): Message with empty string body showed loading forever 2016-03-10 16:13:17 -08:00
Juan Tejada f12896d54f 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
Ben Gotow 7a31da9fc9 fix(bodies): Move loading into component, add retry, loading spinner 2016-03-09 19:14:54 -08:00
Evan Morikawa 19682d8095 fix(search): search perf and fix css issues 2016-03-09 18:12:06 -05:00
Evan Morikawa 51906bd085 fix(spec): fix message timestamp spec 2016-03-09 16:44:44 -05:00
Evan Morikawa 89323b05db feat(sidebar): add timestamps to related messages 2016-03-09 16:17:20 -05:00
Juan Tejada a0a3247815 fix(warning): Remove unused Popover require 2016-03-09 12:11:16 -08:00
Evan Morikawa d4ef6a20e5 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 df9e3b7464 fix(body-processor): Observe the db to clear cache. Fixes #1133
Summary:

Test Plan:

Reviewers:

Subscribers:
2016-03-08 13:14:06 -08:00
Drew Regitsky eaf831efb4 fix(msg-ctrls): reorder hidden options to reduce accidental error reports 2016-03-07 18:24:31 -08:00
Juan Tejada 0d15c6cea6 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 9b54d9cf31 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 b727fe374d fix(find-in-thread): minor rename fixes 2016-03-02 15:00:01 -08:00
Evan Morikawa 10e0fcc965 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