Fixes T1363: move file success to task and listen to DB event

Test Plan: edgehill --test

Reviewers: bengotow

Reviewed By: bengotow

Maniphest Tasks: T1363

Differential Revision: https://phab.nylas.com/D1548
This commit is contained in:
Evan Morikawa 2015-05-21 13:43:14 -07:00
parent 8b7509e50d
commit f97a3a7b86
5 changed files with 45 additions and 44 deletions

View file

@ -6,6 +6,7 @@ Message = require '../../src/flux/models/message'
Actions = require '../../src/flux/actions' Actions = require '../../src/flux/actions'
NamespaceStore = require "../../src/flux/stores/namespace-store" NamespaceStore = require "../../src/flux/stores/namespace-store"
DraftStore = require "../../src/flux/stores/draft-store"
FileUploadTask = proxyquire "../../src/flux/tasks/file-upload-task", FileUploadTask = proxyquire "../../src/flux/tasks/file-upload-task",
fs: fs:
@ -79,6 +80,14 @@ describe "FileUploadTask", ->
spyOn(NylasAPI, 'makeRequest').andCallFake (reqParams) => spyOn(NylasAPI, 'makeRequest').andCallFake (reqParams) =>
reqParams.success(testResponse) if reqParams.success reqParams.success(testResponse) if reqParams.success
return @req return @req
@testFiles = []
@changes = []
spyOn(DraftStore, "sessionForLocalId").andCallFake =>
Promise.resolve(
draft: => files: @testFiles
changes:
add: ({files}) => @changes = files
)
it "notifies when the task starts remote", -> it "notifies when the task starts remote", ->
waitsForPromise => waitsForPromise =>
@ -93,18 +102,13 @@ describe "FileUploadTask", ->
expect(options.method).toBe('POST') expect(options.method).toBe('POST')
expect(options.formData.file.value).toBe("Read Stream") expect(options.formData.file.value).toBe("Read Stream")
it "passes the file to the completed notification function", -> it "attaches the file to the draft", ->
spyOn(@task, "_completedNotification").andReturn(100)
waitsForPromise => @task.performRemote().then => waitsForPromise => @task.performRemote().then =>
expect(@task._completedNotification).toHaveBeenCalledWith(equivalentFile) expect(@changes).toEqual [equivalentFile]
describe "file upload notifications", -> describe "file upload notifications", ->
beforeEach -> beforeEach ->
@fileUploadFiredLast = false spyOn(Actions, "fileUploaded")
spyOn(Actions, "attachFileComplete").andCallFake =>
@fileUploadFiredLast = false
spyOn(Actions, "fileUploaded").andCallFake =>
@fileUploadFiredLast = true
spyOn(@task, "_getBytesUploaded").andReturn(1000) spyOn(@task, "_getBytesUploaded").andReturn(1000)
runs => runs =>
@ -113,16 +117,6 @@ describe "FileUploadTask", ->
waitsFor -> waitsFor ->
Actions.fileUploaded.calls.length > 0 Actions.fileUploaded.calls.length > 0
it "calls the `attachFileComplete` action first", ->
runs ->
expect(@fileUploadFiredLast).toBe true
it "correctly fires the attachFileComplete action", ->
runs ->
expect(Actions.attachFileComplete).toHaveBeenCalledWith
file: equivalentFile
messageLocalId: localId
it "correctly fires the fileUploaded action", -> it "correctly fires the fileUploaded action", ->
runs -> runs ->
expect(Actions.fileUploaded).toHaveBeenCalledWith expect(Actions.fileUploaded).toHaveBeenCalledWith

View file

@ -93,7 +93,6 @@ class Actions
@fileAborted: ActionScopeGlobal @fileAborted: ActionScopeGlobal
@downloadStateChanged: ActionScopeGlobal @downloadStateChanged: ActionScopeGlobal
@fileUploaded: ActionScopeGlobal @fileUploaded: ActionScopeGlobal
@attachFileComplete: ActionScopeGlobal
@multiWindowNotification: ActionScopeGlobal @multiWindowNotification: ActionScopeGlobal
@sendDraftSuccess: ActionScopeGlobal @sendDraftSuccess: ActionScopeGlobal
@sendToAllWindows: ActionScopeGlobal @sendToAllWindows: ActionScopeGlobal
@ -400,12 +399,24 @@ class Actions
@createTemplate: ActionScopeWindow @createTemplate: ActionScopeWindow
@showTemplates: ActionScopeWindow @showTemplates: ActionScopeWindow
###
Public: Remove a file from a draft.
*Scope: Window*
```
Actions.removeFile
file: fileObject
messageLocalId: draftLocalId
```
###
@removeFile: ActionScopeWindow
# File Actions # File Actions
# Some file actions only need to be processed in their current window # Some file actions only need to be processed in their current window
@attachFile: ActionScopeWindow @attachFile: ActionScopeWindow
@attachFilePath: ActionScopeWindow @attachFilePath: ActionScopeWindow
@abortUpload: ActionScopeWindow @abortUpload: ActionScopeWindow
@removeFile: ActionScopeWindow
@fetchAndOpenFile: ActionScopeWindow @fetchAndOpenFile: ActionScopeWindow
@fetchAndSaveFile: ActionScopeWindow @fetchAndSaveFile: ActionScopeWindow
@fetchFile: ActionScopeWindow @fetchFile: ActionScopeWindow

