@uppy/provider-views
Version:
View library for Uppy remote provider plugins.
187 lines (186 loc) • 8.58 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
import { remoteFileObjToLocal } from '@uppy/utils';
import classNames from 'classnames';
import packageJson from '../../package.json' with { type: 'json' };
import Browser from '../Browser.js';
import FooterActions from '../FooterActions.js';
import SearchInput from '../SearchInput.js';
import addFiles from '../utils/addFiles.js';
import getClickedRange from '../utils/getClickedRange.js';
import handleError from '../utils/handleError.js';
import getCheckedFilesWithPaths from '../utils/PartialTreeUtils/getCheckedFilesWithPaths.js';
import PartialTreeUtils from '../utils/PartialTreeUtils/index.js';
import shouldHandleScroll from '../utils/shouldHandleScroll.js';
const defaultState = {
loading: false,
searchString: '',
partialTree: [
{
type: 'root',
id: null,
cached: false,
nextPagePath: null,
},
],
currentFolderId: null,
isInputMode: true,
};
const defaultOptions = {
viewType: 'grid',
showTitles: true,
showFilter: true,
utmSource: 'Companion',
};
/**
* SearchProviderView, used for Unsplash and future image search providers.
* Extends generic View, shared with regular providers like Google Drive and Instagram.
*/
export default class SearchProviderView {
static VERSION = packageJson.version;
plugin;
provider;
opts;
isHandlingScroll = false;
lastCheckbox = null;
constructor(plugin, opts) {
this.plugin = plugin;
this.provider = opts.provider;
this.opts = { ...defaultOptions, ...opts };
this.setSearchString = this.setSearchString.bind(this);
this.search = this.search.bind(this);
this.resetPluginState = this.resetPluginState.bind(this);
this.handleScroll = this.handleScroll.bind(this);
this.donePicking = this.donePicking.bind(this);
this.cancelSelection = this.cancelSelection.bind(this);
this.toggleCheckbox = this.toggleCheckbox.bind(this);
this.render = this.render.bind(this);
// Set default state for the plugin
this.resetPluginState();
// @ts-expect-error this should be typed in @uppy/dashboard.
this.plugin.uppy.on('dashboard:close-panel', this.resetPluginState);
this.plugin.uppy.registerRequestClient(this.provider.provider, this.provider);
}
tearDown() {
// Nothing.
}
setLoading(loading) {
this.plugin.setPluginState({ loading });
}
resetPluginState() {
this.plugin.setPluginState(defaultState);
}
cancelSelection() {
const { partialTree } = this.plugin.getPluginState();
const newPartialTree = partialTree.map((item) => item.type === 'root' ? item : { ...item, status: 'unchecked' });
this.plugin.setPluginState({ partialTree: newPartialTree });
}
async search() {
const { searchString } = this.plugin.getPluginState();
if (searchString === '')
return;
this.setLoading(true);
try {
const response = await this.provider.search(searchString);
const newPartialTree = [
{
type: 'root',
id: null,
cached: false,
nextPagePath: response.nextPageQuery,
},
...response.items.map((item) => ({
type: 'file',
id: item.requestPath,
status: 'unchecked',
parentId: null,
data: item,
})),
];
this.plugin.setPluginState({
partialTree: newPartialTree,
isInputMode: false,
});
}
catch (error) {
handleError(this.plugin.uppy)(error);
}
this.setLoading(false);
}
async handleScroll(event) {
const { partialTree, searchString } = this.plugin.getPluginState();
const root = partialTree.find((i) => i.type === 'root');
if (shouldHandleScroll(event) &&
!this.isHandlingScroll &&
root.nextPagePath) {
this.isHandlingScroll = true;
try {
const response = await this.provider.search(searchString, root.nextPagePath);
const newRoot = {
...root,
nextPagePath: response.nextPageQuery,
};
const oldItems = partialTree.filter((i) => i.type !== 'root');
const newPartialTree = [
newRoot,
...oldItems,
...response.items.map((item) => ({
type: 'file',
id: item.requestPath,
status: 'unchecked',
parentId: null,
data: item,
})),
];
this.plugin.setPluginState({ partialTree: newPartialTree });
}
catch (error) {
handleError(this.plugin.uppy)(error);
}
this.isHandlingScroll = false;
}
}
async donePicking() {
const { partialTree } = this.plugin.getPluginState();
// 1. Add files
const companionFiles = getCheckedFilesWithPaths(partialTree);
addFiles(companionFiles, this.plugin, this.provider);
// 2. Reset state
this.resetPluginState();
}
toggleCheckbox(ourItem, isShiftKeyPressed) {
const { partialTree } = this.plugin.getPluginState();
const clickedRange = getClickedRange(ourItem.id, this.getDisplayedPartialTree(), isShiftKeyPressed, this.lastCheckbox);
const newPartialTree = PartialTreeUtils.afterToggleCheckbox(partialTree, clickedRange);
this.plugin.setPluginState({ partialTree: newPartialTree });
this.lastCheckbox = ourItem.id;
}
validateSingleFile = (file) => {
const companionFile = remoteFileObjToLocal(file);
const result = this.plugin.uppy.validateSingleFile(companionFile);
return result;
};
getDisplayedPartialTree = () => {
const { partialTree } = this.plugin.getPluginState();
return partialTree.filter((item) => item.type !== 'root');
};
setSearchString = (searchString) => {
this.plugin.setPluginState({ searchString });
if (searchString === '') {
this.plugin.setPluginState({ partialTree: [] });
}
};
validateAggregateRestrictions = (partialTree) => {
const checkedFiles = partialTree.filter((item) => item.type === 'file' && item.status === 'checked');
const uppyFiles = checkedFiles.map((file) => file.data);
return this.plugin.uppy.validateAggregateRestrictions(uppyFiles);
};
render(state, viewOptions = {}) {
const { isInputMode, searchString, loading, partialTree } = this.plugin.getPluginState();
const { i18n } = this.plugin.uppy;
const opts = { ...this.opts, ...viewOptions };
if (isInputMode) {
return (_jsx(SearchInput, { searchString: searchString, setSearchString: this.setSearchString, submitSearchString: this.search, inputLabel: i18n('enterTextToSearch'), buttonLabel: i18n('searchImages'), wrapperClassName: "uppy-SearchProvider", inputClassName: "uppy-c-textInput uppy-SearchProvider-input", showButton: true, buttonCSSClassName: "uppy-SearchProvider-searchButton" }));
}
return (_jsxs("div", { className: classNames('uppy-ProviderBrowser', `uppy-ProviderBrowser-viewType--${opts.viewType}`), children: [opts.showFilter && (_jsx(SearchInput, { searchString: searchString, setSearchString: this.setSearchString, submitSearchString: this.search, inputLabel: i18n('search'), clearSearchLabel: i18n('resetSearch'), wrapperClassName: "uppy-ProviderBrowser-searchFilter", inputClassName: "uppy-ProviderBrowser-searchFilterInput" })), _jsx(Browser, { toggleCheckbox: this.toggleCheckbox, displayedPartialTree: this.getDisplayedPartialTree(), handleScroll: this.handleScroll, openFolder: async () => { }, noResultsLabel: i18n('noSearchResults'), viewType: opts.viewType, showTitles: opts.showTitles, isLoading: loading, i18n: i18n, virtualList: false, utmSource: this.opts.utmSource }), _jsx(FooterActions, { partialTree: partialTree, donePicking: this.donePicking, cancelSelection: this.cancelSelection, i18n: i18n, validateAggregateRestrictions: this.validateAggregateRestrictions })] }));
}
}