瀏覽代碼

Adds the ability to upload whole folders to dashboard (#2334)

bdirito 4 年之前
父節點
當前提交
4ad07f5f1b

+ 27 - 9
packages/@uppy/dashboard/src/components/AddFiles.js

@@ -5,6 +5,10 @@ class AddFiles extends Component {
     this.fileInput.click()
     this.fileInput.click()
   }
   }
 
 
+  triggerFolderInputClick = () => {
+    this.folderInput.click()
+  }
+
   onFileInputChange = (event) => {
   onFileInputChange = (event) => {
     this.props.handleInputChange(event)
     this.props.handleInputChange(event)
 
 
@@ -46,19 +50,20 @@ class AddFiles extends Component {
     )
     )
   }
   }
 
 
-  renderHiddenFileInput = () => {
+  renderHiddenInput = (isFolder, refCallback) => {
     return (
     return (
       <input
       <input
         class="uppy-Dashboard-input"
         class="uppy-Dashboard-input"
         hidden
         hidden
         aria-hidden="true"
         aria-hidden="true"
         tabindex={-1}
         tabindex={-1}
+        webkitdirectory={isFolder}
         type="file"
         type="file"
         name="files[]"
         name="files[]"
         multiple={this.props.maxNumberOfFiles !== 1}
         multiple={this.props.maxNumberOfFiles !== 1}
         onchange={this.onFileInputChange}
         onchange={this.onFileInputChange}
         accept={this.props.allowedFileTypes}
         accept={this.props.allowedFileTypes}
-        ref={(ref) => { this.fileInput = ref }}
+        ref={refCallback}
       />
       />
     )
     )
   }
   }
@@ -90,24 +95,36 @@ class AddFiles extends Component {
     )
     )
   }
   }
 
 