View file

@ -45,6 +45,8 @@ class DraftChangeSet
DatabaseStore = require './database-store' DatabaseStore = require './database-store'
DatabaseStore.findByLocalId(Message, @localId).then (draft) => DatabaseStore.findByLocalId(Message, @localId).then (draft) =>
if not draft
throw new Error("Tried to commit a draft that had already been removed from the database. DraftId: #{@localId}")
draft = @applyToModel(draft) draft = @applyToModel(draft)
DatabaseStore.persistModel(draft).then => DatabaseStore.persistModel(draft).then =>
@_pending = {} @_pending = {}
@ -123,7 +125,8 @@ class DraftStoreProxy
# Is this change an update to our draft? # Is this change an update to our draft?
myDraft = _.find(change.objects, (obj) => obj.id == @_draft.id) myDraft = _.find(change.objects, (obj) => obj.id == @_draft.id)
if myDraft if myDraft
@_setDraft(myDraft) @_draft = _.extend @_draft, myDraft
@trigger()
_onDraftSwapped: (change) -> _onDraftSwapped: (change) ->
# A draft was saved with a new ID. Since we use the draft ID to # A draft was saved with a new ID. Since we use the draft ID to

View file

@ -59,7 +59,6 @@ class DraftStore
@listenTo Actions.destroyDraft, @_onDestroyDraft @listenTo Actions.destroyDraft, @_onDestroyDraft
@listenTo Actions.removeFile, @_onRemoveFile @listenTo Actions.removeFile, @_onRemoveFile
@listenTo Actions.attachFileComplete, @_onAttachFileComplete
atom.onBeforeUnload @_onBeforeUnload atom.onBeforeUnload @_onBeforeUnload
@ -165,6 +164,7 @@ class DraftStore
return unless change.objectClass is Message.name return unless change.objectClass is Message.name
containsDraft = _.some(change.objects, (msg) -> msg.draft) containsDraft = _.some(change.objects, (msg) -> msg.draft)
return unless containsDraft return unless containsDraft
@trigger(change)
_isMe: (contact={}) => _isMe: (contact={}) =>
contact.email is NamespaceStore.current().me().email contact.email is NamespaceStore.current().me().email
@ -390,12 +390,6 @@ class DraftStore
continue unless extension.finalizeSessionBeforeSending continue unless extension.finalizeSessionBeforeSending
extension.finalizeSessionBeforeSending(session) extension.finalizeSessionBeforeSending(session)
_onAttachFileComplete: ({file, messageLocalId}) =>
@sessionForLocalId(messageLocalId).then (session) ->
files = _.clone(session.draft().files) ? []
files.push(file)
session.changes.add({files}, true)
_onRemoveFile: ({file, messageLocalId}) => _onRemoveFile: ({file, messageLocalId}) =>
@sessionForLocalId(messageLocalId).then (session) -> @sessionForLocalId(messageLocalId).then (session) ->
files = _.clone(session.draft().files) ? [] files = _.clone(session.draft().files) ? []

View file

@ -41,14 +41,9 @@ class FileUploadTask extends Task
try try
json = JSON.parse(rawResponseString) json = JSON.parse(rawResponseString)
file = (new File).fromJSON(json[0]) file = (new File).fromJSON(json[0])
Actions.uploadStateChanged @_uploadData("completed")
@_completedNotification(file)
clearInterval(@progress)
@req = null
resolve()
catch error catch error
reject(error) reject(error)
@_onRemoteSuccess(file, resolve, reject)
@progress = setInterval => @progress = setInterval =>
Actions.uploadStateChanged(@_uploadData("progress")) Actions.uploadStateChanged(@_uploadData("progress"))
@ -90,17 +85,21 @@ class FileUploadTask extends Task
Actions.postNotification({message: msg, type: "error"}) Actions.postNotification({message: msg, type: "error"})
Actions.uploadStateChanged @_uploadData("failed") Actions.uploadStateChanged @_uploadData("failed")
# The `fileUploaded` action is needed to notify all other windows (like _onRemoteSuccess: (file, resolve, reject) =>
# composers) that the file has finished uploading. clearInterval(@progress)
_completedNotification: (file) -> @req = null
setTimeout => @_attachFileToDraft(file).then =>
# We need these to be two separate actions in this sequence so Actions.uploadStateChanged @_uploadData("completed")
# stores (like the DrafStore) can attach the file to their objects
# before we take action (like sending and closing the message) upon
# upload completion
Actions.attachFileComplete({file, @messageLocalId})
Actions.fileUploaded(uploadData: @_uploadData("completed")) Actions.fileUploaded(uploadData: @_uploadData("completed"))
, 1000 # To see the success state for a little bit resolve()
.catch(reject)
_attachFileToDraft: (file) ->
DraftStore = require '../stores/draft-store'
DraftStore.sessionForLocalId(@messageLocalId).then (session) =>
files = _.clone(session.draft().files) ? []
files.push(file)
return session.changes.add({files}, true)
_formData: -> _formData: ->
file: # Must be named `file` as per the Nylas API spec file: # Must be named `file` as per the Nylas API spec