From 102d8f886be84abc3466e342770a6116bd837d8f Mon Sep 17 00:00:00 2001 From: Murderlon Date: Tue, 5 Mar 2024 11:44:08 +0100 Subject: [PATCH 1/4] @uppy/url: migrate to TS --- packages/@uppy/provider-views/src/View.ts | 37 +-- packages/@uppy/provider-views/src/index.ts | 1 + packages/@uppy/url/.npmignore | 1 + packages/@uppy/url/src/Url.jsx | 195 -------------- packages/@uppy/url/src/Url.tsx | 238 ++++++++++++++++++ .../@uppy/url/src/{UrlUI.jsx => UrlUI.tsx} | 26 +- packages/@uppy/url/src/index.js | 1 - packages/@uppy/url/src/index.ts | 1 + .../@uppy/url/src/{locale.js => locale.ts} | 6 +- ...tedUrl.js => forEachDroppedOrPastedUrl.ts} | 24 +- packages/@uppy/url/tsconfig.build.json | 30 +++ packages/@uppy/url/tsconfig.json | 26 ++ packages/@uppy/utils/src/UppyFile.ts | 47 +++- 13 files changed, 382 insertions(+), 251 deletions(-) create mode 100644 packages/@uppy/url/.npmignore delete mode 100644 packages/@uppy/url/src/Url.jsx create mode 100644 packages/@uppy/url/src/Url.tsx rename packages/@uppy/url/src/{UrlUI.jsx => UrlUI.tsx} (69%) delete mode 100644 packages/@uppy/url/src/index.js create mode 100644 packages/@uppy/url/src/index.ts rename packages/@uppy/url/src/{locale.js => locale.ts} (61%) rename packages/@uppy/url/src/utils/{forEachDroppedOrPastedUrl.js => forEachDroppedOrPastedUrl.ts} (81%) create mode 100644 packages/@uppy/url/tsconfig.build.json create mode 100644 packages/@uppy/url/tsconfig.json diff --git a/packages/@uppy/provider-views/src/View.ts b/packages/@uppy/provider-views/src/View.ts index cbdb485ad6..126a46d412 100644 --- a/packages/@uppy/provider-views/src/View.ts +++ b/packages/@uppy/provider-views/src/View.ts @@ -2,38 +2,12 @@ import type { UnknownProviderPlugin, UnknownSearchProviderPlugin, } from '@uppy/core/lib/Uppy' -import type { Body, Meta } from '@uppy/utils/lib/UppyFile' +import type { Body, Meta, TagFile } from '@uppy/utils/lib/UppyFile' import type { CompanionFile } from '@uppy/utils/lib/CompanionFile' import getFileType from '@uppy/utils/lib/getFileType' import isPreviewSupported from '@uppy/utils/lib/isPreviewSupported' import remoteFileObjToLocal from '@uppy/utils/lib/remoteFileObjToLocal' -type TagFile = { - id: string - source: string - data: Blob - name: string - type: string - isRemote: boolean - preview?: string - meta: { - authorName?: string - authorUrl?: string - relativePath?: string | null - absolutePath?: string - } & M - remote: { - companionUrl: string - url: string - body: { - fileId: string - } - providerName: string - provider: string - requestClientId: string - } -} - type PluginType = 'Provider' | 'SearchProvider' // Conditional type for selecting the plugin @@ -155,7 +129,6 @@ export default class View< name: file.name || file.id, type: file.mimeType, isRemote: true, - // @ts-expect-error meta is filled conditionally below data: file, // @ts-expect-error meta is filled conditionally below meta: {}, @@ -184,17 +157,17 @@ export default class View< if (file.author) { if (file.author.name != null) - tagFile.meta.authorName = String(file.author.name) - if (file.author.url) tagFile.meta.authorUrl = file.author.url + tagFile.meta!.authorName = String(file.author.name) + if (file.author.url) tagFile.meta!.authorUrl = file.author.url } // add relativePath similar to non-remote files: https://github.com/transloadit/uppy/pull/4486#issuecomment-1579203717 if (file.relDirPath != null) - tagFile.meta.relativePath = + tagFile.meta!.relativePath = file.relDirPath ? `${file.relDirPath}/${tagFile.name}` : null // and absolutePath (with leading slash) https://github.com/transloadit/uppy/pull/4537#issuecomment-1614236655 if (file.absDirPath != null) - tagFile.meta.absolutePath = + tagFile.meta!.absolutePath = file.absDirPath ? `/${file.absDirPath}/${tagFile.name}` : `/${tagFile.name}` diff --git a/packages/@uppy/provider-views/src/index.ts b/packages/@uppy/provider-views/src/index.ts index 22281fd810..64c621627e 100644 --- a/packages/@uppy/provider-views/src/index.ts +++ b/packages/@uppy/provider-views/src/index.ts @@ -2,4 +2,5 @@ export { default as ProviderViews, defaultPickerIcon, } from './ProviderView/index.ts' + export { default as SearchProviderViews } from './SearchProviderView/index.ts' diff --git a/packages/@uppy/url/.npmignore b/packages/@uppy/url/.npmignore new file mode 100644 index 0000000000..6c816673f0 --- /dev/null +++ b/packages/@uppy/url/.npmignore @@ -0,0 +1 @@ +tsconfig.* diff --git a/packages/@uppy/url/src/Url.jsx b/packages/@uppy/url/src/Url.jsx deleted file mode 100644 index a4889a2e0f..0000000000 --- a/packages/@uppy/url/src/Url.jsx +++ /dev/null @@ -1,195 +0,0 @@ -import { h } from 'preact' -import { UIPlugin } from '@uppy/core' -import { RequestClient } from '@uppy/companion-client' -import toArray from '@uppy/utils/lib/toArray' -import UrlUI from './UrlUI.jsx' -import forEachDroppedOrPastedUrl from './utils/forEachDroppedOrPastedUrl.js' - -import packageJson from '../package.json' -import locale from './locale.js' - -function UrlIcon () { - return ( - - ) -} - -function addProtocolToURL (url) { - const protocolRegex = /^[a-z0-9]+:\/\// - const defaultProtocol = 'http://' - if (protocolRegex.test(url)) { - return url - } - - return defaultProtocol + url -} - -function canHandleRootDrop (e) { - const items = toArray(e.dataTransfer.items) - const urls = items.filter((item) => item.kind === 'string' - && item.type === 'text/uri-list') - return urls.length > 0 -} - -function checkIfCorrectURL (url) { - if (!url) return false - - const protocol = url.match(/^([a-z0-9]+):\/\//)[1] - if (protocol !== 'http' && protocol !== 'https') { - return false - } - - return true -} - -function getFileNameFromUrl (url) { - const { pathname } = new URL(url) - return pathname.substring(pathname.lastIndexOf('/') + 1) -} - -/** - * Url - * - */ -export default class Url extends UIPlugin { - static VERSION = packageJson.version - - static requestClientId = Url.name - - constructor (uppy, opts) { - super(uppy, opts) - this.id = this.opts.id || 'Url' - this.title = this.opts.title || 'Link' - this.type = 'acquirer' - this.icon = () => - - // Set default options and locale - this.defaultLocale = locale - - const defaultOptions = {} - - this.opts = { ...defaultOptions, ...opts } - - this.i18nInit() - - this.hostname = this.opts.companionUrl - - if (!this.hostname) { - throw new Error('Companion hostname is required, please consult https://uppy.io/docs/companion') - } - - // Bind all event handlers for referencability - this.getMeta = this.getMeta.bind(this) - this.addFile = this.addFile.bind(this) - this.handleRootDrop = this.handleRootDrop.bind(this) - this.handleRootPaste = this.handleRootPaste.bind(this) - - this.client = new RequestClient(uppy, { - companionUrl: this.opts.companionUrl, - companionHeaders: this.opts.companionHeaders, - companionCookiesRule: this.opts.companionCookiesRule, - }) - - this.uppy.registerRequestClient(Url.requestClientId, this.client) - } - - getMeta (url) { - return this.client.post('url/meta', { url }) - .then((res) => { - if (res.error) { - this.uppy.log('[URL] Error:') - this.uppy.log(res.error) - throw new Error('Failed to fetch the file') - } - return res - }) - } - - async addFile (protocollessUrl, optionalMeta = undefined) { - const url = addProtocolToURL(protocollessUrl) - if (!checkIfCorrectURL(url)) { - this.uppy.log(`[URL] Incorrect URL entered: ${url}`) - this.uppy.info(this.i18n('enterCorrectUrl'), 'error', 4000) - return undefined - } - - try { - const meta = await this.getMeta(url) - - const tagFile = { - meta: optionalMeta, - source: this.id, - name: meta.name || getFileNameFromUrl(url), - type: meta.type, - data: { - size: meta.size, - }, - isRemote: true, - body: { - url, - }, - remote: { - companionUrl: this.opts.companionUrl, - url: `${this.hostname}/url/get`, - body: { - fileId: url, - url, - }, - requestClientId: Url.requestClientId, - }, - } - - this.uppy.log('[Url] Adding remote file') - try { - return this.uppy.addFile(tagFile) - } catch (err) { - if (!err.isRestriction) { - this.uppy.log(err) - } - return err - } - } catch (err) { - this.uppy.log(err) - this.uppy.info({ - message: this.i18n('failedToFetch'), - details: err, - }, 'error', 4000) - return err - } - } - - handleRootDrop (e) { - forEachDroppedOrPastedUrl(e.dataTransfer, 'drop', (url) => { - this.uppy.log(`[URL] Adding file from dropped url: ${url}`) - this.addFile(url) - }) - } - - handleRootPaste (e) { - forEachDroppedOrPastedUrl(e.clipboardData, 'paste', (url) => { - this.uppy.log(`[URL] Adding file from pasted url: ${url}`) - this.addFile(url) - }) - } - - render () { - return - } - - install () { - const { target } = this.opts - if (target) { - this.mount(target, this) - } - } - - uninstall () { - this.unmount() - } -} - -// This is defined outside of the class body because it's not using `this`, but -// we still want it available on the prototype so the Dashboard can access it. -Url.prototype.canHandleRootDrop = canHandleRootDrop diff --git a/packages/@uppy/url/src/Url.tsx b/packages/@uppy/url/src/Url.tsx new file mode 100644 index 0000000000..e3775947b8 --- /dev/null +++ b/packages/@uppy/url/src/Url.tsx @@ -0,0 +1,238 @@ +import { h, type ComponentChild } from 'preact' +import { UIPlugin, Uppy } from '@uppy/core' +import { + RequestClient, + type CompanionPluginOptions, +} from '@uppy/companion-client' +import toArray from '@uppy/utils/lib/toArray' +import type { TagFile, Meta, Body } from '@uppy/utils/lib/UppyFile' +import UrlUI from './UrlUI.tsx' +import forEachDroppedOrPastedUrl from './utils/forEachDroppedOrPastedUrl.ts' + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore We don't want TS to generate types for the package.json +import packageJson from '../package.json' +import locale from './locale.ts' + +function UrlIcon() { + return ( + + ) +} + +function addProtocolToURL(url: string) { + const protocolRegex = /^[a-z0-9]+:\/\// + const defaultProtocol = 'http://' + if (protocolRegex.test(url)) { + return url + } + + return defaultProtocol + url +} + +function canHandleRootDrop(e: DragEvent) { + const items = toArray(e.dataTransfer!.items) + const urls = items.filter( + (item) => item.kind === 'string' && item.type === 'text/uri-list', + ) + return urls.length > 0 +} + +function checkIfCorrectURL(url?: string) { + if (!url) return false + + const protocol = url.match(/^([a-z0-9]+):\/\//)![1] + if (protocol !== 'http' && protocol !== 'https') { + return false + } + + return true +} + +function getFileNameFromUrl(url: string) { + const { pathname } = new URL(url) + return pathname.substring(pathname.lastIndexOf('/') + 1) +} + +/* + * Response from the /url/meta Companion endpoint. + * Has to be kept in sync with `getURLMeta` in `companion/src/server/helpers/request.js`. + */ +type MetaResponse = { + name: string + type: string + size: number | null + statusCode: number +} + +export type UrlOptions = CompanionPluginOptions + +export default class Url extends UIPlugin< + UrlOptions, + M, + B +> { + static VERSION = packageJson.version + + static requestClientId = Url.name + + icon: () => JSX.Element + + hostname: string + + client: RequestClient + + canHandleRootDrop: typeof canHandleRootDrop + + constructor(uppy: Uppy, opts: UrlOptions) { + super(uppy, opts) + this.id = this.opts.id || 'Url' + this.title = this.opts.title || 'Link' + this.type = 'acquirer' + this.icon = () => + + // Set default options and locale + this.defaultLocale = locale + + this.i18nInit() + + this.hostname = this.opts.companionUrl + + if (!this.hostname) { + throw new Error( + 'Companion hostname is required, please consult https://uppy.io/docs/companion', + ) + } + + // Bind all event handlers for referencability + this.getMeta = this.getMeta.bind(this) + this.addFile = this.addFile.bind(this) + this.handleRootDrop = this.handleRootDrop.bind(this) + this.handleRootPaste = this.handleRootPaste.bind(this) + + this.client = new RequestClient(uppy, { + pluginId: this.id, + provider: 'url', + companionUrl: this.opts.companionUrl, + companionHeaders: this.opts.companionHeaders, + companionCookiesRule: this.opts.companionCookiesRule, + }) + + this.uppy.registerRequestClient(Url.requestClientId, this.client) + } + + async getMeta(url: string): Promise { + try { + return this.client.post('url/meta', { url }) + } catch (error) { + this.uppy.log('[URL] Error:') + this.uppy.log(error) + throw new Error('Failed to fetch the file') + } + } + + async addFile( + protocollessUrl: string, + optionalMeta?: M, + ): Promise { + const url = addProtocolToURL(protocollessUrl) + if (!checkIfCorrectURL(url)) { + this.uppy.log(`[URL] Incorrect URL entered: ${url}`) + this.uppy.info(this.i18n('enterCorrectUrl'), 'error', 4000) + return undefined + } + + try { + const meta = await this.getMeta(url) + + const tagFile: TagFile = { + meta: optionalMeta, + source: this.id, + name: meta.name || getFileNameFromUrl(url), + type: meta.type, + data: { + size: meta.size, + }, + isRemote: true, + body: { + url, + }, + remote: { + companionUrl: this.opts.companionUrl, + url: `${this.hostname}/url/get`, + body: { + fileId: url, + url, + }, + requestClientId: Url.requestClientId, + }, + } + + this.uppy.log('[Url] Adding remote file') + try { + return this.uppy.addFile(tagFile) + } catch (err) { + if (!err.isRestriction) { + this.uppy.log(err) + } + return err + } + } catch (err) { + this.uppy.log(err) + this.uppy.info( + { + message: this.i18n('failedToFetch'), + details: err, + }, + 'error', + 4000, + ) + return err + } + } + + handleRootDrop(e: DragEvent): void { + forEachDroppedOrPastedUrl(e.dataTransfer!, 'drop', (url) => { + this.uppy.log(`[URL] Adding file from dropped url: ${url}`) + this.addFile(url) + }) + } + + handleRootPaste(e: ClipboardEvent): void { + forEachDroppedOrPastedUrl(e.clipboardData!, 'paste', (url) => { + this.uppy.log(`[URL] Adding file from pasted url: ${url}`) + this.addFile(url) + }) + } + + render(): ComponentChild { + return + } + + install(): void { + const { target } = this.opts + if (target) { + this.mount(target, this) + } + } + + uninstall(): void { + this.unmount() + } +} + +// This is defined outside of the class body because it's not using `this`, but +// we still want it available on the prototype so the Dashboard can access it. +Url.prototype.canHandleRootDrop = canHandleRootDrop diff --git a/packages/@uppy/url/src/UrlUI.jsx b/packages/@uppy/url/src/UrlUI.tsx similarity index 69% rename from packages/@uppy/url/src/UrlUI.jsx rename to packages/@uppy/url/src/UrlUI.tsx index f1edf16bb2..9149a201c2 100644 --- a/packages/@uppy/url/src/UrlUI.jsx +++ b/packages/@uppy/url/src/UrlUI.tsx @@ -1,33 +1,41 @@ -import { h, Component } from 'preact' +import { h, Component, type ComponentChild } from 'preact' import { nanoid } from 'nanoid/non-secure' +import type { I18n } from '@uppy/utils/lib/Translator' -class UrlUI extends Component { +type UrlUIProps = { + i18n: I18n + addFile: (url: string) => void +} + +class UrlUI extends Component { form = document.createElement('form') - constructor (props) { + input: HTMLInputElement + + constructor(props: UrlUIProps) { super(props) this.form.id = nanoid() } - componentDidMount () { + componentDidMount(): void { this.input.value = '' this.form.addEventListener('submit', this.#handleSubmit) document.body.appendChild(this.form) } - componentWillUnmount () { + componentWillUnmount(): void { this.form.removeEventListener('submit', this.#handleSubmit) document.body.removeChild(this.form) } - #handleSubmit = (ev) => { + #handleSubmit = (ev: SubmitEvent) => { ev.preventDefault() const { addFile } = this.props const preparedValue = this.input.value.trim() addFile(preparedValue) } - render () { + render(): ComponentChild { const { i18n } = this.props return (
@@ -36,7 +44,9 @@ class UrlUI extends Component { type="text" aria-label={i18n('enterUrlToImport')} placeholder={i18n('enterUrlToImport')} - ref={(input) => { this.input = input }} + ref={(input) => { + this.input = input! + }} data-uppy-super-focusable form={this.form.id} /> diff --git a/packages/@uppy/url/src/index.js b/packages/@uppy/url/src/index.js deleted file mode 100644 index a427b2b25e..0000000000 --- a/packages/@uppy/url/src/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Url.jsx' diff --git a/packages/@uppy/url/src/index.ts b/packages/@uppy/url/src/index.ts new file mode 100644 index 0000000000..dc341e0ed8 --- /dev/null +++ b/packages/@uppy/url/src/index.ts @@ -0,0 +1 @@ +export { default } from './Url.tsx' diff --git a/packages/@uppy/url/src/locale.js b/packages/@uppy/url/src/locale.ts similarity index 61% rename from packages/@uppy/url/src/locale.js rename to packages/@uppy/url/src/locale.ts index 79350e25aa..859037030c 100644 --- a/packages/@uppy/url/src/locale.js +++ b/packages/@uppy/url/src/locale.ts @@ -5,8 +5,10 @@ export default { // Placeholder text for the URL input. enterUrlToImport: 'Enter URL to import a file', // Error message shown if Companion could not load a URL. - failedToFetch: 'Companion failed to fetch this URL, please make sure it’s correct', + failedToFetch: + 'Companion failed to fetch this URL, please make sure it’s correct', // Error message shown if the input does not look like a URL. - enterCorrectUrl: 'Incorrect URL: Please make sure you are entering a direct link to a file', + enterCorrectUrl: + 'Incorrect URL: Please make sure you are entering a direct link to a file', }, } diff --git a/packages/@uppy/url/src/utils/forEachDroppedOrPastedUrl.js b/packages/@uppy/url/src/utils/forEachDroppedOrPastedUrl.ts similarity index 81% rename from packages/@uppy/url/src/utils/forEachDroppedOrPastedUrl.js rename to packages/@uppy/url/src/utils/forEachDroppedOrPastedUrl.ts index a0c700a1a2..c05bae3837 100644 --- a/packages/@uppy/url/src/utils/forEachDroppedOrPastedUrl.js +++ b/packages/@uppy/url/src/utils/forEachDroppedOrPastedUrl.ts @@ -53,12 +53,12 @@ import toArray from '@uppy/utils/lib/toArray' /** * Finds all links dropped/pasted from one browser window to another. - * - * @param {object} dataTransfer - DataTransfer instance, e.g. e.clipboardData, or e.dataTransfer - * @param {string} isDropOrPaste - either 'drop' or 'paste' - * @param {Function} callback - (urlString) => {} */ -export default function forEachDroppedOrPastedUrl (dataTransfer, isDropOrPaste, callback) { +export default function forEachDroppedOrPastedUrl( + dataTransfer: DataTransfer, + isDropOrPaste: 'drop' | 'paste', + callback: (url: string) => void, +): void { const items = toArray(dataTransfer.items) let urlItems @@ -69,18 +69,22 @@ export default function forEachDroppedOrPastedUrl (dataTransfer, isDropOrPaste, if (atLeastOneFileIsDragged) { return } - urlItems = items.filter((item) => item.kind === 'string' - && item.type === 'text/plain') + urlItems = items.filter( + (item) => item.kind === 'string' && item.type === 'text/plain', + ) break } case 'drop': { - urlItems = items.filter((item) => item.kind === 'string' - && item.type === 'text/uri-list') + urlItems = items.filter( + (item) => item.kind === 'string' && item.type === 'text/uri-list', + ) break } default: { - throw new Error(`isDropOrPaste must be either 'drop' or 'paste', but it's ${isDropOrPaste}`) + throw new Error( + `isDropOrPaste must be either 'drop' or 'paste', but it's ${isDropOrPaste}`, + ) } } diff --git a/packages/@uppy/url/tsconfig.build.json b/packages/@uppy/url/tsconfig.build.json new file mode 100644 index 0000000000..40df14c108 --- /dev/null +++ b/packages/@uppy/url/tsconfig.build.json @@ -0,0 +1,30 @@ +{ + "extends": "../../../tsconfig.shared", + "compilerOptions": { + "noImplicitAny": false, + "outDir": "./lib", + "paths": { + "@uppy/companion-client": ["../companion-client/src/index.js"], + "@uppy/companion-client/lib/*": ["../companion-client/src/*"], + "@uppy/utils/lib/*": ["../utils/src/*"], + "@uppy/core": ["../core/src/index.js"], + "@uppy/core/lib/*": ["../core/src/*"] + }, + "resolveJsonModule": false, + "rootDir": "./src", + "skipLibCheck": true + }, + "include": ["./src/**/*.*"], + "exclude": ["./src/**/*.test.ts"], + "references": [ + { + "path": "../companion-client/tsconfig.build.json" + }, + { + "path": "../utils/tsconfig.build.json" + }, + { + "path": "../core/tsconfig.build.json" + } + ] +} diff --git a/packages/@uppy/url/tsconfig.json b/packages/@uppy/url/tsconfig.json new file mode 100644 index 0000000000..f43408fa18 --- /dev/null +++ b/packages/@uppy/url/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../../../tsconfig.shared", + "compilerOptions": { + "emitDeclarationOnly": false, + "noEmit": true, + "paths": { + "@uppy/companion-client": ["../companion-client/src/index.js"], + "@uppy/companion-client/lib/*": ["../companion-client/src/*"], + "@uppy/utils/lib/*": ["../utils/src/*"], + "@uppy/core": ["../core/src/index.js"], + "@uppy/core/lib/*": ["../core/src/*"], + }, + }, + "include": ["./package.json", "./src/**/*.*"], + "references": [ + { + "path": "../companion-client/tsconfig.build.json", + }, + { + "path": "../utils/tsconfig.build.json", + }, + { + "path": "../core/tsconfig.build.json", + }, + ], +} diff --git a/packages/@uppy/utils/src/UppyFile.ts b/packages/@uppy/utils/src/UppyFile.ts index 7ffa9bc8ba..f0374e45c9 100644 --- a/packages/@uppy/utils/src/UppyFile.ts +++ b/packages/@uppy/utils/src/UppyFile.ts @@ -42,13 +42,54 @@ export interface UppyFile { } } -// The user facing type for UppyFile used in uppy.addFile() and uppy.setOptions() +/* + * The user facing type for UppyFile used in uppy.addFile() and uppy.setOptions() + */ export type MinimalRequiredUppyFile = Required< - Pick, 'name' | 'data'> + Pick, 'name'> > & Partial< Omit, 'name' | 'data' | 'meta'> // We want to omit the 'meta' from UppyFile because of internal metadata // (see InternalMetadata in `UppyFile.ts`), as when adding a new file // that is not required. - > & { meta?: M } + > & { meta?: M; data: { size: number | null } } + +/* + * We are not entirely sure what a "tag file" is. + * It is used as an intermidiate type between `CompanionFile` and `UppyFile` + * in `@uppy/provider-views` and `@uppy/url`. + * TODO: remove this in favor of UppyFile + */ +export type TagFile = { + id?: string + source: string + name: string + type: string + isRemote: boolean + preview?: string + data: { + size: number | null + } + body?: { + url?: string + fileId?: string + } + meta?: { + authorName?: string + authorUrl?: string + relativePath?: string | null + absolutePath?: string + } & M + remote: { + companionUrl: string + url: string + body: { + fileId: string + url?: string + } + providerName?: string + provider?: string + requestClientId: string + } +} From a51f3a5c16a3853e2d82dcf058b015c434acce8c Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 10 Mar 2024 13:09:51 +0100 Subject: [PATCH 2/4] Apply suggestions from code review --- packages/@uppy/url/src/Url.tsx | 39 ++++++++++++---------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/packages/@uppy/url/src/Url.tsx b/packages/@uppy/url/src/Url.tsx index e3775947b8..3b0a9df9ce 100644 --- a/packages/@uppy/url/src/Url.tsx +++ b/packages/@uppy/url/src/Url.tsx @@ -51,14 +51,7 @@ function canHandleRootDrop(e: DragEvent) { } function checkIfCorrectURL(url?: string) { - if (!url) return false - - const protocol = url.match(/^([a-z0-9]+):\/\//)![1] - if (protocol !== 'http' && protocol !== 'https') { - return false - } - - return true + return url?.startsWith('http://') || url?.startsWith('https://') } function getFileNameFromUrl(url: string) { @@ -116,12 +109,6 @@ export default class Url extends UIPlugin< ) } - // Bind all event handlers for referencability - this.getMeta = this.getMeta.bind(this) - this.addFile = this.addFile.bind(this) - this.handleRootDrop = this.handleRootDrop.bind(this) - this.handleRootPaste = this.handleRootPaste.bind(this) - this.client = new RequestClient(uppy, { pluginId: this.id, provider: 'url', @@ -133,17 +120,19 @@ export default class Url extends UIPlugin< this.uppy.registerRequestClient(Url.requestClientId, this.client) } - async getMeta(url: string): Promise { - try { - return this.client.post('url/meta', { url }) - } catch (error) { - this.uppy.log('[URL] Error:') - this.uppy.log(error) - throw new Error('Failed to fetch the file') - } + private getMeta = (url: string): Promise => { + return this.client.post('url/meta', { url }).then((res) => { + // TODO: remove this handler in the next major + if ((res as any).errors) { + this.uppy.log('[URL] Error:') + this.uppy.log(error) + throw new Error('Failed to fetch the file') + } + return res + }) } - async addFile( + private addFile = async ( protocollessUrl: string, optionalMeta?: M, ): Promise { @@ -203,14 +192,14 @@ export default class Url extends UIPlugin< } } - handleRootDrop(e: DragEvent): void { + private handleRootDrop = (e: DragEvent) => { forEachDroppedOrPastedUrl(e.dataTransfer!, 'drop', (url) => { this.uppy.log(`[URL] Adding file from dropped url: ${url}`) this.addFile(url) }) } - handleRootPaste(e: ClipboardEvent): void { + private handleRootPaste = (e: ClipboardEvent) => { forEachDroppedOrPastedUrl(e.clipboardData!, 'paste', (url) => { this.uppy.log(`[URL] Adding file from pasted url: ${url}`) this.addFile(url) From 00530620fe94f81c5e88439f33c144be5c80aad4 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 10 Mar 2024 13:16:09 +0100 Subject: [PATCH 3/4] fixup! Apply suggestions from code review --- packages/@uppy/url/src/Url.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@uppy/url/src/Url.tsx b/packages/@uppy/url/src/Url.tsx index 3b0a9df9ce..b13b89d673 100644 --- a/packages/@uppy/url/src/Url.tsx +++ b/packages/@uppy/url/src/Url.tsx @@ -125,7 +125,7 @@ export default class Url extends UIPlugin< // TODO: remove this handler in the next major if ((res as any).errors) { this.uppy.log('[URL] Error:') - this.uppy.log(error) + this.uppy.log((res as any).errors) throw new Error('Failed to fetch the file') } return res @@ -135,7 +135,7 @@ export default class Url extends UIPlugin< private addFile = async ( protocollessUrl: string, optionalMeta?: M, - ): Promise { + ): Promise => { const url = addProtocolToURL(protocollessUrl) if (!checkIfCorrectURL(url)) { this.uppy.log(`[URL] Incorrect URL entered: ${url}`) From 2f8652b736aa18da201f325c1b11bf5b6dd423da Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 10 Mar 2024 13:19:14 +0100 Subject: [PATCH 4/4] Update packages/@uppy/url/src/Url.tsx --- packages/@uppy/url/src/Url.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@uppy/url/src/Url.tsx b/packages/@uppy/url/src/Url.tsx index b13b89d673..bfe15a4d85 100644 --- a/packages/@uppy/url/src/Url.tsx +++ b/packages/@uppy/url/src/Url.tsx @@ -123,9 +123,9 @@ export default class Url extends UIPlugin< private getMeta = (url: string): Promise => { return this.client.post('url/meta', { url }).then((res) => { // TODO: remove this handler in the next major - if ((res as any).errors) { + if ((res as any).error) { this.uppy.log('[URL] Error:') - this.uppy.log((res as any).errors) + this.uppy.log((res as any).error) throw new Error('Failed to fetch the file') } return res