-  renderDropPasteBrowseTagline = () => {
+  renderBrowseButton = (text, onClickFn) => {
     const numberOfAcquirers = this.props.acquirers.length
     const numberOfAcquirers = this.props.acquirers.length
-    const browse =
+    return (
       <button
       <button
         type="button"
         type="button"
         class="uppy-u-reset uppy-Dashboard-browse"
         class="uppy-u-reset uppy-Dashboard-browse"
-        onclick={this.triggerFileInputClick}
+        onclick={onClickFn}
         data-uppy-super-focusable={numberOfAcquirers === 0}
         data-uppy-super-focusable={numberOfAcquirers === 0}
       >
       >
-        {this.props.i18n('browse')}
+        {text}
       </button>
       </button>
+    )
+  }
+
+  renderDropPasteBrowseTagline = () => {
+    const numberOfAcquirers = this.props.acquirers.length
+    const browseFiles = this.renderBrowseButton(this.props.i18n('browseFiles'), this.triggerFileInputClick)
+    const browseFolders = this.renderBrowseButton(this.props.i18n('browseFolders'), this.triggerFolderInputClick)
+
+    // in order to keep the i18n CamelCase and options lower (as are defaults) we will want to transform a lower
+    // to Camel
+    const lowerFMSelectionType = this.props.fileManagerSelectionType
+    const camelFMSelectionType = lowerFMSelectionType.charAt(0).toUpperCase() + lowerFMSelectionType.slice(1)
 
 
     return (
     return (
       <div class="uppy-Dashboard-AddFiles-title">
       <div class="uppy-Dashboard-AddFiles-title">
         {
         {
           numberOfAcquirers > 0
           numberOfAcquirers > 0
-            ? this.props.i18nArray('dropPasteImport', { browse })
-            : this.props.i18nArray('dropPaste', { browse })
+            ? this.props.i18nArray(`dropPasteImport${camelFMSelectionType}`, { browseFiles, browseFolders, browse: browseFiles })
+            : this.props.i18nArray(`dropPaste${camelFMSelectionType}`, { browseFiles, browseFolders, browse: browseFiles })
         }
         }
       </div>
       </div>
     )
     )
@@ -157,7 +174,8 @@ class AddFiles extends Component {
   render () {
   render () {
     return (
     return (
       <div class="uppy-Dashboard-AddFiles">
       <div class="uppy-Dashboard-AddFiles">
-        {this.renderHiddenFileInput()}
+        {this.renderHiddenInput(false, (ref) => { this.fileInput = ref })}
+        {this.renderHiddenInput(true, (ref) => { this.folderInput = ref })}
         {this.renderDropPasteBrowseTagline()}
         {this.renderDropPasteBrowseTagline()}
         {this.props.acquirers.length > 0 && this.renderAcquirers(this.props.acquirers)}
         {this.props.acquirers.length > 0 && this.renderAcquirers(this.props.acquirers)}
         <div class="uppy-Dashboard-AddFiles-info">
         <div class="uppy-Dashboard-AddFiles-info">

+ 15 - 3
packages/@uppy/dashboard/src/index.js

@@ -68,10 +68,15 @@ module.exports = class Dashboard extends Plugin {
         saveChanges: 'Save changes',
         saveChanges: 'Save changes',
         cancel: 'Cancel',
         cancel: 'Cancel',
         myDevice: 'My Device',
         myDevice: 'My Device',
-        dropPaste: 'Drop files here, paste or %{browse}',
-        dropPasteImport: 'Drop files here, paste, %{browse} or import from:',
+        dropPasteFiles: 'Drop files here, paste or %{browseFiles}',
+        dropPasteFolders: 'Drop files here, paste or %{browseFolders}',
+        dropPasteBoth: 'Drop files here, paste, %{browseFiles} or %{browseFolders}',
+        dropPasteImportFiles: 'Drop files here, paste, %{browseFiles} or import from:',
+        dropPasteImportFolders: 'Drop files here, paste, %{browseFolders} or import from:',
+        dropPasteImportBoth: 'Drop files here, paste, %{browseFiles}, %{browseFolders} or import from:',
         dropHint: 'Drop your files here',
         dropHint: 'Drop your files here',
-        browse: 'browse',
+        browseFiles: 'browse files',
+        browseFolders: 'browse folders',
         uploadComplete: 'Upload complete',
         uploadComplete: 'Upload complete',
         uploadPaused: 'Upload paused',
         uploadPaused: 'Upload paused',
         resumeUpload: 'Resume upload',
         resumeUpload: 'Resume upload',
@@ -126,6 +131,7 @@ module.exports = class Dashboard extends Plugin {
       disableThumbnailGenerator: false,
       disableThumbnailGenerator: false,
       disablePageScrollWhenModalOpen: true,
       disablePageScrollWhenModalOpen: true,
       animateOpenClose: true,
       animateOpenClose: true,
+      fileManagerSelectionType: 'files',
       proudlyDisplayPoweredByUppy: true,
       proudlyDisplayPoweredByUppy: true,
       onRequestCloseModal: () => this.closeModal(),
       onRequestCloseModal: () => this.closeModal(),
       showSelectedFiles: true,
       showSelectedFiles: true,
@@ -839,6 +845,11 @@ module.exports = class Dashboard extends Plugin {
       theme = this.opts.theme
       theme = this.opts.theme
     }
     }
 
 
+    if (['files', 'folders', 'both'].indexOf(this.opts.fileManagerSelectionType) < 0) {
+      this.opts.fileManagerSelectionType = 'files'
+      console.error(`Unsupported option for "fileManagerSelectionType". Using default of "${this.opts.fileManagerSelectionType}".`)
+    }
+
     return DashboardUI({
     return DashboardUI({
       state,
       state,
       isHidden: pluginState.isHidden,
       isHidden: pluginState.isHidden,
@@ -900,6 +911,7 @@ module.exports = class Dashboard extends Plugin {
       width: this.opts.width,
       width: this.opts.width,
       height: this.opts.height,
       height: this.opts.height,
       showLinkToFileUploadResult: this.opts.showLinkToFileUploadResult,
       showLinkToFileUploadResult: this.opts.showLinkToFileUploadResult,
+      fileManagerSelectionType: this.opts.fileManagerSelectionType,
       proudlyDisplayPoweredByUppy: this.opts.proudlyDisplayPoweredByUppy,
       proudlyDisplayPoweredByUppy: this.opts.proudlyDisplayPoweredByUppy,
       hideCancelButton: this.opts.hideCancelButton,
       hideCancelButton: this.opts.hideCancelButton,
       hideRetryButton: this.opts.hideRetryButton,
       hideRetryButton: this.opts.hideRetryButton,

+ 1 - 0
packages/@uppy/dashboard/types/index.d.ts

@@ -38,6 +38,7 @@ declare module Dashboard {
     note?: string | null
     note?: string | null
     onRequestCloseModal?: () => void
     onRequestCloseModal?: () => void
     plugins?: string[]
     plugins?: string[]
+    fileManagerSelectionType?: 'files' | 'folders' | 'both';
     proudlyDisplayPoweredByUppy?: boolean
     proudlyDisplayPoweredByUppy?: boolean
     showLinkToFileUploadResult?: boolean
     showLinkToFileUploadResult?: boolean
     showProgressDetails?: boolean
     showProgressDetails?: boolean

+ 8 - 2
packages/@uppy/locales/src/en_US.js

@@ -17,6 +17,8 @@ en_US.strings = {
   authenticateWithTitle: 'Please authenticate with %{pluginName} to select files',
   authenticateWithTitle: 'Please authenticate with %{pluginName} to select files',
   back: 'Back',
   back: 'Back',
   browse: 'browse',
   browse: 'browse',
+  browseFiles: 'browse files',
+  browseFolders: 'browse folders',
   cancel: 'Cancel',
   cancel: 'Cancel',
   cancelUpload: 'Cancel upload',
   cancelUpload: 'Cancel upload',
   chooseFiles: 'Choose files',
   chooseFiles: 'Choose files',
@@ -36,8 +38,12 @@ en_US.strings = {
   done: 'Done',
   done: 'Done',
   dropHereOr: 'Drop files here or %{browse}',
   dropHereOr: 'Drop files here or %{browse}',
   dropHint: 'Drop your files here',
   dropHint: 'Drop your files here',
-  dropPaste: 'Drop files here, paste or %{browse}',
-  dropPasteImport: 'Drop files here, paste, %{browse} or import from:',
+  dropPasteBoth: 'Drop files here, paste, %{browseFiles} or %{browseFolders}',
+  dropPasteFiles: 'Drop files here, paste or %{browseFiles}',
+  dropPasteFolders: 'Drop files here, paste or %{browseFolders}',
+  dropPasteImportBoth: 'Drop files here, paste, %{browseFiles}, %{browseFolders} or import from:',
+  dropPasteImportFiles: 'Drop files here, paste, %{browseFiles} or import from:',
+  dropPasteImportFolders: 'Drop files here, paste, %{browseFolders} or import from:',
   editFile: 'Edit file',
   editFile: 'Edit file',
   editing: 'Editing %{file}',
   editing: 'Editing %{file}',
   emptyFolderAdded: 'No files were added from empty folder',
   emptyFolderAdded: 'No files were added from empty folder',

+ 5 - 0
website/src/docs/dashboard.md

@@ -88,6 +88,7 @@ uppy.use(Dashboard, {
   disableThumbnailGenerator: false,
   disableThumbnailGenerator: false,
   disablePageScrollWhenModalOpen: true,
   disablePageScrollWhenModalOpen: true,
   animateOpenClose: true,
   animateOpenClose: true,
+  fileManagerSelectionType: 'files',
   proudlyDisplayPoweredByUppy: true,
   proudlyDisplayPoweredByUppy: true,
   onRequestCloseModal: () => this.closeModal(),
   onRequestCloseModal: () => this.closeModal(),
   showSelectedFiles: true,
   showSelectedFiles: true,
@@ -257,6 +258,10 @@ Page scrolling is disabled by default when the Dashboard modal is open, so when
 
 
 Add light animations when the modal dialog is opened or closed, for a more satisfying user experience.
 Add light animations when the modal dialog is opened or closed, for a more satisfying user experience.
 
 
+### `fileManagerSelectionType: 'files'`
+
+Configure the type of selections allowed when browsing your file system via the file manager selection window. May be either 'files', 'folders', or 'both'. Selecting entire folders for upload may not be supported on all [browsers](https://caniuse.com/#feat=input-file-directory).
+
 ### `proudlyDisplayPoweredByUppy: true`
 ### `proudlyDisplayPoweredByUppy: true`
 
 
 Uppy is provided to the world for free by the team behind [Transloadit](https://transloadit.com). In return, we ask that you consider keeping a tiny Uppy logo at the bottom of the Dashboard, so that more people can discover and use Uppy.
 Uppy is provided to the world for free by the team behind [Transloadit](https://transloadit.com). In return, we ask that you consider keeping a tiny Uppy logo at the bottom of the Dashboard, so that more people can discover and use Uppy.