@uppy/provider-views
Advanced tools
Comparing version 3.3.0 to 3.3.1
# @uppy/provider-views | ||
## 3.3.1 | ||
Released: 2023-06-19 | ||
Included in: Uppy v3.10.0 | ||
- @uppy/provider-views: Fix range selection not resetting and computing correctly (Terence C / #4415) | ||
## 3.3.0 | ||
@@ -4,0 +11,0 @@ |
import { h, Fragment } from 'preact'; | ||
const Breadcrumb = props => { | ||
@@ -15,3 +14,2 @@ const { | ||
}; | ||
export default (props => { | ||
@@ -18,0 +16,0 @@ const { |
@@ -8,3 +8,2 @@ import { h } from 'preact'; | ||
const VIRTUAL_SHARED_DIR = 'shared-with-me'; | ||
function Browser(props) { | ||
@@ -63,3 +62,2 @@ const { | ||
} | ||
if (!folders.length && !files.length) { | ||
@@ -70,3 +68,2 @@ return h("div", { | ||
} | ||
return h("div", { | ||
@@ -77,3 +74,4 @@ className: "uppy-ProviderBrowser-body" | ||
onScroll: handleScroll, | ||
role: "listbox" // making <ul> not focusable for firefox | ||
role: "listbox" | ||
// making <ul> not focusable for firefox | ||
, | ||
@@ -83,3 +81,2 @@ tabIndex: "-1" | ||
var _isChecked; | ||
return Item({ | ||
@@ -127,3 +124,2 @@ columns, | ||
} | ||
export default Browser; |
@@ -9,3 +9,2 @@ import { Component, toChildArray } from 'preact'; | ||
} | ||
render() { | ||
@@ -17,3 +16,2 @@ const { | ||
} | ||
} |
import { h } from 'preact'; | ||
import classNames from 'classnames'; | ||
function GridListItem(props) { | ||
@@ -29,2 +28,3 @@ const { | ||
onKeyDown: recordShiftKeyPress, | ||
onMouseDown: recordShiftKeyPress, | ||
name: "listitem", | ||
@@ -41,3 +41,2 @@ id: id, | ||
} | ||
export default GridListItem; |
import { h } from 'preact'; | ||
function FileIcon() { | ||
@@ -15,3 +14,2 @@ return h("svg", { | ||
} | ||
function FolderIcon() { | ||
@@ -31,3 +29,2 @@ return h("svg", { | ||
} | ||
function VideoIcon() { | ||
@@ -48,3 +45,2 @@ return h("svg", { | ||
} | ||
export default (props => { | ||
@@ -55,13 +51,9 @@ const { | ||
if (itemIconString === null) return undefined; | ||
switch (itemIconString) { | ||
case 'file': | ||
return h(FileIcon, null); | ||
case 'folder': | ||
return h(FolderIcon, null); | ||
case 'video': | ||
return h(VideoIcon, null); | ||
default: | ||
@@ -68,0 +60,0 @@ { |
@@ -1,2 +0,4 @@ | ||
import { h } from 'preact'; // if folder: | ||
import { h } from 'preact'; | ||
// if folder: | ||
// + checkbox (selects all files from folder) | ||
@@ -32,3 +34,5 @@ // + folder name (opens folder) | ||
onChange: toggleCheckbox, | ||
onKeyDown: recordShiftKeyPress // for the <label/> | ||
onKeyDown: recordShiftKeyPress, | ||
onMouseDown: recordShiftKeyPress | ||
// for the <label/> | ||
, | ||
@@ -43,3 +47,4 @@ name: "listitem", | ||
"data-uppy-super-focusable": true | ||
}) : null, type === 'file' ? // label for a checkbox | ||
}) : null, type === 'file' ? | ||
// label for a checkbox | ||
h("label", { | ||
@@ -50,3 +55,4 @@ htmlFor: id, | ||
className: "uppy-ProviderBrowserItem-iconWrap" | ||
}, itemIconEl), showTitles && title) : // button to open a folder | ||
}, itemIconEl), showTitles && title) : | ||
// button to open a folder | ||
h("button", { | ||
@@ -63,3 +69,2 @@ type: "button", | ||
} | ||
export default ListItem; |
function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); } | ||
import { h } from 'preact'; | ||
@@ -27,6 +26,6 @@ import classNames from 'classnames'; | ||
}); | ||
switch (viewType) { | ||
case 'grid': | ||
return h(GridListItem // eslint-disable-next-line react/jsx-props-no-spreading | ||
return h(GridListItem | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
, _extends({}, props, { | ||
@@ -36,5 +35,5 @@ className: className, | ||
})); | ||
case 'list': | ||
return (// eslint-disable-next-line react/jsx-props-no-spreading | ||
return ( | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
h(ListItem, _extends({}, props, { | ||
@@ -45,5 +44,5 @@ className: className, | ||
); | ||
case 'unsplash': | ||
return (// eslint-disable-next-line react/jsx-props-no-spreading | ||
return ( | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
h(GridListItem, _extends({}, props, { | ||
@@ -60,3 +59,2 @@ className: className, | ||
); | ||
default: | ||
@@ -63,0 +61,0 @@ throw new Error(`There is no such type ${viewType}`); |
@@ -9,3 +9,4 @@ import { h } from 'preact'; | ||
className: "uppy-Provider-loading" | ||
}, h("span", null, i18n('loading')), typeof loading === 'string' && // todo improve this, see discussion in https://github.com/transloadit/uppy/pull/4399#discussion_r1162564445 | ||
}, h("span", null, i18n('loading')), typeof loading === 'string' && | ||
// todo improve this, see discussion in https://github.com/transloadit/uppy/pull/4399#discussion_r1162564445 | ||
h("span", { | ||
@@ -12,0 +13,0 @@ style: { |
import { h } from 'preact'; | ||
function GoogleIcon() { | ||
@@ -37,3 +36,2 @@ return h("svg", { | ||
} | ||
function AuthView(props) { | ||
@@ -45,5 +43,5 @@ const { | ||
handleAuth | ||
} = props; // In order to comply with Google's brand we need to create a different button | ||
} = props; | ||
// In order to comply with Google's brand we need to create a different button | ||
// for the Google Drive plugin | ||
const isGoogleDrive = pluginName === 'Google Drive'; | ||
@@ -75,3 +73,2 @@ const pluginNameComponent = h("span", { | ||
} | ||
export default AuthView; |
@@ -5,3 +5,2 @@ import User from "./User.js"; | ||
const components = []; | ||
if (props.showBreadcrumbs) { | ||
@@ -15,3 +14,2 @@ components.push(Breadcrumbs({ | ||
} | ||
components.push(User({ | ||
@@ -18,0 +16,0 @@ logout: props.logout, |
function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } | ||
var id = 0; | ||
function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; } | ||
import { h } from 'preact'; // eslint-disable-next-line import/no-unresolved | ||
import { h } from 'preact'; | ||
// eslint-disable-next-line import/no-unresolved | ||
import PQueue from 'p-queue'; | ||
@@ -18,5 +15,4 @@ import { getSafeFileId } from '@uppy/utils/lib/generateFileID'; | ||
const packageJson = { | ||
"version": "3.3.0" | ||
"version": "3.3.1" | ||
}; | ||
function getOrigin() { | ||
@@ -26,3 +22,2 @@ // eslint-disable-next-line no-restricted-globals | ||
} | ||
function getRegex(value) { | ||
@@ -32,10 +27,7 @@ if (typeof value === 'string') { | ||
} | ||
if (value instanceof RegExp) { | ||
return value; | ||
} | ||
return undefined; | ||
} | ||
function isOriginAllowed(origin, allowedOrigin) { | ||
@@ -45,9 +37,7 @@ const patterns = Array.isArray(allowedOrigin) ? allowedOrigin.map(getRegex) : [getRegex(allowedOrigin)]; | ||
} | ||
/** | ||
* Class to easily generate generic views for Provider plugins | ||
*/ | ||
var _updateFilesAndFolders = /*#__PURE__*/_classPrivateFieldLooseKey("updateFilesAndFolders"); | ||
export default class ProviderView extends View { | ||
@@ -59,4 +49,4 @@ /** | ||
constructor(plugin, opts) { | ||
super(plugin, opts); // set default options | ||
super(plugin, opts); | ||
// set default options | ||
Object.defineProperty(this, _updateFilesAndFolders, { | ||
@@ -70,8 +60,11 @@ value: _updateFilesAndFolders2 | ||
showBreadcrumbs: true | ||
}; // merge default options with the ones set by user | ||
}; | ||
this.opts = { ...defaultOptions, | ||
// merge default options with the ones set by user | ||
this.opts = { | ||
...defaultOptions, | ||
...opts | ||
}; // Logic | ||
}; | ||
// Logic | ||
this.filterQuery = this.filterQuery.bind(this); | ||
@@ -84,6 +77,8 @@ this.clearFilter = this.clearFilter.bind(this); | ||
this.handleScroll = this.handleScroll.bind(this); | ||
this.donePicking = this.donePicking.bind(this); // Visual | ||
this.donePicking = this.donePicking.bind(this); | ||
this.render = this.render.bind(this); // Set default state for the plugin | ||
// Visual | ||
this.render = this.render.bind(this); | ||
// Set default state for the plugin | ||
this.plugin.setPluginState({ | ||
@@ -98,8 +93,8 @@ authenticated: false, | ||
}); | ||
} // eslint-disable-next-line class-methods-use-this | ||
} | ||
tearDown() {// Nothing. | ||
// eslint-disable-next-line class-methods-use-this | ||
tearDown() { | ||
// Nothing. | ||
} | ||
/** | ||
@@ -113,3 +108,2 @@ * Based on folder ID, fetch a new folder and update it to state | ||
this.setLoading(true); | ||
try { | ||
@@ -122,3 +116,2 @@ const res = await this.provider.list(id); | ||
const index = state.directories.findIndex(dir => id === dir.id); | ||
if (index !== -1) { | ||
@@ -132,7 +125,4 @@ updatedDirectories = state.directories.slice(0, index + 1); | ||
} | ||
this.username = res.username || this.username; | ||
_classPrivateFieldLooseBase(this, _updateFilesAndFolders)[_updateFilesAndFolders](res, files, folders); | ||
this.plugin.setPluginState({ | ||
@@ -142,2 +132,3 @@ directories: updatedDirectories, | ||
}); | ||
this.lastCheckbox = undefined; | ||
} catch (err) { | ||
@@ -149,2 +140,3 @@ this.handleError(err); | ||
} | ||
/** | ||
@@ -155,4 +147,2 @@ * Fetches new folder | ||
*/ | ||
getNextFolder(folder) { | ||
@@ -162,7 +152,6 @@ this.getFolder(folder.requestPath, folder.name); | ||
} | ||
/** | ||
* Removes session token on client side. | ||
*/ | ||
logout() { | ||
@@ -178,3 +167,2 @@ this.provider.logout().then(res => { | ||
} | ||
const newState = { | ||
@@ -191,3 +179,2 @@ authenticated: false, | ||
} | ||
filterQuery(input) { | ||
@@ -198,3 +185,2 @@ this.plugin.setPluginState({ | ||
} | ||
clearFilter() { | ||
@@ -205,3 +191,2 @@ this.plugin.setPluginState({ | ||
} | ||
async handleAuth() { | ||
@@ -218,3 +203,2 @@ await this.provider.ensurePreAuth(); | ||
const authWindow = window.open(link, '_blank'); | ||
const handleToken = e => { | ||
@@ -225,11 +209,9 @@ if (e.source !== authWindow) { | ||
} | ||
if (!isOriginAllowed(e.origin, this.plugin.opts.companionAllowedHosts) || e.source !== authWindow) { | ||
this.plugin.uppy.log(`rejecting event from ${e.origin} vs allowed pattern ${this.plugin.opts.companionAllowedHosts}`); | ||
} // Check if it's a string before doing the JSON.parse to maintain support | ||
} | ||
// Check if it's a string before doing the JSON.parse to maintain support | ||
// for older Companion versions that used object references | ||
const data = typeof e.data === 'string' ? JSON.parse(e.data) : e.data; | ||
if (data.error) { | ||
@@ -246,3 +228,2 @@ this.plugin.uppy.log('auth aborted', 'warning'); | ||
} | ||
if (!data.token) { | ||
@@ -252,3 +233,2 @@ this.plugin.uppy.log('did not receive token from auth window', 'error'); | ||
} | ||
authWindow.close(); | ||
@@ -259,12 +239,8 @@ window.removeEventListener('message', handleToken); | ||
}; | ||
window.addEventListener('message', handleToken); | ||
} | ||
async handleScroll(event) { | ||
const path = this.nextPagePath || null; | ||
if (this.shouldHandleScroll(event) && path) { | ||
this.isHandlingScroll = true; | ||
try { | ||
@@ -276,3 +252,2 @@ const response = await this.provider.list(path); | ||
} = this.plugin.getPluginState(); | ||
_classPrivateFieldLooseBase(this, _updateFilesAndFolders)[_updateFilesAndFolders](response, files, folders); | ||
@@ -286,6 +261,4 @@ } catch (error) { | ||
} | ||
async recursivelyListAllFiles(path, queue, onFiles) { | ||
let curPath = path; | ||
while (curPath) { | ||
@@ -296,4 +269,5 @@ const res = await this.provider.list(curPath); | ||
const folders = res.items.filter(item => item.isFolder); | ||
onFiles(files); // recursively queue call to self for each folder | ||
onFiles(files); | ||
// recursively queue call to self for each folder | ||
const promises = folders.map(async folder => queue.add(async () => this.recursivelyListAllFiles(folder.requestPath, queue, onFiles))); | ||
@@ -306,3 +280,2 @@ await Promise.all(promises); // in case we get an error | ||
this.setLoading(true); | ||
try { | ||
@@ -314,3 +287,2 @@ const { | ||
const newFiles = []; | ||
for (const file of currentSelection) { | ||
@@ -327,11 +299,10 @@ if (file.isFolder) { | ||
}); | ||
const onFiles = files => { | ||
for (const newFile of files) { | ||
const tagFile = this.getTagFile(newFile); | ||
const id = getSafeFileId(tagFile); // If the same folder is added again, we don't want to send | ||
const id = getSafeFileId(tagFile); | ||
// If the same folder is added again, we don't want to send | ||
// X amount of duplicate file notifications, we want to say | ||
// the folder was already added. This checks if all files are duplicate, | ||
// if that's the case, we don't add the files. | ||
if (!this.plugin.uppy.checkIfFileAlreadyExists(id)) { | ||
@@ -344,11 +315,8 @@ newFiles.push(newFile); | ||
} | ||
isEmpty = false; | ||
} | ||
}; | ||
await this.recursivelyListAllFiles(requestPath, queue, onFiles); | ||
await queue.onIdle(); | ||
let message; | ||
if (isEmpty) { | ||
@@ -369,3 +337,2 @@ message = this.plugin.uppy.i18n('emptyFolderAdded'); | ||
} | ||
messages.push(message); | ||
@@ -375,3 +342,5 @@ } else { | ||
} | ||
} // Note: this.plugin.uppy.addFiles must be only run once we are done fetching all files, | ||
} | ||
// Note: this.plugin.uppy.addFiles must be only run once we are done fetching all files, | ||
// because it will cause the loading screen to disappear, | ||
@@ -381,4 +350,2 @@ // and that will allow the user to start the upload, so we need to make sure we have | ||
// see https://github.com/transloadit/uppy/pull/4384 | ||
this.plugin.uppy.log('Adding remote provider files'); | ||
@@ -397,10 +364,7 @@ this.plugin.uppy.addFiles(newFiles.map(file => this.getTagFile(file))); | ||
} | ||
render(state, viewOptions) { | ||
var _this = this; | ||
if (viewOptions === void 0) { | ||
viewOptions = {}; | ||
} | ||
const { | ||
@@ -413,8 +377,7 @@ authenticated, | ||
} = this.plugin.uppy; | ||
if (!didFirstRender) { | ||
this.preFirstRender(); | ||
} | ||
const targetViewOptions = { ...this.opts, | ||
const targetViewOptions = { | ||
...this.opts, | ||
...viewOptions | ||
@@ -481,3 +444,2 @@ }; | ||
}; | ||
if (loading) { | ||
@@ -491,3 +453,2 @@ return h(CloseWrapper, { | ||
} | ||
if (!authenticated) { | ||
@@ -504,3 +465,2 @@ return h(CloseWrapper, { | ||
} | ||
return h(CloseWrapper, { | ||
@@ -510,5 +470,3 @@ onUnmount: this.clearSelection | ||
} | ||
} | ||
function _updateFilesAndFolders2(res, files, folders) { | ||
@@ -528,3 +486,2 @@ this.nextPagePath = res.nextPagePath; | ||
} | ||
ProviderView.VERSION = packageJson.version; |
import { h, Fragment } from 'preact'; | ||
import { useEffect, useState, useCallback } from 'preact/hooks'; | ||
import { nanoid } from 'nanoid/non-secure'; // import debounce from 'lodash.debounce' | ||
import { nanoid } from 'nanoid/non-secure'; | ||
// import debounce from 'lodash.debounce' | ||
@@ -18,3 +19,4 @@ export default function SearchFilterInput(props) { | ||
} = props; | ||
const [searchText, setSearchText] = useState(searchTerm != null ? searchTerm : ''); // const debouncedSearch = debounce((q) => search(q), 1000) | ||
const [searchText, setSearchText] = useState(searchTerm != null ? searchTerm : ''); | ||
// const debouncedSearch = debounce((q) => search(q), 1000) | ||
@@ -30,3 +32,2 @@ const validateAndSearch = useCallback(ev => { | ||
}, [setSearchText, searchOnInput, search]); | ||
const handleReset = () => { | ||
@@ -36,3 +37,2 @@ setSearchText(''); | ||
}; | ||
const [form] = useState(() => { | ||
@@ -39,0 +39,0 @@ const formEl = document.createElement('form'); |
function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } | ||
var id = 0; | ||
function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; } | ||
import { h } from 'preact'; | ||
@@ -13,3 +10,3 @@ import SearchFilterInput from "../SearchFilterInput.js"; | ||
const packageJson = { | ||
"version": "3.3.0" | ||
"version": "3.3.1" | ||
}; | ||
@@ -20,5 +17,3 @@ /** | ||
*/ | ||
var _updateFilesAndInputMode = /*#__PURE__*/_classPrivateFieldLooseKey("updateFilesAndInputMode"); | ||
export default class SearchProviderView extends View { | ||
@@ -30,4 +25,5 @@ /** | ||
constructor(plugin, opts) { | ||
super(plugin, opts); // set default options | ||
super(plugin, opts); | ||
// set default options | ||
Object.defineProperty(this, _updateFilesAndInputMode, { | ||
@@ -41,8 +37,11 @@ value: _updateFilesAndInputMode2 | ||
showBreadcrumbs: false | ||
}; // merge default options with the ones set by user | ||
}; | ||
this.opts = { ...defaultOptions, | ||
// merge default options with the ones set by user | ||
this.opts = { | ||
...defaultOptions, | ||
...opts | ||
}; // Logic | ||
}; | ||
// Logic | ||
this.search = this.search.bind(this); | ||
@@ -52,4 +51,5 @@ this.clearSearch = this.clearSearch.bind(this); | ||
this.handleScroll = this.handleScroll.bind(this); | ||
this.donePicking = this.donePicking.bind(this); // Visual | ||
this.donePicking = this.donePicking.bind(this); | ||
// Visual | ||
this.render = this.render.bind(this); | ||
@@ -64,15 +64,15 @@ this.defaultState = { | ||
searchTerm: null | ||
}; // Set default state for the plugin | ||
}; | ||
// Set default state for the plugin | ||
this.plugin.setPluginState(this.defaultState); | ||
} // eslint-disable-next-line class-methods-use-this | ||
} | ||
tearDown() {// Nothing. | ||
// eslint-disable-next-line class-methods-use-this | ||
tearDown() { | ||
// Nothing. | ||
} | ||
resetPluginState() { | ||
this.plugin.setPluginState(this.defaultState); | ||
} | ||
async search(query) { | ||
@@ -82,3 +82,2 @@ const { | ||
} = this.plugin.getPluginState(); | ||
if (query && query === searchTerm) { | ||
@@ -88,8 +87,5 @@ // no need to search again as this is the same as the previous search | ||
} | ||
this.setLoading(true); | ||
try { | ||
const res = await this.provider.search(query); | ||
_classPrivateFieldLooseBase(this, _updateFilesAndInputMode)[_updateFilesAndInputMode](res, []); | ||
@@ -102,3 +98,2 @@ } catch (err) { | ||
} | ||
clearSearch() { | ||
@@ -111,9 +106,6 @@ this.plugin.setPluginState({ | ||
} | ||
async handleScroll(event) { | ||
const query = this.nextPageQuery || null; | ||
if (this.shouldHandleScroll(event) && query) { | ||
this.isHandlingScroll = true; | ||
try { | ||
@@ -125,3 +117,2 @@ const { | ||
const response = await this.provider.search(searchTerm, query); | ||
_classPrivateFieldLooseBase(this, _updateFilesAndInputMode)[_updateFilesAndInputMode](response, files); | ||
@@ -135,3 +126,2 @@ } catch (error) { | ||
} | ||
donePicking() { | ||
@@ -145,10 +135,7 @@ const { | ||
} | ||
render(state, viewOptions) { | ||
var _this = this; | ||
if (viewOptions === void 0) { | ||
viewOptions = {}; | ||
} | ||
const { | ||
@@ -162,8 +149,7 @@ didFirstRender, | ||
} = this.plugin.uppy; | ||
if (!didFirstRender) { | ||
this.preFirstRender(); | ||
} | ||
const targetViewOptions = { ...this.opts, | ||
const targetViewOptions = { | ||
...this.opts, | ||
...viewOptions | ||
@@ -181,3 +167,4 @@ }; | ||
toggleCheckbox, | ||
filterItems | ||
filterItems, | ||
recordShiftKeyPress | ||
} = this; | ||
@@ -188,2 +175,3 @@ const hasInput = filterInput !== ''; | ||
toggleCheckbox, | ||
recordShiftKeyPress, | ||
currentSelection, | ||
@@ -217,3 +205,2 @@ files: hasInput ? filterItems(files) : files, | ||
}; | ||
if (isInputMode) { | ||
@@ -234,3 +221,2 @@ return h(CloseWrapper, { | ||
} | ||
return h(CloseWrapper, { | ||
@@ -240,5 +226,3 @@ onUnmount: this.resetPluginState | ||
} | ||
} | ||
function _updateFilesAndInputMode2(res, files) { | ||
@@ -256,3 +240,2 @@ this.nextPageQuery = res.nextPageQuery; | ||
} | ||
SearchProviderView.VERSION = packageJson.version; |
@@ -8,7 +8,5 @@ import getFileType from '@uppy/utils/lib/getFileType'; | ||
const state = this.plugin.getPluginState(); | ||
if (!state.filterInput || state.filterInput === '') { | ||
return items; | ||
} | ||
return items.filter(folder => { | ||
@@ -18,7 +16,12 @@ return folder.name.toLowerCase().indexOf(state.filterInput.toLowerCase()) !== -1; | ||
}; | ||
this.recordShiftKeyPress = e => { | ||
this.isShiftKeyPressed = e.shiftKey; | ||
}; | ||
/** | ||
* Toggles file/folder checkbox to on/off state while updating files list. | ||
* | ||
* Note that some extra complexity comes from supporting shift+click to | ||
* toggle multiple checkboxes at once, which is done by getting all files | ||
* in between last checked file and current one. | ||
*/ | ||
this.toggleCheckbox = (e, file) => { | ||
@@ -32,20 +35,23 @@ e.stopPropagation(); | ||
} = this.plugin.getPluginState(); | ||
const items = this.filterItems(folders.concat(files)); // Shift-clicking selects a single consecutive list of items | ||
// starting at the previous click and deselects everything else. | ||
const items = this.filterItems(folders.concat(files)); | ||
// Shift-clicking selects a single consecutive list of items | ||
// starting at the previous click. | ||
if (this.lastCheckbox && this.isShiftKeyPressed) { | ||
const { | ||
currentSelection | ||
} = this.plugin.getPluginState(); | ||
const prevIndex = items.indexOf(this.lastCheckbox); | ||
const currentIndex = items.indexOf(file); | ||
const currentSelection = prevIndex < currentIndex ? items.slice(prevIndex, currentIndex + 1) : items.slice(currentIndex, prevIndex + 1); | ||
const reducedCurrentSelection = []; // Check restrictions on each file in currentSelection, | ||
const newSelection = prevIndex < currentIndex ? items.slice(prevIndex, currentIndex + 1) : items.slice(currentIndex, prevIndex + 1); | ||
const reducedNewSelection = []; | ||
// Check restrictions on each file in currentSelection, | ||
// reduce it to only contain files that pass restrictions | ||
for (const item of currentSelection) { | ||
for (const item of newSelection) { | ||
const { | ||
uppy | ||
} = this.plugin; | ||
const restrictionError = uppy.validateRestrictions(remoteFileObjToLocal(item), [...uppy.getFiles(), ...reducedCurrentSelection]); | ||
const restrictionError = uppy.validateRestrictions(remoteFileObjToLocal(item), [...uppy.getFiles(), ...reducedNewSelection]); | ||
if (!restrictionError) { | ||
reducedCurrentSelection.push(item); | ||
reducedNewSelection.push(item); | ||
} else { | ||
@@ -57,9 +63,7 @@ uppy.info({ | ||
} | ||
this.plugin.setPluginState({ | ||
currentSelection: reducedCurrentSelection | ||
currentSelection: [...new Set([...currentSelection, ...reducedNewSelection])] | ||
}); | ||
return; | ||
} | ||
this.lastCheckbox = file; | ||
@@ -69,3 +73,2 @@ const { | ||
} = this.plugin.getPluginState(); | ||
if (this.isChecked(file)) { | ||
@@ -81,12 +84,10 @@ this.plugin.setPluginState({ | ||
}; | ||
this.isChecked = file => { | ||
const { | ||
currentSelection | ||
} = this.plugin.getPluginState(); // comparing id instead of the file object, because the reference to the object | ||
} = this.plugin.getPluginState(); | ||
// comparing id instead of the file object, because the reference to the object | ||
// changes when we switch folders, and the file list is updated | ||
return currentSelection.some(item => item.id === file.id); | ||
}; | ||
this.plugin = plugin; | ||
@@ -100,3 +101,2 @@ this.provider = opts.provider; | ||
} | ||
preFirstRender() { | ||
@@ -107,5 +107,5 @@ this.plugin.setPluginState({ | ||
this.plugin.onFirstRender(); | ||
} // eslint-disable-next-line class-methods-use-this | ||
} | ||
// eslint-disable-next-line class-methods-use-this | ||
shouldHandleScroll(event) { | ||
@@ -120,3 +120,2 @@ const { | ||
} | ||
clearSelection() { | ||
@@ -128,7 +127,5 @@ this.plugin.setPluginState({ | ||
} | ||
cancelPicking() { | ||
this.clearSelection(); | ||
const dashboard = this.plugin.uppy.getPlugin('Dashboard'); | ||
if (dashboard) { | ||
@@ -138,3 +135,2 @@ dashboard.hideAllPanels(); | ||
} | ||
handleError(error) { | ||
@@ -146,7 +142,5 @@ const { | ||
uppy.log(error.toString()); | ||
if (error.isAuthError) { | ||
return; | ||
} | ||
uppy.info({ | ||
@@ -156,5 +150,5 @@ message, | ||
}, 'error', 5000); | ||
} // todo document what is a "tagFile" or get rid of this concept | ||
} | ||
// todo document what is a "tagFile" or get rid of this concept | ||
getTagFile(file) { | ||
@@ -183,8 +177,8 @@ const tagFile = { | ||
}; | ||
const fileType = getFileType(tagFile); // TODO Should we just always use the thumbnail URL if it exists? | ||
const fileType = getFileType(tagFile); | ||
// TODO Should we just always use the thumbnail URL if it exists? | ||
if (fileType && isPreviewSupported(fileType)) { | ||
tagFile.preview = file.thumbnail; | ||
} | ||
if (file.author) { | ||
@@ -194,6 +188,4 @@ if (file.author.name != null) tagFile.meta.authorName = String(file.author.name); | ||
} | ||
return tagFile; | ||
} | ||
setLoading(loading) { | ||
@@ -204,3 +196,2 @@ this.plugin.setPluginState({ | ||
} | ||
} |
{ | ||
"name": "@uppy/provider-views", | ||
"description": "View library for Uppy remote provider plugins.", | ||
"version": "3.3.0", | ||
"version": "3.3.1", | ||
"license": "MIT", | ||
@@ -23,3 +23,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@uppy/utils": "^5.3.0", | ||
"@uppy/utils": "^5.4.0", | ||
"classnames": "^2.2.6", | ||
@@ -31,4 +31,4 @@ "nanoid": "^4.0.0", | ||
"peerDependencies": { | ||
"@uppy/core": "^3.2.0" | ||
"@uppy/core": "^3.2.1" | ||
} | ||
} |
@@ -36,2 +36,3 @@ import { h } from 'preact' | ||
onKeyDown={recordShiftKeyPress} | ||
onMouseDown={recordShiftKeyPress} | ||
name="listitem" | ||
@@ -38,0 +39,0 @@ id={id} |
@@ -39,2 +39,3 @@ import { h } from 'preact' | ||
onKeyDown={recordShiftKeyPress} | ||
onMouseDown={recordShiftKeyPress} | ||
// for the <label/> | ||
@@ -41,0 +42,0 @@ name="listitem" |
@@ -127,2 +127,3 @@ import { h } from 'preact' | ||
this.plugin.setPluginState({ directories: updatedDirectories, filterInput: '' }) | ||
this.lastCheckbox = undefined | ||
} catch (err) { | ||
@@ -129,0 +130,0 @@ this.handleError(err) |
@@ -141,3 +141,3 @@ import { h } from 'preact' | ||
const { files, folders, filterInput, loading, currentSelection } = this.plugin.getPluginState() | ||
const { isChecked, toggleCheckbox, filterItems } = this | ||
const { isChecked, toggleCheckbox, filterItems, recordShiftKeyPress } = this | ||
const hasInput = filterInput !== '' | ||
@@ -148,2 +148,3 @@ | ||
toggleCheckbox, | ||
recordShiftKeyPress, | ||
currentSelection, | ||
@@ -150,0 +151,0 @@ files: hasInput ? filterItems(files) : files, |
@@ -126,22 +126,23 @@ import getFileType from '@uppy/utils/lib/getFileType' | ||
// Shift-clicking selects a single consecutive list of items | ||
// starting at the previous click and deselects everything else. | ||
// starting at the previous click. | ||
if (this.lastCheckbox && this.isShiftKeyPressed) { | ||
const { currentSelection } = this.plugin.getPluginState() | ||
const prevIndex = items.indexOf(this.lastCheckbox) | ||
const currentIndex = items.indexOf(file) | ||
const currentSelection = (prevIndex < currentIndex) | ||
const newSelection = (prevIndex < currentIndex) | ||
? items.slice(prevIndex, currentIndex + 1) | ||
: items.slice(currentIndex, prevIndex + 1) | ||
const reducedCurrentSelection = [] | ||
const reducedNewSelection = [] | ||
// Check restrictions on each file in currentSelection, | ||
// reduce it to only contain files that pass restrictions | ||
for (const item of currentSelection) { | ||
for (const item of newSelection) { | ||
const { uppy } = this.plugin | ||
const restrictionError = uppy.validateRestrictions( | ||
remoteFileObjToLocal(item), | ||
[...uppy.getFiles(), ...reducedCurrentSelection], | ||
[...uppy.getFiles(), ...reducedNewSelection], | ||
) | ||
if (!restrictionError) { | ||
reducedCurrentSelection.push(item) | ||
reducedNewSelection.push(item) | ||
} else { | ||
@@ -151,3 +152,3 @@ uppy.info({ message: restrictionError.message }, 'error', uppy.opts.infoTimeout) | ||
} | ||
this.plugin.setPluginState({ currentSelection: reducedCurrentSelection }) | ||
this.plugin.setPluginState({ currentSelection: [...new Set([...currentSelection, ...reducedNewSelection])] }) | ||
return | ||
@@ -154,0 +155,0 @@ } |
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
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
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
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
245442
3482
Updated@uppy/utils@^5.4.0