mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-10-05 02:44:51 +08:00
Inits FileUploadStore from current state in the filesystem
- Removes uploads when draft is deleted - Misc fixes and renaming
This commit is contained in:
parent
752a749da7
commit
63d36a78c3
5 changed files with 60 additions and 26 deletions
|
@ -441,7 +441,7 @@ class ComposerView extends React.Component
|
||||||
|
|
||||||
<button className="btn btn-toolbar btn-attach" style={order: 50}
|
<button className="btn btn-toolbar btn-attach" style={order: 50}
|
||||||
title="Attach file"
|
title="Attach file"
|
||||||
onClick={@_selectFileForUpload}><RetinaImg name="icon-composer-attachment.png" mode={RetinaImg.Mode.ContentIsMask} /></button>
|
onClick={@_selectAttachment}><RetinaImg name="icon-composer-attachment.png" mode={RetinaImg.Mode.ContentIsMask} /></button>
|
||||||
|
|
||||||
<div style={order: 0, flex: 1} />
|
<div style={order: 0, flex: 1} />
|
||||||
|
|
||||||
|
@ -506,6 +506,7 @@ class ComposerView extends React.Component
|
||||||
files: draft.files
|
files: draft.files
|
||||||
subject: draft.subject
|
subject: draft.subject
|
||||||
accounts: @_getAccountsForSend()
|
accounts: @_getAccountsForSend()
|
||||||
|
uploads: FileUploadStore.uploadsForMessage(@props.draftClientId) ? []
|
||||||
|
|
||||||
if !@state.populated
|
if !@state.populated
|
||||||
_.extend state,
|
_.extend state,
|
||||||
|
@ -615,14 +616,14 @@ class ComposerView extends React.Component
|
||||||
_onDrop: (e) =>
|
_onDrop: (e) =>
|
||||||
# Accept drops of real files from other applications
|
# Accept drops of real files from other applications
|
||||||
for file in e.dataTransfer.files
|
for file in e.dataTransfer.files
|
||||||
Actions.attachFile({filePath: file.path, messageClientId: @props.draftClientId})
|
Actions.addAttachment({filePath: file.path, messageClientId: @props.draftClientId})
|
||||||
|
|
||||||
# Accept drops from attachment components / images within the app
|
# Accept drops from attachment components / images within the app
|
||||||
if (uri = @_nonNativeFilePathForDrop(e))
|
if (uri = @_nonNativeFilePathForDrop(e))
|
||||||
Actions.attachFile({filePath: uri, messageClientId: @props.draftClientId})
|
Actions.addAttachment({filePath: uri, messageClientId: @props.draftClientId})
|
||||||
|
|
||||||
_onFilePaste: (path) =>
|
_onFilePaste: (path) =>
|
||||||
Actions.attachFile({filePath: path, messageClientId: @props.draftClientId})
|
Actions.addAttachment({filePath: path, messageClientId: @props.draftClientId})
|
||||||
|
|
||||||
_onChangeParticipants: (changes={}) =>
|
_onChangeParticipants: (changes={}) =>
|
||||||
@_addToProxy(changes)
|
@_addToProxy(changes)
|
||||||
|
@ -744,8 +745,8 @@ class ComposerView extends React.Component
|
||||||
_destroyDraft: =>
|
_destroyDraft: =>
|
||||||
Actions.destroyDraft(@props.draftClientId)
|
Actions.destroyDraft(@props.draftClientId)
|
||||||
|
|
||||||
_selectFileForUpload: =>
|
_selectAttachment: =>
|
||||||
Actions.selectFileForUpload({messageClientId: @props.draftClientId})
|
Actions.selectAttachment({messageClientId: @props.draftClientId})
|
||||||
|
|
||||||
undo: (event) =>
|
undo: (event) =>
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
|
@ -27,7 +27,7 @@ class FileUpload extends React.Component
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
_onClickRemove: =>
|
_onClickRemove: =>
|
||||||
Actions.removeFileFromUpload @props.upload
|
Actions.removeAttachment @props.upload
|
||||||
|
|
||||||
_extension: =>
|
_extension: =>
|
||||||
path.extname(@props.upload.filename)[1..-1]
|
path.extname(@props.upload.filename)[1..-1]
|
||||||
|
|
|
@ -445,9 +445,9 @@ class Actions
|
||||||
|
|
||||||
# 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
|
@addAttachment: ActionScopeWindow
|
||||||
@selectFileForUpload: ActionScopeWindow
|
@selectAttachment: ActionScopeWindow
|
||||||
@removeFileFromUpload: ActionScopeWindow
|
@removeAttachment: ActionScopeWindow
|
||||||
@fetchAndOpenFile: ActionScopeWindow
|
@fetchAndOpenFile: ActionScopeWindow
|
||||||
@fetchAndSaveFile: ActionScopeWindow
|
@fetchAndSaveFile: ActionScopeWindow
|
||||||
@fetchFile: ActionScopeWindow
|
@fetchFile: ActionScopeWindow
|
||||||
|
|
|
@ -5,14 +5,16 @@ mkdirp = require 'mkdirp'
|
||||||
NylasStore = require 'nylas-store'
|
NylasStore = require 'nylas-store'
|
||||||
Actions = require '../actions'
|
Actions = require '../actions'
|
||||||
Utils = require '../models/utils'
|
Utils = require '../models/utils'
|
||||||
|
Message = require '../models/message'
|
||||||
|
DatabaseStore = require './database-store'
|
||||||
|
|
||||||
|
|
||||||
UPLOAD_DIR = path.join(NylasEnv.getConfigDirPath(), 'uploads')
|
UPLOAD_DIR = path.join(NylasEnv.getConfigDirPath(), 'uploads')
|
||||||
|
|
||||||
class Upload
|
class Upload
|
||||||
|
|
||||||
constructor: (@messageClientId, @originPath, @stats, @uploadDir = UPLOAD_DIR) ->
|
constructor: (@messageClientId, @originPath, @stats, @id, @uploadDir = UPLOAD_DIR) ->
|
||||||
@id = Utils.generateTempId()
|
@id ?= Utils.generateTempId()
|
||||||
@filename = path.basename(@originPath)
|
@filename = path.basename(@originPath)
|
||||||
@draftUploadDir = path.join(@uploadDir, @messageClientId)
|
@draftUploadDir = path.join(@uploadDir, @messageClientId)
|
||||||
@targetDir = path.join(@draftUploadDir, @id)
|
@targetDir = path.join(@draftUploadDir, @id)
|
||||||
|
@ -23,30 +25,38 @@ class Upload
|
||||||
class FileUploadStore extends NylasStore
|
class FileUploadStore extends NylasStore
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
@listenTo Actions.selectFileForUpload, @_onSelectFileForUpload
|
@listenTo Actions.selectAttachment, @_onSelectAttachment
|
||||||
@listenTo Actions.attachFile, @_onAttachFile
|
@listenTo Actions.addAttachment, @_onAddAttachment
|
||||||
@listenTo Actions.removeFileFromUpload, @_onRemoveUpload
|
@listenTo Actions.removeAttachment, @_onRemoveAttachment
|
||||||
|
@listenTo DatabaseStore, @_onDataChanged
|
||||||
|
|
||||||
# We don't save uploads to the DB, we keep it in memory in the store.
|
mkdirp.sync(UPLOAD_DIR)
|
||||||
# The key is the messageClientId. The value is a hash of paths and
|
@_fileUploads = @_getFileUploadsFromFs()
|
||||||
# corresponding upload data.
|
|
||||||
@_fileUploads = {}
|
|
||||||
mkdirp(UPLOAD_DIR)
|
|
||||||
|
|
||||||
uploadsForMessage: (messageClientId) ->
|
uploadsForMessage: (messageClientId) ->
|
||||||
@_fileUploads[messageClientId] ? []
|
@_fileUploads[messageClientId] ? []
|
||||||
|
|
||||||
_onSelectFileForUpload: ({messageClientId}) ->
|
|
||||||
|
# Handlers
|
||||||
|
|
||||||
|
_onDataChanged: (change) =>
|
||||||
|
return unless change.objectClass is Message.name and change.type is 'unpersist'
|
||||||
|
change.objects.forEach (message) =>
|
||||||
|
uploads = @_fileUploads[message.clientId]
|
||||||
|
if uploads?
|
||||||
|
uploads.forEach (upload) => @_onRemoveAttachment(upload)
|
||||||
|
|
||||||
|
_onSelectAttachment: ({messageClientId}) ->
|
||||||
@_verifyId(messageClientId)
|
@_verifyId(messageClientId)
|
||||||
# When the dialog closes, it triggers `Actions.attachFile`
|
# When the dialog closes, it triggers `Actions.addAttachment`
|
||||||
NylasEnv.showOpenDialog {properties: ['openFile', 'multiSelections']}, (pathsToOpen) ->
|
NylasEnv.showOpenDialog {properties: ['openFile', 'multiSelections']}, (pathsToOpen) ->
|
||||||
return if not pathsToOpen?
|
return if not pathsToOpen?
|
||||||
pathsToOpen = [pathsToOpen] if _.isString(pathsToOpen)
|
pathsToOpen = [pathsToOpen] if _.isString(pathsToOpen)
|
||||||
|
|
||||||
pathsToOpen.forEach (filePath) ->
|
pathsToOpen.forEach (filePath) ->
|
||||||
Actions.attachFile({messageClientId, filePath})
|
Actions.addAttachment({messageClientId, filePath})
|
||||||
|
|
||||||
_onAttachFile: ({messageClientId, filePath}) ->
|
_onAddAttachment: ({messageClientId, filePath}) ->
|
||||||
@_verifyId(messageClientId)
|
@_verifyId(messageClientId)
|
||||||
@_getFileStats({messageClientId, filePath})
|
@_getFileStats({messageClientId, filePath})
|
||||||
.then(@_makeUpload)
|
.then(@_makeUpload)
|
||||||
|
@ -56,7 +66,7 @@ class FileUploadStore extends NylasStore
|
||||||
.then(@_saveUpload)
|
.then(@_saveUpload)
|
||||||
.catch(@_onAttachFileError)
|
.catch(@_onAttachFileError)
|
||||||
|
|
||||||
_onRemoveUpload: (upload) ->
|
_onRemoveAttachment: (upload) ->
|
||||||
return unless (@_fileUploads[upload.messageClientId] ? []).length > 0
|
return unless (@_fileUploads[upload.messageClientId] ? []).length > 0
|
||||||
@_deleteUpload(upload)
|
@_deleteUpload(upload)
|
||||||
.then (upload) =>
|
.then (upload) =>
|
||||||
|
@ -77,6 +87,29 @@ class FileUploadStore extends NylasStore
|
||||||
message: 'Cannot Attach File',
|
message: 'Cannot Attach File',
|
||||||
detail: message
|
detail: message
|
||||||
|
|
||||||
|
# Helpers
|
||||||
|
|
||||||
|
_getTempIdDirsFor: (path) ->
|
||||||
|
fs.readdirSync(path).filter((dir) -> Utils.isTempId(dir))
|
||||||
|
|
||||||
|
_getFileUploadsFromFs: (rootDir = UPLOAD_DIR)->
|
||||||
|
# TODO This function makes my eyes hurt. Refactor
|
||||||
|
uploads = {}
|
||||||
|
dirs = @_getTempIdDirsFor(rootDir)
|
||||||
|
for messageClientId in dirs
|
||||||
|
uploads[messageClientId] = []
|
||||||
|
messageDir = path.join(rootDir, messageClientId)
|
||||||
|
uploadIds = @_getTempIdDirsFor(messageDir)
|
||||||
|
for uploadId in uploadIds
|
||||||
|
uploadDir = path.join(messageDir, uploadId)
|
||||||
|
for filename in fs.readdirSync(uploadDir)
|
||||||
|
uploadPath = path.join(uploadDir, filename)
|
||||||
|
stats = fs.statSync(uploadPath)
|
||||||
|
uploads[messageClientId].push(
|
||||||
|
new Upload(messageClientId, uploadPath, stats, uploadId)
|
||||||
|
)
|
||||||
|
return uploads
|
||||||
|
|
||||||
_verifyId: (messageClientId) ->
|
_verifyId: (messageClientId) ->
|
||||||
if messageClientId.blank?
|
if messageClientId.blank?
|
||||||
throw new Error "You need to pass the ID of the message (draft) this Action refers to"
|
throw new Error "You need to pass the ID of the message (draft) this Action refers to"
|
||||||
|
|
|
@ -169,7 +169,7 @@ class SendDraftTask extends Task
|
||||||
# Remove attachments we were waiting to upload
|
# Remove attachments we were waiting to upload
|
||||||
# Call the Action to do this
|
# Call the Action to do this
|
||||||
for upload in @uploads
|
for upload in @uploads
|
||||||
Actions.removeFileFromUpload(upload.messageClientId, upload.id)
|
Actions.removeAttachment(upload.messageClientId, upload.id)
|
||||||
|
|
||||||
return Promise.resolve(Task.Status.Success)
|
return Promise.resolve(Task.Status.Success)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue