@uppy/provider-views
Advanced tools
Comparing version 2.0.2 to 2.0.3
"use strict"; | ||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } | ||
const classNames = require('classnames'); | ||
const { | ||
@@ -11,9 +7,15 @@ h | ||
const classNames = require('classnames'); | ||
const remoteFileObjToLocal = require('@uppy/utils/lib/remoteFileObjToLocal'); | ||
const Filter = require('./Filter'); | ||
const ItemList = require('./ItemList'); | ||
const FooterActions = require('./FooterActions'); | ||
const Browser = props => { | ||
const Item = require('./Item/index'); | ||
const VIRTUAL_SHARED_DIR = 'shared-with-me'; | ||
function Browser(props) { | ||
const { | ||
@@ -24,43 +26,89 @@ currentSelection, | ||
uppyFiles, | ||
filterItems, | ||
filterInput | ||
viewType, | ||
headerComponent, | ||
showBreadcrumbs, | ||
isChecked, | ||
toggleCheckbox, | ||
handleScroll, | ||
showTitles, | ||
i18n, | ||
validateRestrictions, | ||
showFilter, | ||
filterQuery, | ||
filterInput, | ||
getNextFolder, | ||
cancel, | ||
done, | ||
columns | ||
} = props; | ||
let filteredFolders = folders; | ||
let filteredFiles = files; | ||
if (filterInput !== '') { | ||
filteredFolders = filterItems(folders); | ||
filteredFiles = filterItems(files); | ||
} | ||
const selected = currentSelection.length; | ||
return h("div", { | ||
className: classNames('uppy-ProviderBrowser', `uppy-ProviderBrowser-viewType--${props.viewType}`) | ||
className: classNames('uppy-ProviderBrowser', `uppy-ProviderBrowser-viewType--${viewType}`) | ||
}, h("div", { | ||
className: "uppy-ProviderBrowser-header" | ||
}, h("div", { | ||
className: classNames('uppy-ProviderBrowser-headerBar', !props.showBreadcrumbs && 'uppy-ProviderBrowser-headerBar--simple') | ||
}, props.headerComponent)), props.showFilter && h(Filter, props), h(ItemList, { | ||
columns: [{ | ||
name: 'Name', | ||
key: 'title' | ||
}], | ||
folders: filteredFolders, | ||
files: filteredFiles, | ||
isChecked: props.isChecked, | ||
handleFolderClick: props.getNextFolder, | ||
toggleCheckbox: props.toggleCheckbox, | ||
handleScroll: props.handleScroll, | ||
title: props.title, | ||
showTitles: props.showTitles, | ||
i18n: props.i18n, | ||
viewType: props.viewType, | ||
validateRestrictions: props.validateRestrictions, | ||
uppyFiles: uppyFiles, | ||
currentSelection: currentSelection | ||
}), selected > 0 && h(FooterActions, _extends({ | ||
selected: selected | ||
}, props))); | ||
}; | ||
className: classNames('uppy-ProviderBrowser-headerBar', !showBreadcrumbs && 'uppy-ProviderBrowser-headerBar--simple') | ||
}, headerComponent)), showFilter && h(Filter, { | ||
i18n: i18n, | ||
filterQuery: filterQuery, | ||
filterInput: filterInput | ||
}), (() => { | ||
if (!folders.length && !files.length) { | ||
return h("div", { | ||
className: "uppy-Provider-empty" | ||
}, props.i18n('noFilesFound')); | ||
} | ||
return h("div", { | ||
className: "uppy-ProviderBrowser-body" | ||
}, h("ul", { | ||
className: "uppy-ProviderBrowser-list", | ||
onScroll: handleScroll, | ||
role: "listbox" // making <ul> not focusable for firefox | ||
, | ||
tabIndex: "-1" | ||
}, folders.map(folder => { | ||
var _isChecked; | ||
return Item({ | ||
columns, | ||
showTitles, | ||
viewType, | ||
i18n, | ||
id: folder.id, | ||
title: folder.name, | ||
getItemIcon: () => folder.icon, | ||
isChecked: isChecked(folder), | ||
toggleCheckbox: event => toggleCheckbox(event, folder), | ||
type: 'folder', | ||
isDisabled: (_isChecked = isChecked(folder)) == null ? void 0 : _isChecked.loading, | ||
isCheckboxDisabled: folder.id === VIRTUAL_SHARED_DIR, | ||
handleFolderClick: () => getNextFolder(folder) | ||
}); | ||
}), files.map(file => { | ||
const validated = validateRestrictions(remoteFileObjToLocal(file), [...uppyFiles, ...currentSelection]); | ||
return Item({ | ||
id: file.id, | ||
title: file.name, | ||
author: file.author, | ||
getItemIcon: () => file.icon, | ||
isChecked: isChecked(file), | ||
toggleCheckbox: event => toggleCheckbox(event, file), | ||
columns, | ||
showTitles, | ||
viewType, | ||
i18n, | ||
type: 'file', | ||
isDisabled: !validated.result && isChecked(file), | ||
restrictionReason: validated.reason | ||
}); | ||
}))); | ||
})(), selected > 0 && h(FooterActions, { | ||
selected: selected, | ||
done: done, | ||
cancel: cancel, | ||
i18n: i18n | ||
})); | ||
} | ||
module.exports = Browser; |
@@ -17,3 +17,4 @@ "use strict"; | ||
toggleCheckbox, | ||
id | ||
id, | ||
children | ||
} = props; | ||
@@ -36,5 +37,7 @@ return h("li", { | ||
className: "uppy-u-reset uppy-ProviderBrowserItem-inner" | ||
}, itemIconEl, showTitles && title)); | ||
}, h("span", { | ||
className: "uppy-ProviderBrowserItem-inner-relative" | ||
}, itemIconEl, showTitles && title, children))); | ||
} | ||
module.exports = GridListItem; |
@@ -13,7 +13,10 @@ "use strict"; | ||
const GridLi = require('./components/GridLi'); | ||
const GridListItem = require('./components/GridLi'); | ||
const ListLi = require('./components/ListLi'); | ||
const ListItem = require('./components/ListLi'); | ||
module.exports = props => { | ||
const { | ||
author | ||
} = props; | ||
const itemIconString = props.getItemIcon(); | ||
@@ -33,3 +36,3 @@ const className = classNames('uppy-ProviderBrowserItem', { | ||
case 'grid': | ||
return h(GridLi, _extends({}, props, { | ||
return h(GridListItem, _extends({}, props, { | ||
className: className, | ||
@@ -40,3 +43,3 @@ itemIconEl: itemIconEl | ||
case 'list': | ||
return h(ListLi, _extends({}, props, { | ||
return h(ListItem, _extends({}, props, { | ||
className: className, | ||
@@ -46,2 +49,13 @@ itemIconEl: itemIconEl | ||
case 'unsplash': | ||
return h(GridListItem, _extends({}, props, { | ||
className: className, | ||
itemIconEl: itemIconEl | ||
}), h("a", { | ||
href: `${author.url}?utm_source=Companion&utm_medium=referral`, | ||
target: "_blank", | ||
rel: "noopener noreferrer", | ||
className: "uppy-ProviderBrowserItem-author" | ||
}, author.name)); | ||
default: | ||
@@ -48,0 +62,0 @@ throw new Error(`There is no such type ${props.viewType}`); |
"use strict"; | ||
var _class, _isHandlingScroll, _sharedHandler, _updateFilesAndFolders, _isOriginAllowed, _temp; | ||
var _class, _updateFilesAndFolders, _isOriginAllowed, _temp; | ||
@@ -15,8 +15,2 @@ function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } | ||
const generateFileID = require('@uppy/utils/lib/generateFileID'); | ||
const getFileType = require('@uppy/utils/lib/getFileType'); | ||
const isPreviewSupported = require('@uppy/utils/lib/isPreviewSupported'); | ||
const AuthView = require('./AuthView'); | ||
@@ -30,6 +24,6 @@ | ||
const SharedHandler = require('../SharedHandler'); | ||
const CloseWrapper = require('../CloseWrapper'); | ||
const View = require('../View'); | ||
function getOrigin() { | ||
@@ -44,3 +38,3 @@ // eslint-disable-next-line no-restricted-globals | ||
module.exports = (_temp = (_isHandlingScroll = /*#__PURE__*/_classPrivateFieldLooseKey("isHandlingScroll"), _sharedHandler = /*#__PURE__*/_classPrivateFieldLooseKey("sharedHandler"), _updateFilesAndFolders = /*#__PURE__*/_classPrivateFieldLooseKey("updateFilesAndFolders"), _isOriginAllowed = /*#__PURE__*/_classPrivateFieldLooseKey("isOriginAllowed"), _class = class ProviderView { | ||
module.exports = (_temp = (_updateFilesAndFolders = /*#__PURE__*/_classPrivateFieldLooseKey("updateFilesAndFolders"), _isOriginAllowed = /*#__PURE__*/_classPrivateFieldLooseKey("isOriginAllowed"), _class = class ProviderView extends View { | ||
/** | ||
@@ -51,2 +45,4 @@ * @param {object} plugin instance of the plugin | ||
constructor(plugin, opts) { | ||
super(plugin, opts); // set default options | ||
Object.defineProperty(this, _isOriginAllowed, { | ||
@@ -58,14 +54,2 @@ value: _isOriginAllowed2 | ||
}); | ||
Object.defineProperty(this, _isHandlingScroll, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, _sharedHandler, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this.plugin = plugin; | ||
this.provider = opts.provider; | ||
_classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler] = new SharedHandler(plugin); // set default options | ||
const defaultOptions = { | ||
@@ -82,3 +66,2 @@ viewType: 'list', | ||
this.addFile = this.addFile.bind(this); | ||
this.filterQuery = this.filterQuery.bind(this); | ||
@@ -88,13 +71,8 @@ this.getFolder = this.getFolder.bind(this); | ||
this.logout = this.logout.bind(this); | ||
this.preFirstRender = this.preFirstRender.bind(this); | ||
this.handleAuth = this.handleAuth.bind(this); | ||
this.handleError = this.handleError.bind(this); | ||
this.handleScroll = this.handleScroll.bind(this); | ||
this.listAllFiles = this.listAllFiles.bind(this); | ||
this.donePicking = this.donePicking.bind(this); | ||
this.cancelPicking = this.cancelPicking.bind(this); | ||
this.clearSelection = this.clearSelection.bind(this); // Visual | ||
this.donePicking = this.donePicking.bind(this); // Visual | ||
this.render = this.render.bind(this); | ||
this.clearSelection(); // Set default state for the plugin | ||
this.render = this.render.bind(this); // Set default state for the plugin | ||
@@ -107,3 +85,4 @@ this.plugin.setPluginState({ | ||
filterInput: '', | ||
isSearchVisible: false | ||
isSearchVisible: false, | ||
currentSelection: [] | ||
}); | ||
@@ -116,12 +95,2 @@ } | ||
/** | ||
* Called only the first time the provider view is rendered. | ||
* Kind of like an init function. | ||
*/ | ||
preFirstRender() { | ||
this.plugin.setPluginState({ | ||
didFirstRender: true | ||
}); | ||
this.plugin.onFirstRender(); | ||
} | ||
/** | ||
* Based on folder ID, fetch a new folder and update it to state | ||
@@ -132,6 +101,4 @@ * | ||
*/ | ||
getFolder(id, name) { | ||
return _classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler].loaderWrapper(this.provider.list(id), res => { | ||
return this.sharedHandler.loaderWrapper(this.provider.list(id), res => { | ||
const folders = []; | ||
@@ -172,42 +139,2 @@ const files = []; | ||
} | ||
addFile(file) { | ||
const tagFile = { | ||
id: this.providerFileToId(file), | ||
source: this.plugin.id, | ||
data: file, | ||
name: file.name || file.id, | ||
type: file.mimeType, | ||
isRemote: true, | ||
body: { | ||
fileId: file.id | ||
}, | ||
remote: { | ||
companionUrl: this.plugin.opts.companionUrl, | ||
url: `${this.provider.fileUrl(file.requestPath)}`, | ||
body: { | ||
fileId: file.id | ||
}, | ||
providerOptions: this.provider.opts | ||
} | ||
}; | ||
const fileType = getFileType(tagFile); // TODO Should we just always use the thumbnail URL if it exists? | ||
if (fileType && isPreviewSupported(fileType)) { | ||
tagFile.preview = file.thumbnail; | ||
} | ||
this.plugin.uppy.log('Adding remote file'); | ||
try { | ||
this.plugin.uppy.addFile(tagFile); | ||
return true; | ||
} catch (err) { | ||
if (!err.isRestriction) { | ||
this.plugin.uppy.log(err); | ||
} | ||
return false; | ||
} | ||
} | ||
/** | ||
@@ -327,10 +254,2 @@ * Removes session token on client side. | ||
providerFileToId(file) { | ||
return generateFileID({ | ||
data: file, | ||
name: file.name || file.id, | ||
type: file.mimeType | ||
}); | ||
} | ||
handleAuth() { | ||
@@ -357,2 +276,14 @@ const authState = btoa(JSON.stringify({ | ||
if (data.error) { | ||
this.plugin.uppy.log('auth aborted'); | ||
const { | ||
uppy | ||
} = this.plugin; | ||
const message = uppy.i18n('authAborted'); | ||
uppy.info({ | ||
message | ||
}, 'warning', 5000); | ||
return; | ||
} | ||
if (!data.token) { | ||
@@ -372,25 +303,10 @@ this.plugin.uppy.log('did not receive token from auth window'); | ||
handleError(error) { | ||
const { | ||
uppy | ||
} = this.plugin; | ||
uppy.log(error.toString()); | ||
async handleScroll(event) { | ||
const path = this.nextPagePath || null; | ||
if (error.isAuthError) { | ||
return; | ||
} | ||
if (this.shouldHandleScroll(event) && path) { | ||
this.isHandlingScroll = true; | ||
const message = uppy.i18n('companionError'); | ||
uppy.info({ | ||
message, | ||
details: error.toString() | ||
}, 'error', 5000); | ||
} | ||
handleScroll(e) { | ||
const scrollPos = e.target.scrollHeight - (e.target.scrollTop + e.target.offsetHeight); | ||
const path = this.nextPagePath || null; | ||
if (scrollPos < 50 && path && !_classPrivateFieldLooseBase(this, _isHandlingScroll)[_isHandlingScroll]) { | ||
this.provider.list(path).then(res => { | ||
try { | ||
const response = await this.provider.list(path); | ||
const { | ||
@@ -401,8 +317,8 @@ files, | ||
_classPrivateFieldLooseBase(this, _updateFilesAndFolders)[_updateFilesAndFolders](res, files, folders); | ||
}).catch(this.handleError).then(() => { | ||
_classPrivateFieldLooseBase(this, _isHandlingScroll)[_isHandlingScroll] = false; | ||
}); // always called | ||
_classPrivateFieldLooseBase(this, _isHandlingScroll)[_isHandlingScroll] = true; | ||
_classPrivateFieldLooseBase(this, _updateFilesAndFolders)[_updateFilesAndFolders](response, files, folders); | ||
} catch (error) { | ||
this.handleError(error); | ||
} finally { | ||
this.isHandlingScroll = false; | ||
} | ||
} | ||
@@ -444,4 +360,3 @@ } | ||
}); | ||
_classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler].loaderWrapper(Promise.all(promises), () => { | ||
this.sharedHandler.loaderWrapper(Promise.all(promises), () => { | ||
this.clearSelection(); | ||
@@ -451,14 +366,2 @@ }, () => {}); | ||
cancelPicking() { | ||
this.clearSelection(); | ||
const dashboard = this.plugin.uppy.getPlugin('Dashboard'); | ||
if (dashboard) dashboard.hideAllPanels(); | ||
} | ||
clearSelection() { | ||
this.plugin.setPluginState({ | ||
currentSelection: [] | ||
}); | ||
} | ||
render(state, viewOptions = {}) { | ||
@@ -472,29 +375,20 @@ const { | ||
this.preFirstRender(); | ||
} // reload pluginState for "loading" attribute because it might | ||
// have changed above. | ||
if (this.plugin.getPluginState().loading) { | ||
return h(CloseWrapper, { | ||
onUnmount: this.clearSelection | ||
}, h(LoaderView, { | ||
i18n: this.plugin.uppy.i18n | ||
})); | ||
} | ||
if (!authenticated) { | ||
return h(CloseWrapper, { | ||
onUnmount: this.clearSelection | ||
}, h(AuthView, { | ||
pluginName: this.plugin.title, | ||
pluginIcon: this.plugin.icon, | ||
handleAuth: this.handleAuth, | ||
i18n: this.plugin.uppy.i18n, | ||
i18nArray: this.plugin.uppy.i18nArray | ||
})); | ||
} | ||
const targetViewOptions = { ...this.opts, | ||
...viewOptions | ||
}; | ||
const { | ||
files, | ||
folders, | ||
filterInput, | ||
loading, | ||
currentSelection | ||
} = this.plugin.getPluginState(); | ||
const { | ||
isChecked, | ||
toggleCheckbox, | ||
filterItems | ||
} = this.sharedHandler; | ||
const hasInput = filterInput !== ''; | ||
const headerProps = { | ||
@@ -510,11 +404,14 @@ showBreadcrumbs: targetViewOptions.showBreadcrumbs, | ||
}; | ||
const browserProps = { ...this.plugin.getPluginState(), | ||
const browserProps = { | ||
isChecked, | ||
toggleCheckbox, | ||
currentSelection, | ||
files: hasInput ? filterItems(files) : files, | ||
folders: hasInput ? filterItems(folders) : folders, | ||
username: this.username, | ||
getNextFolder: this.getNextFolder, | ||
getFolder: this.getFolder, | ||
filterItems: _classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler].filterItems, | ||
filterItems: this.sharedHandler.filterItems, | ||
filterQuery: this.filterQuery, | ||
logout: this.logout, | ||
isChecked: _classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler].isChecked, | ||
toggleCheckbox: _classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler].toggleCheckbox, | ||
handleScroll: this.handleScroll, | ||
@@ -535,2 +432,23 @@ listAllFiles: this.listAllFiles, | ||
}; | ||
if (loading) { | ||
return h(CloseWrapper, { | ||
onUnmount: this.clearSelection | ||
}, h(LoaderView, { | ||
i18n: this.plugin.uppy.i18n | ||
})); | ||
} | ||
if (!authenticated) { | ||
return h(CloseWrapper, { | ||
onUnmount: this.clearSelection | ||
}, h(AuthView, { | ||
pluginName: this.plugin.title, | ||
pluginIcon: this.plugin.icon, | ||
handleAuth: this.handleAuth, | ||
i18n: this.plugin.uppy.i18n, | ||
i18nArray: this.plugin.uppy.i18nArray | ||
})); | ||
} | ||
return h(CloseWrapper, { | ||
@@ -541,3 +459,3 @@ onUnmount: this.clearSelection | ||
}), _class.VERSION = "2.0.2", _temp); | ||
}), _class.VERSION = "2.0.3", _temp); | ||
@@ -544,0 +462,0 @@ function _updateFilesAndFolders2(res, files, folders) { |
"use strict"; | ||
var _class, _isHandlingScroll, _searchTerm, _sharedHandler, _updateFilesAndInputMode, _temp; | ||
var _class, _searchTerm, _updateFilesAndInputMode, _temp; | ||
@@ -15,8 +15,2 @@ function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } | ||
const generateFileID = require('@uppy/utils/lib/generateFileID'); | ||
const getFileType = require('@uppy/utils/lib/getFileType'); | ||
const isPreviewSupported = require('@uppy/utils/lib/isPreviewSupported'); | ||
const SearchInput = require('./InputView'); | ||
@@ -30,5 +24,5 @@ | ||
const SharedHandler = require('../SharedHandler'); | ||
const CloseWrapper = require('../CloseWrapper'); | ||
const CloseWrapper = require('../CloseWrapper'); | ||
const View = require('../View'); | ||
/** | ||
@@ -39,3 +33,3 @@ * Class to easily generate generic views for Provider plugins | ||
module.exports = (_temp = (_isHandlingScroll = /*#__PURE__*/_classPrivateFieldLooseKey("isHandlingScroll"), _searchTerm = /*#__PURE__*/_classPrivateFieldLooseKey("searchTerm"), _sharedHandler = /*#__PURE__*/_classPrivateFieldLooseKey("sharedHandler"), _updateFilesAndInputMode = /*#__PURE__*/_classPrivateFieldLooseKey("updateFilesAndInputMode"), _class = class ProviderView { | ||
module.exports = (_temp = (_searchTerm = /*#__PURE__*/_classPrivateFieldLooseKey("searchTerm"), _updateFilesAndInputMode = /*#__PURE__*/_classPrivateFieldLooseKey("updateFilesAndInputMode"), _class = class SearchProviderView extends View { | ||
/** | ||
@@ -46,9 +40,7 @@ * @param {object} plugin instance of the plugin | ||
constructor(plugin, opts) { | ||
super(plugin, opts); // set default options | ||
Object.defineProperty(this, _updateFilesAndInputMode, { | ||
value: _updateFilesAndInputMode2 | ||
}); | ||
Object.defineProperty(this, _isHandlingScroll, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, _searchTerm, { | ||
@@ -58,10 +50,2 @@ writable: true, | ||
}); | ||
Object.defineProperty(this, _sharedHandler, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
this.plugin = plugin; | ||
this.provider = opts.provider; | ||
_classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler] = new SharedHandler(plugin); // set default options | ||
const defaultOptions = { | ||
@@ -81,11 +65,6 @@ viewType: 'grid', | ||
this.addFile = this.addFile.bind(this); | ||
this.preFirstRender = this.preFirstRender.bind(this); | ||
this.handleError = this.handleError.bind(this); | ||
this.handleScroll = this.handleScroll.bind(this); | ||
this.donePicking = this.donePicking.bind(this); | ||
this.cancelPicking = this.cancelPicking.bind(this); | ||
this.clearSelection = this.clearSelection.bind(this); // Visual | ||
this.donePicking = this.donePicking.bind(this); // Visual | ||
this.render = this.render.bind(this); | ||
this.clearSelection(); // Set default state for the plugin | ||
this.render = this.render.bind(this); // Set default state for the plugin | ||
@@ -98,3 +77,4 @@ this.plugin.setPluginState({ | ||
filterInput: '', | ||
isSearchVisible: false | ||
isSearchVisible: false, | ||
currentSelection: [] | ||
}); | ||
@@ -106,13 +86,2 @@ } | ||
/** | ||
* Called only the first time the provider view is rendered. | ||
* Kind of like an init function. | ||
*/ | ||
preFirstRender() { | ||
this.plugin.setPluginState({ | ||
didFirstRender: true | ||
}); | ||
this.plugin.onFirstRender(); | ||
} | ||
search(query) { | ||
@@ -127,3 +96,3 @@ if (query && query === _classPrivateFieldLooseBase(this, _searchTerm)[_searchTerm]) { | ||
return _classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler].loaderWrapper(this.provider.search(query), res => { | ||
return this.sharedHandler.loaderWrapper(this.provider.search(query), res => { | ||
_classPrivateFieldLooseBase(this, _updateFilesAndInputMode)[_updateFilesAndInputMode](res, []); | ||
@@ -137,71 +106,12 @@ }, this.handleError); | ||
}); | ||
} // @todo this function should really be a function of the plugin and not the view. | ||
// maybe we should consider creating a base ProviderPlugin class that has this method | ||
addFile(file) { | ||
const tagFile = { | ||
id: this.providerFileToId(file), | ||
source: this.plugin.id, | ||
data: file, | ||
name: file.name || file.id, | ||
type: file.mimeType, | ||
isRemote: true, | ||
body: { | ||
fileId: file.id | ||
}, | ||
remote: { | ||
companionUrl: this.plugin.opts.companionUrl, | ||
url: `${this.provider.fileUrl(file.requestPath)}`, | ||
body: { | ||
fileId: file.id | ||
}, | ||
providerOptions: { ...this.provider.opts, | ||
provider: null | ||
} | ||
} | ||
}; | ||
const fileType = getFileType(tagFile); // TODO Should we just always use the thumbnail URL if it exists? | ||
if (fileType && isPreviewSupported(fileType)) { | ||
tagFile.preview = file.thumbnail; | ||
} | ||
this.plugin.uppy.log('Adding remote file'); | ||
try { | ||
this.plugin.uppy.addFile(tagFile); | ||
} catch (err) { | ||
if (!err.isRestriction) { | ||
this.plugin.uppy.log(err); | ||
} | ||
} | ||
} | ||
providerFileToId(file) { | ||
return generateFileID({ | ||
data: file, | ||
name: file.name || file.id, | ||
type: file.mimeType | ||
}); | ||
} | ||
async handleScroll(event) { | ||
const query = this.nextPageQuery || null; | ||
handleError(error) { | ||
const { | ||
uppy | ||
} = this.plugin; | ||
uppy.log(error.toString()); | ||
const message = uppy.i18n('companionError'); | ||
uppy.info({ | ||
message, | ||
details: error.toString() | ||
}, 'error', 5000); | ||
} | ||
if (this.shouldHandleScroll(event) && query) { | ||
this.isHandlingScroll = true; | ||
handleScroll(e) { | ||
const scrollPos = e.target.scrollHeight - (e.target.scrollTop + e.target.offsetHeight); | ||
const query = this.nextPageQuery || null; | ||
if (scrollPos < 50 && query && !_classPrivateFieldLooseBase(this, _isHandlingScroll)[_isHandlingScroll]) { | ||
this.provider.search(_classPrivateFieldLooseBase(this, _searchTerm)[_searchTerm], query).then(res => { | ||
try { | ||
const response = await this.provider.search(_classPrivateFieldLooseBase(this, _searchTerm)[_searchTerm], query); | ||
const { | ||
@@ -211,8 +121,8 @@ files | ||
_classPrivateFieldLooseBase(this, _updateFilesAndInputMode)[_updateFilesAndInputMode](res, files); | ||
}).catch(this.handleError).then(() => { | ||
_classPrivateFieldLooseBase(this, _isHandlingScroll)[_isHandlingScroll] = false; | ||
}); // always called | ||
_classPrivateFieldLooseBase(this, _isHandlingScroll)[_isHandlingScroll] = true; | ||
_classPrivateFieldLooseBase(this, _updateFilesAndInputMode)[_updateFilesAndInputMode](response, files); | ||
} catch (error) { | ||
this.handleError(error); | ||
} finally { | ||
this.isHandlingScroll = false; | ||
} | ||
} | ||
@@ -226,4 +136,3 @@ } | ||
const promises = currentSelection.map(file => this.addFile(file)); | ||
_classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler].loaderWrapper(Promise.all(promises), () => { | ||
this.sharedHandler.loaderWrapper(Promise.all(promises), () => { | ||
this.clearSelection(); | ||
@@ -233,14 +142,2 @@ }, () => {}); | ||
cancelPicking() { | ||
this.clearSelection(); | ||
const dashboard = this.plugin.uppy.getPlugin('Dashboard'); | ||
if (dashboard) dashboard.hideAllPanels(); | ||
} | ||
clearSelection() { | ||
this.plugin.setPluginState({ | ||
currentSelection: [] | ||
}); | ||
} | ||
render(state, viewOptions = {}) { | ||
@@ -254,29 +151,26 @@ const { | ||
this.preFirstRender(); | ||
} // reload pluginState for "loading" attribute because it might | ||
// have changed above. | ||
if (this.plugin.getPluginState().loading) { | ||
return h(CloseWrapper, { | ||
onUnmount: this.clearSelection | ||
}, h(LoaderView, { | ||
i18n: this.plugin.uppy.i18n | ||
})); | ||
} | ||
if (isInputMode) { | ||
return h(CloseWrapper, { | ||
onUnmount: this.clearSelection | ||
}, h(SearchInput, { | ||
search: this.search, | ||
i18n: this.plugin.uppy.i18n | ||
})); | ||
} | ||
const targetViewOptions = { ...this.opts, | ||
...viewOptions | ||
}; | ||
const browserProps = { ...this.plugin.getPluginState(), | ||
isChecked: _classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler].isChecked, | ||
toggleCheckbox: _classPrivateFieldLooseBase(this, _sharedHandler)[_sharedHandler].toggleCheckbox, | ||
const { | ||
files, | ||
folders, | ||
filterInput, | ||
loading, | ||
currentSelection | ||
} = this.plugin.getPluginState(); | ||
const { | ||
isChecked, | ||
toggleCheckbox, | ||
filterItems | ||
} = this.sharedHandler; | ||
const hasInput = filterInput !== ''; | ||
const browserProps = { | ||
isChecked, | ||
toggleCheckbox, | ||
currentSelection, | ||
files: hasInput ? filterItems(files) : files, | ||
folders: hasInput ? filterItems(folders) : folders, | ||
handleScroll: this.handleScroll, | ||
@@ -299,2 +193,20 @@ done: this.donePicking, | ||
}; | ||
if (loading) { | ||
return h(CloseWrapper, { | ||
onUnmount: this.clearSelection | ||
}, h(LoaderView, { | ||
i18n: this.plugin.uppy.i18n | ||
})); | ||
} | ||
if (isInputMode) { | ||
return h(CloseWrapper, { | ||
onUnmount: this.clearSelection | ||
}, h(SearchInput, { | ||
search: this.search, | ||
i18n: this.plugin.uppy.i18n | ||
})); | ||
} | ||
return h(CloseWrapper, { | ||
@@ -305,3 +217,3 @@ onUnmount: this.clearSelection | ||
}), _class.VERSION = "2.0.2", _temp); | ||
}), _class.VERSION = "2.0.3", _temp); | ||
@@ -308,0 +220,0 @@ function _updateFilesAndInputMode2(res, files) { |
{ | ||
"name": "@uppy/provider-views", | ||
"description": "View library for Uppy remote provider plugins.", | ||
"version": "2.0.2", | ||
"version": "2.0.3", | ||
"license": "MIT", | ||
@@ -22,3 +22,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@uppy/utils": "^4.0.1", | ||
"@uppy/utils": "^4.0.2", | ||
"classnames": "^2.2.6", | ||
@@ -30,3 +30,3 @@ "preact": "^10.5.13" | ||
}, | ||
"gitHead": "b3b68c07773395d1521c38148cbf87ed88ff2364" | ||
"gitHead": "1eb317ba3a3115596212ac50f1d81d3188dd0619" | ||
} |
@@ -0,8 +1,13 @@ | ||
const { h } = require('preact') | ||
const classNames = require('classnames') | ||
const { h } = require('preact') | ||
const remoteFileObjToLocal = require('@uppy/utils/lib/remoteFileObjToLocal') | ||
const Filter = require('./Filter') | ||
const ItemList = require('./ItemList') | ||
const FooterActions = require('./FooterActions') | ||
const Item = require('./Item/index') | ||
const Browser = (props) => { | ||
const VIRTUAL_SHARED_DIR = 'shared-with-me' | ||
function Browser (props) { | ||
const { | ||
@@ -13,44 +18,119 @@ currentSelection, | ||
uppyFiles, | ||
filterItems, | ||
viewType, | ||
headerComponent, | ||
showBreadcrumbs, | ||
isChecked, | ||
toggleCheckbox, | ||
handleScroll, | ||
showTitles, | ||
i18n, | ||
validateRestrictions, | ||
showFilter, | ||
filterQuery, | ||
filterInput, | ||
getNextFolder, | ||
cancel, | ||
done, | ||
columns, | ||
} = props | ||
let filteredFolders = folders | ||
let filteredFiles = files | ||
if (filterInput !== '') { | ||
filteredFolders = filterItems(folders) | ||
filteredFiles = filterItems(files) | ||
} | ||
const selected = currentSelection.length | ||
return ( | ||
<div className={classNames('uppy-ProviderBrowser', `uppy-ProviderBrowser-viewType--${props.viewType}`)}> | ||
<div | ||
className={classNames( | ||
'uppy-ProviderBrowser', | ||
`uppy-ProviderBrowser-viewType--${viewType}` | ||
)} | ||
> | ||
<div className="uppy-ProviderBrowser-header"> | ||
<div className={classNames('uppy-ProviderBrowser-headerBar', !props.showBreadcrumbs && 'uppy-ProviderBrowser-headerBar--simple')}> | ||
{props.headerComponent} | ||
<div | ||
className={classNames( | ||
'uppy-ProviderBrowser-headerBar', | ||
!showBreadcrumbs && 'uppy-ProviderBrowser-headerBar--simple' | ||
)} | ||
> | ||
{headerComponent} | ||
</div> | ||
</div> | ||
{props.showFilter && <Filter {...props} />} | ||
<ItemList | ||
columns={[{ | ||
name: 'Name', | ||
key: 'title', | ||
}]} | ||
folders={filteredFolders} | ||
files={filteredFiles} | ||
isChecked={props.isChecked} | ||
handleFolderClick={props.getNextFolder} | ||
toggleCheckbox={props.toggleCheckbox} | ||
handleScroll={props.handleScroll} | ||
title={props.title} | ||
showTitles={props.showTitles} | ||
i18n={props.i18n} | ||
viewType={props.viewType} | ||
validateRestrictions={props.validateRestrictions} | ||
uppyFiles={uppyFiles} | ||
currentSelection={currentSelection} | ||
/> | ||
{selected > 0 && <FooterActions selected={selected} {...props} />} | ||
{showFilter && ( | ||
<Filter | ||
i18n={i18n} | ||
filterQuery={filterQuery} | ||
filterInput={filterInput} | ||
/> | ||
)} | ||
{(() => { | ||
if (!folders.length && !files.length) { | ||
return ( | ||
<div className="uppy-Provider-empty"> | ||
{props.i18n('noFilesFound')} | ||
</div> | ||
) | ||
} | ||
return ( | ||
<div className="uppy-ProviderBrowser-body"> | ||
<ul | ||
className="uppy-ProviderBrowser-list" | ||
onScroll={handleScroll} | ||
role="listbox" | ||
// making <ul> not focusable for firefox | ||
tabIndex="-1" | ||
> | ||
{folders.map((folder) => { | ||
return Item({ | ||
columns, | ||
showTitles, | ||
viewType, | ||
i18n, | ||
id: folder.id, | ||
title: folder.name, | ||
getItemIcon: () => folder.icon, | ||
isChecked: isChecked(folder), | ||
toggleCheckbox: (event) => toggleCheckbox(event, folder), | ||
type: 'folder', | ||
isDisabled: isChecked(folder)?.loading, | ||
isCheckboxDisabled: folder.id === VIRTUAL_SHARED_DIR, | ||
handleFolderClick: () => getNextFolder(folder), | ||
}) | ||
})} | ||
{files.map((file) => { | ||
const validated = validateRestrictions( | ||
remoteFileObjToLocal(file), | ||
[...uppyFiles, ...currentSelection] | ||
) | ||
return Item({ | ||
id: file.id, | ||
title: file.name, | ||
author: file.author, | ||
getItemIcon: () => file.icon, | ||
isChecked: isChecked(file), | ||
toggleCheckbox: (event) => toggleCheckbox(event, file), | ||
columns, | ||
showTitles, | ||
viewType, | ||
i18n, | ||
type: 'file', | ||
isDisabled: !validated.result && isChecked(file), | ||
restrictionReason: validated.reason, | ||
}) | ||
})} | ||
</ul> | ||
</div> | ||
) | ||
})()} | ||
{selected > 0 && ( | ||
<FooterActions | ||
selected={selected} | ||
done={done} | ||
cancel={cancel} | ||
i18n={i18n} | ||
/> | ||
)} | ||
</div> | ||
@@ -57,0 +137,0 @@ ) |
@@ -14,2 +14,3 @@ const { h } = require('preact') | ||
id, | ||
children, | ||
} = props | ||
@@ -39,4 +40,9 @@ | ||
> | ||
{itemIconEl} | ||
{showTitles && title} | ||
<span className="uppy-ProviderBrowserItem-inner-relative"> | ||
{itemIconEl} | ||
{showTitles && title} | ||
{children} | ||
</span> | ||
</label> | ||
@@ -43,0 +49,0 @@ </li> |
const { h } = require('preact') | ||
const classNames = require('classnames') | ||
const ItemIcon = require('./components/ItemIcon') | ||
const GridLi = require('./components/GridLi') | ||
const ListLi = require('./components/ListLi') | ||
const GridListItem = require('./components/GridLi') | ||
const ListItem = require('./components/ListLi') | ||
module.exports = (props) => { | ||
const { author } = props | ||
const itemIconString = props.getItemIcon() | ||
@@ -21,5 +22,26 @@ | ||
case 'grid': | ||
return <GridLi {...props} className={className} itemIconEl={itemIconEl} /> | ||
return ( | ||
<GridListItem | ||
{...props} | ||
className={className} | ||
itemIconEl={itemIconEl} | ||
/> | ||
) | ||
case 'list': | ||
return <ListLi {...props} className={className} itemIconEl={itemIconEl} /> | ||
return ( | ||
<ListItem {...props} className={className} itemIconEl={itemIconEl} /> | ||
) | ||
case 'unsplash': | ||
return ( | ||
<GridListItem {...props} className={className} itemIconEl={itemIconEl}> | ||
<a | ||
href={`${author.url}?utm_source=Companion&utm_medium=referral`} | ||
target="_blank" | ||
rel="noopener noreferrer" | ||
className="uppy-ProviderBrowserItem-author" | ||
> | ||
{author.name} | ||
</a> | ||
</GridListItem> | ||
) | ||
default: | ||
@@ -26,0 +48,0 @@ throw new Error(`There is no such type ${props.viewType}`) |
const { h } = require('preact') | ||
const generateFileID = require('@uppy/utils/lib/generateFileID') | ||
const getFileType = require('@uppy/utils/lib/getFileType') | ||
const isPreviewSupported = require('@uppy/utils/lib/isPreviewSupported') | ||
const AuthView = require('./AuthView') | ||
@@ -9,4 +6,4 @@ const Header = require('./Header') | ||
const LoaderView = require('../Loader') | ||
const SharedHandler = require('../SharedHandler') | ||
const CloseWrapper = require('../CloseWrapper') | ||
const View = require('../View') | ||
@@ -21,9 +18,5 @@ function getOrigin () { | ||
*/ | ||
module.exports = class ProviderView { | ||
module.exports = class ProviderView extends View { | ||
static VERSION = require('../../package.json').version | ||
#isHandlingScroll | ||
#sharedHandler | ||
/** | ||
@@ -34,6 +27,3 @@ * @param {object} plugin instance of the plugin | ||
constructor (plugin, opts) { | ||
this.plugin = plugin | ||
this.provider = opts.provider | ||
this.#sharedHandler = new SharedHandler(plugin) | ||
super(plugin, opts) | ||
// set default options | ||
@@ -51,3 +41,2 @@ const defaultOptions = { | ||
// Logic | ||
this.addFile = this.addFile.bind(this) | ||
this.filterQuery = this.filterQuery.bind(this) | ||
@@ -57,10 +46,6 @@ this.getFolder = this.getFolder.bind(this) | ||
this.logout = this.logout.bind(this) | ||
this.preFirstRender = this.preFirstRender.bind(this) | ||
this.handleAuth = this.handleAuth.bind(this) | ||
this.handleError = this.handleError.bind(this) | ||
this.handleScroll = this.handleScroll.bind(this) | ||
this.listAllFiles = this.listAllFiles.bind(this) | ||
this.donePicking = this.donePicking.bind(this) | ||
this.cancelPicking = this.cancelPicking.bind(this) | ||
this.clearSelection = this.clearSelection.bind(this) | ||
@@ -70,4 +55,2 @@ // Visual | ||
this.clearSelection() | ||
// Set default state for the plugin | ||
@@ -81,2 +64,3 @@ this.plugin.setPluginState({ | ||
isSearchVisible: false, | ||
currentSelection: [], | ||
}) | ||
@@ -103,11 +87,2 @@ } | ||
/** | ||
* Called only the first time the provider view is rendered. | ||
* Kind of like an init function. | ||
*/ | ||
preFirstRender () { | ||
this.plugin.setPluginState({ didFirstRender: true }) | ||
this.plugin.onFirstRender() | ||
} | ||
/** | ||
* Based on folder ID, fetch a new folder and update it to state | ||
@@ -119,3 +94,3 @@ * | ||
getFolder (id, name) { | ||
return this.#sharedHandler.loaderWrapper( | ||
return this.sharedHandler.loaderWrapper( | ||
this.provider.list(id), | ||
@@ -154,40 +129,2 @@ (res) => { | ||
addFile (file) { | ||
const tagFile = { | ||
id: this.providerFileToId(file), | ||
source: this.plugin.id, | ||
data: file, | ||
name: file.name || file.id, | ||
type: file.mimeType, | ||
isRemote: true, | ||
body: { | ||
fileId: file.id, | ||
}, | ||
remote: { | ||
companionUrl: this.plugin.opts.companionUrl, | ||
url: `${this.provider.fileUrl(file.requestPath)}`, | ||
body: { | ||
fileId: file.id, | ||
}, | ||
providerOptions: this.provider.opts, | ||
}, | ||
} | ||
const fileType = getFileType(tagFile) | ||
// TODO Should we just always use the thumbnail URL if it exists? | ||
if (fileType && isPreviewSupported(fileType)) { | ||
tagFile.preview = file.thumbnail | ||
} | ||
this.plugin.uppy.log('Adding remote file') | ||
try { | ||
this.plugin.uppy.addFile(tagFile) | ||
return true | ||
} catch (err) { | ||
if (!err.isRestriction) { | ||
this.plugin.uppy.log(err) | ||
} | ||
return false | ||
} | ||
} | ||
/** | ||
@@ -294,10 +231,2 @@ * Removes session token on client side. | ||
providerFileToId (file) { | ||
return generateFileID({ | ||
data: file, | ||
name: file.name || file.id, | ||
type: file.mimeType, | ||
}) | ||
} | ||
handleAuth () { | ||
@@ -319,2 +248,10 @@ const authState = btoa(JSON.stringify({ origin: getOrigin() })) | ||
if (data.error) { | ||
this.plugin.uppy.log('auth aborted') | ||
const { uppy } = this.plugin | ||
const message = uppy.i18n('authAborted') | ||
uppy.info({ message }, 'warning', 5000) | ||
return | ||
} | ||
if (!data.token) { | ||
@@ -348,25 +285,18 @@ this.plugin.uppy.log('did not receive token from auth window') | ||
handleError (error) { | ||
const { uppy } = this.plugin | ||
uppy.log(error.toString()) | ||
if (error.isAuthError) { | ||
return | ||
} | ||
const message = uppy.i18n('companionError') | ||
uppy.info({ message, details: error.toString() }, 'error', 5000) | ||
} | ||
handleScroll (e) { | ||
const scrollPos = e.target.scrollHeight - (e.target.scrollTop + e.target.offsetHeight) | ||
async handleScroll (event) { | ||
const path = this.nextPagePath || null | ||
if (scrollPos < 50 && path && !this.#isHandlingScroll) { | ||
this.provider.list(path) | ||
.then((res) => { | ||
const { files, folders } = this.plugin.getPluginState() | ||
this.#updateFilesAndFolders(res, files, folders) | ||
}).catch(this.handleError) | ||
.then(() => { this.#isHandlingScroll = false }) // always called | ||
if (this.shouldHandleScroll(event) && path) { | ||
this.isHandlingScroll = true | ||
this.#isHandlingScroll = true | ||
try { | ||
const response = await this.provider.list(path) | ||
const { files, folders } = this.plugin.getPluginState() | ||
this.#updateFilesAndFolders(response, files, folders) | ||
} catch (error) { | ||
this.handleError(error) | ||
} finally { | ||
this.isHandlingScroll = false | ||
} | ||
} | ||
@@ -406,3 +336,3 @@ } | ||
this.#sharedHandler.loaderWrapper(Promise.all(promises), () => { | ||
this.sharedHandler.loaderWrapper(Promise.all(promises), () => { | ||
this.clearSelection() | ||
@@ -412,15 +342,5 @@ }, () => {}) | ||
cancelPicking () { | ||
this.clearSelection() | ||
const dashboard = this.plugin.uppy.getPlugin('Dashboard') | ||
if (dashboard) dashboard.hideAllPanels() | ||
} | ||
clearSelection () { | ||
this.plugin.setPluginState({ currentSelection: [] }) | ||
} | ||
render (state, viewOptions = {}) { | ||
const { authenticated, didFirstRender } = this.plugin.getPluginState() | ||
if (!didFirstRender) { | ||
@@ -430,27 +350,6 @@ this.preFirstRender() | ||
// reload pluginState for "loading" attribute because it might | ||
// have changed above. | ||
if (this.plugin.getPluginState().loading) { | ||
return ( | ||
<CloseWrapper onUnmount={this.clearSelection}> | ||
<LoaderView i18n={this.plugin.uppy.i18n} /> | ||
</CloseWrapper> | ||
) | ||
} | ||
if (!authenticated) { | ||
return ( | ||
<CloseWrapper onUnmount={this.clearSelection}> | ||
<AuthView | ||
pluginName={this.plugin.title} | ||
pluginIcon={this.plugin.icon} | ||
handleAuth={this.handleAuth} | ||
i18n={this.plugin.uppy.i18n} | ||
i18nArray={this.plugin.uppy.i18nArray} | ||
/> | ||
</CloseWrapper> | ||
) | ||
} | ||
const targetViewOptions = { ...this.opts, ...viewOptions } | ||
const { files, folders, filterInput, loading, currentSelection } = this.plugin.getPluginState() | ||
const { isChecked, toggleCheckbox, filterItems } = this.sharedHandler | ||
const hasInput = filterInput !== '' | ||
const headerProps = { | ||
@@ -468,11 +367,13 @@ showBreadcrumbs: targetViewOptions.showBreadcrumbs, | ||
const browserProps = { | ||
...this.plugin.getPluginState(), | ||
isChecked, | ||
toggleCheckbox, | ||
currentSelection, | ||
files: hasInput ? filterItems(files) : files, | ||
folders: hasInput ? filterItems(folders) : folders, | ||
username: this.username, | ||
getNextFolder: this.getNextFolder, | ||
getFolder: this.getFolder, | ||
filterItems: this.#sharedHandler.filterItems, | ||
filterItems: this.sharedHandler.filterItems, | ||
filterQuery: this.filterQuery, | ||
logout: this.logout, | ||
isChecked: this.#sharedHandler.isChecked, | ||
toggleCheckbox: this.#sharedHandler.toggleCheckbox, | ||
handleScroll: this.handleScroll, | ||
@@ -494,2 +395,24 @@ listAllFiles: this.listAllFiles, | ||
if (loading) { | ||
return ( | ||
<CloseWrapper onUnmount={this.clearSelection}> | ||
<LoaderView i18n={this.plugin.uppy.i18n} /> | ||
</CloseWrapper> | ||
) | ||
} | ||
if (!authenticated) { | ||
return ( | ||
<CloseWrapper onUnmount={this.clearSelection}> | ||
<AuthView | ||
pluginName={this.plugin.title} | ||
pluginIcon={this.plugin.icon} | ||
handleAuth={this.handleAuth} | ||
i18n={this.plugin.uppy.i18n} | ||
i18nArray={this.plugin.uppy.i18nArray} | ||
/> | ||
</CloseWrapper> | ||
) | ||
} | ||
return ( | ||
@@ -496,0 +419,0 @@ <CloseWrapper onUnmount={this.clearSelection}> |
const { h } = require('preact') | ||
const generateFileID = require('@uppy/utils/lib/generateFileID') | ||
const getFileType = require('@uppy/utils/lib/getFileType') | ||
const isPreviewSupported = require('@uppy/utils/lib/isPreviewSupported') | ||
const SearchInput = require('./InputView') | ||
@@ -9,4 +6,4 @@ const Browser = require('../Browser') | ||
const Header = require('./Header') | ||
const SharedHandler = require('../SharedHandler') | ||
const CloseWrapper = require('../CloseWrapper') | ||
const View = require('../View') | ||
@@ -16,11 +13,7 @@ /** | ||
*/ | ||
module.exports = class ProviderView { | ||
module.exports = class SearchProviderView extends View { | ||
static VERSION = require('../../package.json').version | ||
#isHandlingScroll | ||
#searchTerm | ||
#sharedHandler | ||
/** | ||
@@ -31,5 +24,3 @@ * @param {object} plugin instance of the plugin | ||
constructor (plugin, opts) { | ||
this.plugin = plugin | ||
this.provider = opts.provider | ||
this.#sharedHandler = new SharedHandler(plugin) | ||
super(plugin, opts) | ||
@@ -51,8 +42,4 @@ // set default options | ||
this.addFile = this.addFile.bind(this) | ||
this.preFirstRender = this.preFirstRender.bind(this) | ||
this.handleError = this.handleError.bind(this) | ||
this.handleScroll = this.handleScroll.bind(this) | ||
this.donePicking = this.donePicking.bind(this) | ||
this.cancelPicking = this.cancelPicking.bind(this) | ||
this.clearSelection = this.clearSelection.bind(this) | ||
@@ -62,4 +49,2 @@ // Visual | ||
this.clearSelection() | ||
// Set default state for the plugin | ||
@@ -73,2 +58,3 @@ this.plugin.setPluginState({ | ||
isSearchVisible: false, | ||
currentSelection: [], | ||
}) | ||
@@ -88,11 +74,2 @@ } | ||
/** | ||
* Called only the first time the provider view is rendered. | ||
* Kind of like an init function. | ||
*/ | ||
preFirstRender () { | ||
this.plugin.setPluginState({ didFirstRender: true }) | ||
this.plugin.onFirstRender() | ||
} | ||
search (query) { | ||
@@ -105,3 +82,3 @@ if (query && query === this.#searchTerm) { | ||
return this.#sharedHandler.loaderWrapper( | ||
return this.sharedHandler.loaderWrapper( | ||
this.provider.search(query), | ||
@@ -119,68 +96,18 @@ (res) => { | ||
// @todo this function should really be a function of the plugin and not the view. | ||
// maybe we should consider creating a base ProviderPlugin class that has this method | ||
addFile (file) { | ||
const tagFile = { | ||
id: this.providerFileToId(file), | ||
source: this.plugin.id, | ||
data: file, | ||
name: file.name || file.id, | ||
type: file.mimeType, | ||
isRemote: true, | ||
body: { | ||
fileId: file.id, | ||
}, | ||
remote: { | ||
companionUrl: this.plugin.opts.companionUrl, | ||
url: `${this.provider.fileUrl(file.requestPath)}`, | ||
body: { | ||
fileId: file.id, | ||
}, | ||
providerOptions: { ...this.provider.opts, provider: null }, | ||
}, | ||
} | ||
async handleScroll (event) { | ||
const query = this.nextPageQuery || null | ||
const fileType = getFileType(tagFile) | ||
// TODO Should we just always use the thumbnail URL if it exists? | ||
if (fileType && isPreviewSupported(fileType)) { | ||
tagFile.preview = file.thumbnail | ||
} | ||
this.plugin.uppy.log('Adding remote file') | ||
try { | ||
this.plugin.uppy.addFile(tagFile) | ||
} catch (err) { | ||
if (!err.isRestriction) { | ||
this.plugin.uppy.log(err) | ||
} | ||
} | ||
} | ||
if (this.shouldHandleScroll(event) && query) { | ||
this.isHandlingScroll = true | ||
providerFileToId (file) { | ||
return generateFileID({ | ||
data: file, | ||
name: file.name || file.id, | ||
type: file.mimeType, | ||
}) | ||
} | ||
try { | ||
const response = await this.provider.search(this.#searchTerm, query) | ||
const { files } = this.plugin.getPluginState() | ||
handleError (error) { | ||
const { uppy } = this.plugin | ||
uppy.log(error.toString()) | ||
const message = uppy.i18n('companionError') | ||
uppy.info({ message, details: error.toString() }, 'error', 5000) | ||
} | ||
handleScroll (e) { | ||
const scrollPos = e.target.scrollHeight - (e.target.scrollTop + e.target.offsetHeight) | ||
const query = this.nextPageQuery || null | ||
if (scrollPos < 50 && query && !this.#isHandlingScroll) { | ||
this.provider.search(this.#searchTerm, query) | ||
.then((res) => { | ||
const { files } = this.plugin.getPluginState() | ||
this.#updateFilesAndInputMode(res, files) | ||
}).catch(this.handleError) | ||
.then(() => { this.#isHandlingScroll = false }) // always called | ||
this.#isHandlingScroll = true | ||
this.#updateFilesAndInputMode(response, files) | ||
} catch (error) { | ||
this.handleError(error) | ||
} finally { | ||
this.isHandlingScroll = false | ||
} | ||
} | ||
@@ -193,3 +120,3 @@ } | ||
this.#sharedHandler.loaderWrapper(Promise.all(promises), () => { | ||
this.sharedHandler.loaderWrapper(Promise.all(promises), () => { | ||
this.clearSelection() | ||
@@ -199,15 +126,5 @@ }, () => {}) | ||
cancelPicking () { | ||
this.clearSelection() | ||
const dashboard = this.plugin.uppy.getPlugin('Dashboard') | ||
if (dashboard) dashboard.hideAllPanels() | ||
} | ||
clearSelection () { | ||
this.plugin.setPluginState({ currentSelection: [] }) | ||
} | ||
render (state, viewOptions = {}) { | ||
const { didFirstRender, isInputMode } = this.plugin.getPluginState() | ||
if (!didFirstRender) { | ||
@@ -217,28 +134,13 @@ this.preFirstRender() | ||
// reload pluginState for "loading" attribute because it might | ||
// have changed above. | ||
if (this.plugin.getPluginState().loading) { | ||
return ( | ||
<CloseWrapper onUnmount={this.clearSelection}> | ||
<LoaderView i18n={this.plugin.uppy.i18n} /> | ||
</CloseWrapper> | ||
) | ||
} | ||
const targetViewOptions = { ...this.opts, ...viewOptions } | ||
const { files, folders, filterInput, loading, currentSelection } = this.plugin.getPluginState() | ||
const { isChecked, toggleCheckbox, filterItems } = this.sharedHandler | ||
const hasInput = filterInput !== '' | ||
if (isInputMode) { | ||
return ( | ||
<CloseWrapper onUnmount={this.clearSelection}> | ||
<SearchInput | ||
search={this.search} | ||
i18n={this.plugin.uppy.i18n} | ||
/> | ||
</CloseWrapper> | ||
) | ||
} | ||
const targetViewOptions = { ...this.opts, ...viewOptions } | ||
const browserProps = { | ||
...this.plugin.getPluginState(), | ||
isChecked: this.#sharedHandler.isChecked, | ||
toggleCheckbox: this.#sharedHandler.toggleCheckbox, | ||
isChecked, | ||
toggleCheckbox, | ||
currentSelection, | ||
files: hasInput ? filterItems(files) : files, | ||
folders: hasInput ? filterItems(folders) : folders, | ||
handleScroll: this.handleScroll, | ||
@@ -262,2 +164,21 @@ done: this.donePicking, | ||
if (loading) { | ||
return ( | ||
<CloseWrapper onUnmount={this.clearSelection}> | ||
<LoaderView i18n={this.plugin.uppy.i18n} /> | ||
</CloseWrapper> | ||
) | ||
} | ||
if (isInputMode) { | ||
return ( | ||
<CloseWrapper onUnmount={this.clearSelection}> | ||
<SearchInput | ||
search={this.search} | ||
i18n={this.plugin.uppy.i18n} | ||
/> | ||
</CloseWrapper> | ||
) | ||
} | ||
return ( | ||
@@ -264,0 +185,0 @@ <CloseWrapper onUnmount={this.clearSelection}> |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
235076
3395
1
Updated@uppy/utils@^4.0.2