Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provider views rewrite (.files, .folders => .partialTree) #5050

Draft
wants to merge 149 commits into
base: 4.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
149 commits
Select commit Hold shift + click to select a range
c4ba080
Merge branch 'main' of https://github.com/transloadit/uppy into main
lakesare Feb 14, 2024
631abc6
Merge branch 'main' of https://github.com/transloadit/uppy
lakesare Feb 16, 2024
75eae0a
Merge branch 'main' of https://github.com/transloadit/uppy into main
lakesare Feb 19, 2024
462e61f
Merge branch 'main' of https://github.com/transloadit/uppy
lakesare Feb 20, 2024
47df4a6
Merge branch 'main' of https://github.com/transloadit/uppy into main
lakesare Feb 20, 2024
df682a1
Merge branch 'main' of https://github.com/transloadit/uppy
lakesare Feb 27, 2024
ac3badf
Merge branch 'main' of https://github.com/transloadit/uppy into main
lakesare Mar 11, 2024
76615a1
Merge branch 'main' of https://github.com/transloadit/uppy into main
lakesare Mar 12, 2024
b234045
ProviderView.tsx - fix onedrive breadcrumbs
lakesare Mar 12, 2024
092a390
Merge branch 'lakesare/fix-breadcrumbs' into lakesare/provider-folders
lakesare Mar 12, 2024
10cbbf7
providers - correct ch-unch-indeterminate states
lakesare Mar 12, 2024
8796c35
providers - made .breadcrumbs derived from .partialTree
lakesare Mar 12, 2024
e2d0d04
everywhere - { files, folders, isChecked } => .partialTree
lakesare Mar 27, 2024
ab42ad6
GoogleDrive - made breadcrumbs work
lakesare Mar 27, 2024
1ba90c7
.getFolder() - remove the `name` argument
lakesare Mar 27, 2024
ec532a2
<Breadcrumbs/> - refactors "/"
lakesare Mar 27, 2024
51fc807
Instagram - made files get fetched onScroll
lakesare Mar 27, 2024
ba0b097
clearSelection() - recover the functionality
lakesare Mar 28, 2024
dc589c8
GoogleDrive - recover custom `.toggleCheckbox()` functionality
lakesare Mar 28, 2024
55ef784
providers - recover `.isDisabled` functionality
lakesare Mar 28, 2024
5f356a0
<SearchProviderView/> - made Unsplash use .partialTree
lakesare Mar 28, 2024
74b01c5
Facebook - change `.files, .folders` => `.partialTree`
lakesare Mar 29, 2024
101032c
everywhere - we don't need to ! `partialTreeFile.data` anymore
lakesare Mar 29, 2024
e12b26f
<ProviderView/> - implement folder caching
lakesare Mar 31, 2024
4bc143f
<View/> - enable shift-clicking
lakesare Mar 31, 2024
f96f99f
everywhere - get rid of unnecessary `.getNextFolder()`
lakesare Mar 31, 2024
296cae3
everywhere - fixing types
lakesare Mar 31, 2024
7123684
<ProviderView/> - rename `requestPath` to `folderId`
lakesare Mar 31, 2024
a5dc9e5
all providers - get rid of `.onFirstRender()`
lakesare Apr 1, 2024
60a9c1e
provider views - get rid of `.onFirstRender()`
lakesare Apr 2, 2024
205bc45
<ProviderView/> - make the root folder cacheable too
lakesare Apr 2, 2024
3cc111e
TEMP - setup for working with FOLDERS + LAZY_LOADING
lakesare Apr 2, 2024
ab58d89
<ProviderView/> - get rid of `.#listFilesAndFolders`
lakesare Apr 3, 2024
e9d5ee3
<ProviderView/> - make `this.nextPagePath` per-folder
lakesare Apr 3, 2024
750a422
everywhere - more refined types
lakesare Apr 3, 2024
5d6e92c
types - reintroduce `StatusInPartialTree`
lakesare Apr 4, 2024
f0b7f81
<SearchProviderView/> - made Unsplash work with the new structure
lakesare Apr 4, 2024
992a913
<ProviderView/> - preemptive cleaning of `.absDirPath` and `.relDirPath`
lakesare Apr 5, 2024
e2ab113
<ProviderView/> - give `.nextPagePath` a rigorous type
lakesare Apr 5, 2024
21b0677
<ProviderView/> - make `.nextPagePath` & `.cached` a composite key
lakesare Apr 5, 2024
266fb1f
<ListItem/> - remove unnecessary indirection level
lakesare Apr 8, 2024
9feeb86
css - factor out `.statusClassName`
lakesare Apr 8, 2024
14b93b5
everywhere - refactor `.validateRestrictions()`
lakesare Apr 8, 2024
f021b51
nOfSelectedFiles - make "Selected (n)" as smart as possible
lakesare Apr 8, 2024
196be22
<ProviderViews/> - prevent shift-clicking from highlighting file names
lakesare Apr 9, 2024
4c1bef7
`.validateRestrictions()` - make it accept a `CompanionFile` instead …
lakesare Apr 9, 2024
fe1ac0d
`.getFolder()` - simplify code
lakesare Apr 10, 2024
fbbaa13
everywhere - account for `restrictions` in `.partialTree`
lakesare Apr 10, 2024
095c900
`PartialTreeUtils.ts` - factor out `getPartialTreeAfterTogglingCheckb…
lakesare Apr 10, 2024
9759e76
`PartialTreeUtils.ts` - factor out `clickOnFolder()`
lakesare Apr 10, 2024
56e5284
`PartialTreeUtils.ts` - factor out `getPartialTreeAfterScroll()`
lakesare Apr 10, 2024
3408c5f
`PartialTreeUtils.ts` - rename methods
lakesare Apr 10, 2024
5200d3d
`.donePicking()` - implement using recursion
lakesare Apr 11, 2024
d183ce4
`.donePicking()` - integrate with `<ProviderView/>`
lakesare Apr 11, 2024
0cdad8b
`donePicking()` - show notifications after addition
lakesare Apr 12, 2024
216e05a
`#list()` - get rid of unnecessary indirection
lakesare Apr 12, 2024
4c8c336
ProviderView.tsx - add `signal` everywhere, reduce try/catch indents …
lakesare Apr 15, 2024
c35cd4c
`handleError()` - make error handling uniform
lakesare Apr 16, 2024
fd69102
`state.isSearchVisible` - remove, it's just not used anywhere
lakesare Apr 16, 2024
1bef2b4
state - reuse default state
lakesare Apr 16, 2024
dc339f4
state - reset state on close panel (like we discussed in the uppy call)
lakesare Apr 16, 2024
37e9f33
methods - remove unnecessary indirection in state setting
lakesare Apr 16, 2024
2c869d6
`<CloseWrapper/>` - remove CloseWrappers, this is unnecessary indirec…
lakesare Apr 16, 2024
9550ec2
`this.requestClientId` - remove, again - this was unnecessary indirec…
lakesare Apr 16, 2024
c8f8066
`getTagFile()` - factor out into a separate file
lakesare Apr 16, 2024
503242b
`recordShiftKeyPress()` - fix chaotic shift-clicking in Grid provider…
lakesare Apr 17, 2024
88c393b
`getNOfSelectedFiles.ts`, `filterItems.ts` - factor out, this removes…
lakesare Apr 17, 2024
8eff1df
<Browser/> - pass `displayedPartialTree` right away (because Search&N…
lakesare Apr 18, 2024
c09105a
`searchTerm`, `filterInput` - we only need one of these of course!
lakesare Apr 18, 2024
1302640
<SearchProvider/> - fix the issue where `afterToggleCheckbox()` think…
lakesare Apr 18, 2024
72eee03
<SearchProvider/> - remove `this.nextPageQuery`
lakesare Apr 18, 2024
4dba9ab
<Browser/> - remove unnecessary prop indirection
lakesare Apr 18, 2024
8829a12
<SearchFilterInput/> - make the form controlled, hugely simplifies ev…
lakesare Apr 19, 2024
9b29db1
`filterItems.ts` - move to <ProviderView/>, because it's only used there
lakesare Apr 19, 2024
d493b32
/utils/PartialTreeUtils.ts - put every util in a separate file
lakesare Apr 19, 2024
d1f764c
`shouldHandleScroll.ts` - factor out into a util
lakesare Apr 19, 2024
51584c1
this.state - make sure state is reset 1. on cancel 2. on close
lakesare Apr 22, 2024
decc4cb
`this.xxx` - never leave `this.xxx` variables undefined
lakesare Apr 22, 2024
6db223e
`this.username` - should be in `this.state`
lakesare Apr 22, 2024
03609f2
`SearchProviderPluginState` type - simplify this type, never leave st…
lakesare Apr 22, 2024
af66381
<Header/> - remove completely unnecessary indirection, remove unused …
lakesare Apr 22, 2024
03e4cd8
Facebook.tsx - more sane `viewOptions` code
lakesare Apr 22, 2024
2cdbc29
providers - properly type `opts`
lakesare Apr 22, 2024
c882dca
`this.isShiftKeyPressed` - move this variable into <Browser/>
lakesare Apr 23, 2024
dad1c81
`this.handleError()` - move to /utils
lakesare Apr 23, 2024
13500cf
`this.isHandlingScroll` - move to child classes
lakesare Apr 23, 2024
28df97d
`this.registerRequestClient()` - move to child classes
lakesare Apr 23, 2024
fb4fc8f
`this.lastCheckbox` - move to child classes
lakesare Apr 23, 2024
b8abc73
`this.setLoading()` - move to child classes
lakesare Apr 23, 2024
ddadff9
`this.validateRestrictions()` - move to utils
lakesare Apr 23, 2024
e29a662
types - fully simplify provider types, remove `View.ts` parent class
lakesare Apr 23, 2024
1f9b2d2
index.d.ts - we're not using `OnFirstRenderer` anymore
lakesare Apr 23, 2024
7e2ae6e
<ProviderView/>, <SearchProviderView/> - more precise typing for options
lakesare Apr 24, 2024
a195157
package.json - remove nanoid
lakesare Apr 24, 2024
9379034
GoogleDrive - make shift-clicking work
lakesare Apr 25, 2024
9f00d46
everywhere - fix types across uppy
lakesare Apr 25, 2024
875ac0f
`afterToggleCheckbox.ts` - less redundant args, pass `ourItem.id` ins…
lakesare Apr 25, 2024
2e569a1
tests - create `afterToggleCheckbox()` tests
lakesare Apr 25, 2024
1e070ce
`getClickedRange.ts` - decouple `getClickedRange()` from `afterToggle…
lakesare Apr 25, 2024
f86dbeb
tests - wrote tests for `afterToggleCheckbox.ts`
lakesare Apr 26, 2024
9db9b92
tests - wrote tests for `afterClickOnFolder.ts`
lakesare Apr 26, 2024
11c7a30
everywhere - finally rename `getFolder` => `openFolder`
lakesare Apr 26, 2024
3950933
tests - wrote tests for `afterScrollFolder.ts`
lakesare Apr 26, 2024
f6476e0
getPaths.ts - make `absDirPath`, `relDirPath` work like in docs & add…
lakesare Apr 29, 2024
18ca4bb
injectPaths.ts - improve performance
lakesare Apr 29, 2024
8b5f033
getTagFile.ts - handle path injection all in one place
lakesare Apr 29, 2024
3663638
getTagFile.ts - refactor
lakesare Apr 29, 2024
c9ca3b0
fill.ts - `provider.list(currentPath, { signal })` => `apiList`
lakesare Apr 30, 2024
6b74df0
tests - wrote tests for `fill.ts`
lakesare Apr 30, 2024
834199e
tests - wrote tests for `getNOfSelectedFiles.ts`
lakesare Apr 30, 2024
6dfbcd2
everywhere - change `JSON.stringify()` => `clone()`
lakesare May 1, 2024
8e328fc
`PartialTreeUtils.ts` - more consistent function naming + alphabetica…
lakesare May 1, 2024
f505d5e
`donePicking()` - superseded a notification to i18n one
lakesare May 1, 2024
925cdf9
GoogleDrive - make the shared drive checkable
lakesare May 2, 2024
ceb52ca
`Item.tsx` - standardize names; remove unnecessary question marks fro…
lakesare May 2, 2024
af35dbb
ProviderView.tsx - clicking "Cancel" should make all files "unchecked"
lakesare May 2, 2024
524e189
everywhere - move `document.getSelection()?.removeAllRanges()` to <Br…
lakesare May 7, 2024
7d5eee3
everywhere - standardize names and types of passed props
lakesare May 8, 2024
041b743
<Browser/> - only leave "list of files" to the browser
lakesare May 8, 2024
cc4e77f
TEMP - easier pageSize for alex to play with
lakesare May 8, 2024
80b16c4
everywhere - only handle individual-file restrictions
lakesare May 16, 2024
49c75a6
everywhere - add aggregate restrictions on top
lakesare May 17, 2024
21067a5
SearchProvider, NormalProvider - unite the way we addFiles()
lakesare May 17, 2024
6ef9ede
`getTagFile.ts` - pass fewer arguments
lakesare May 17, 2024
b814da3
`addFiles.ts` - move conversion to tagFiles into `addFiles()`
lakesare May 17, 2024
9a506f5
`uppy.validateRestrictions()` - remove legacy method
lakesare May 20, 2024
1492e33
`uppy.validateAggregateRestrictions()` - make aggregate restricter re…
lakesare May 20, 2024
f58d6e5
<FooterActions/> css - make aggregate errors look nice
lakesare May 20, 2024
eb1951b
`PartialTreeUtils/index.test.ts` - accommodate tests to the latest ch…
lakesare May 20, 2024
5dad68d
tests - make all uppy tests work
lakesare May 20, 2024
649c062
Merge branch '4.x' into lakesare/provider-folders
lakesare May 31, 2024
090376a
prettiness - run `yarn format`
lakesare May 31, 2024
1579bba
prettiness - run `yarn lint:fix`
lakesare May 31, 2024
fd8afda
package.json - add `vitest` as a dev dependency
lakesare May 31, 2024
f62f40c
eslint - fixing 1
lakesare May 31, 2024
14f1a11
<SearchFilterInput/> - add default props as per eslint
lakesare Jun 3, 2024
1bc924b
<SearchFilterInput/> - rename to <SearchInput/>
lakesare Jun 3, 2024
24b4c7f
eslint - fixing 4 (clone.ts)
lakesare Jun 3, 2024
d5c7820
Uppy.ts - rewrite `partialTree` docs
lakesare Jun 3, 2024
2df3828
eslint - fixing 5
lakesare Jun 4, 2024
1b97006
eslint - fixing 6
lakesare Jun 4, 2024
8238989
`getBreadcrumbs.ts` - factor out
lakesare Jun 4, 2024
a583c8c
tests - fixing 7
lakesare Jun 4, 2024
9d40ec2
everywhere - remove `.toReversed()`, because it's not yet supported i…
lakesare Jun 4, 2024
cce8ed2
dev/Dashboard.js - restore to pristine version
lakesare Jun 4, 2024
d26ff40
prettiness - run `yarn format`
lakesare Jun 4, 2024
e72c709
merge
lakesare Jun 4, 2024
ad8f966
fixing 8 (`yarn run build:ts`)
lakesare Jun 4, 2024
1163198
fixing 9 (run `corepack yarn`)
lakesare Jun 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/@uppy/angular/projects/uppy/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/common": "ˆ17.0.0 || ^18.0.0",
"@angular/common": "*",
"@angular/core": "^17.0.0 || ^18.0.0",
"@uppy/core": "workspace:^",
"@uppy/dashboard": "workspace:^",
Expand Down
2 changes: 1 addition & 1 deletion packages/@uppy/companion-client/src/Provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ export default class Provider<M extends Meta, B extends Body>
}

list<ResBody>(
directory: string | undefined,
directory: string | null,
options: RequestOptions,
): Promise<ResBody> {
return this.get<ResBody>(`${this.id}/list/${directory || ''}`, options)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class Drive extends Provider {
q,
// We can only do a page size of 1000 because we do not request permissions in DRIVE_FILES_FIELDS.
// Otherwise we are limited to 100. Instead we get the user info from `this.user()`
pageSize: 1000,
pageSize: 10,
orderBy: 'folder,name',
includeItemsFromAllDrives: true,
supportsAllDrives: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Instagram extends Provider {

async list ({ directory, token, query = { cursor: null } }) {
return this.#withErrorHandling('provider.instagram.list.error', async () => {
const qs = { fields: 'id,media_type,thumbnail_url,media_url,timestamp,children{media_type,media_url,thumbnail_url,timestamp}' }
const qs = { fields: 'id,media_type,thumbnail_url,media_url,timestamp,children{media_type,media_url,thumbnail_url,timestamp}', limit: 5 }

if (query.cursor) qs.after = query.cursor

Expand Down
26 changes: 9 additions & 17 deletions packages/@uppy/core/src/Restricter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,25 +98,17 @@ class Restricter<M extends Meta, B extends Body> {
}

if (maxTotalFileSize) {
let totalFilesSize = existingFiles.reduce(
(total, f) => (total + (f.size ?? 0)) as number,
const totalFilesSize = [...existingFiles, ...addingFiles].reduce(
(total, f) => total + (f.size ?? 0),
0,
)

for (const addingFile of addingFiles) {
if (addingFile.size != null) {
// We can't check maxTotalFileSize if the size is unknown.
totalFilesSize += addingFile.size

if (totalFilesSize > maxTotalFileSize) {
throw new RestrictionError(
this.getI18n()('exceedsSize', {
size: prettierBytes(maxTotalFileSize),
file: addingFile.name,
}),
)
}
}
if (totalFilesSize > maxTotalFileSize) {
throw new RestrictionError(
this.getI18n()('aggregateExceedsSize', {
sizeAllowed: prettierBytes(maxTotalFileSize),
size: prettierBytes(totalFilesSize),
}),
)
}
}
}
Expand Down
20 changes: 9 additions & 11 deletions packages/@uppy/core/src/Uppy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2157,7 +2157,7 @@ describe('src/Core', () => {
it('should enforce the maxTotalFileSize rule', () => {
const core = new Core({
restrictions: {
maxTotalFileSize: 34000,
maxTotalFileSize: 20000,
},
})

Expand All @@ -2176,11 +2176,13 @@ describe('src/Core', () => {
data: testImage,
})
}).toThrowError(
new Error('foo1.jpg exceeds maximum allowed size of 33 KB'),
new Error(
'You selected 34 KB of files, but maximum allowed size is 20 KB',
),
)
})

it('should check if a file validateRestrictions', () => {
it('should report error on validateSingleFile', () => {
const core = new Core({
restrictions: {
minFileSize: 300000,
Expand All @@ -2205,17 +2207,13 @@ describe('src/Core', () => {
size: 270733,
}

// @ts-ignore
const validateRestrictions1 = core.validateRestrictions(newFile)
// @ts-ignore
const validateRestrictions2 = core2.validateRestrictions(newFile)
const validateRestrictions1 = core.validateSingleFile(newFile)
const validateRestrictions2 = core2.validateSingleFile(newFile)

expect(validateRestrictions1!.message).toEqual(
expect(validateRestrictions1).toEqual(
'This file is smaller than the allowed size of 293 KB',
)
expect(validateRestrictions2!.message).toEqual(
'You can only upload: image/png',
)
expect(validateRestrictions2).toEqual('You can only upload: image/png')
})

it('should emit `restriction-failed` event when some rule is violated', () => {
Expand Down
123 changes: 96 additions & 27 deletions packages/@uppy/core/src/Uppy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,86 @@ export type UnknownPlugin<
PluginState extends Record<string, unknown> = Record<string, unknown>,
> = BasePlugin<any, M, B, PluginState>

// `OmitFirstArg<typeof someArray>` is the type of the returned value of `someArray.slice(1)`.
type OmitFirstArg<T> = T extends [any, ...infer U] ? U : never
/**
* ids are always `string`s, except the root folder's id can be `null`
*/
export type PartialTreeId = string | null

export type PartialTreeStatusFile = 'checked' | 'unchecked'
export type PartialTreeStatus = PartialTreeStatusFile | 'partial'

export type PartialTreeFile = {
type: 'file'
id: string

/**
* There exist two types of restrictions:
* - individual restrictions (`allowedFileTypes`, `minFileSize`, `maxFileSize`), and
* - aggregate restrictions (`maxNumberOfFiles`, `maxTotalFileSize`).
*
* `.restrictionError` reports whether this file passes individual restrictions.
*
*/
restrictionError: string | null

status: PartialTreeStatusFile
parentId: PartialTreeId
data: CompanionFile
}

export type PartialTreeFolderNode = {
type: 'folder'
id: string

/**
* Consider `(.nextPagePath, .cached)` a composite key that can represent 4 states:
* - `{ cached: true, nextPagePath: null }` - we fetched all pages in this folder
* - `{ cached: true, nextPagePath: 'smth' }` - we fetched 1st page, and there are still pages left to fetch in this folder
* - `{ cached: false, nextPagePath: null }` - we didn't fetch the 1st page in this folder
* - `{ cached: false, nextPagePath: 'someString' }` - ❌ CAN'T HAPPEN ❌
*/
cached: boolean
nextPagePath: PartialTreeId

status: PartialTreeStatus
parentId: PartialTreeId
data: CompanionFile
}

export type PartialTreeFolderRoot = {
type: 'root'
id: PartialTreeId

cached: boolean
nextPagePath: PartialTreeId
}

export type PartialTreeFolder = PartialTreeFolderNode | PartialTreeFolderRoot

/**
* PartialTree has the following structure.
*
* FolderRoot
* ┌─────┴─────┐
* FolderNode File
* ┌─────┴────┐
* File File
*
* Root folder is called `PartialTreeFolderRoot`,
* all other folders are called `PartialTreeFolderNode`, because they are "internal nodes".
*
* It's possible for `PartialTreeFolderNode` to be a leaf node if it doesn't contain any files.
*/
export type PartialTree = (PartialTreeFile | PartialTreeFolder)[]

export type UnknownProviderPluginState = {
authenticated: boolean | undefined
breadcrumbs: {
requestPath?: string
name?: string
id?: string
}[]
didFirstRender: boolean
currentSelection: CompanionFile[]
filterInput: string
searchString: string
loading: boolean | string
folders: CompanionFile[]
files: CompanionFile[]
isSearchVisible: boolean
partialTree: PartialTree
currentFolderId: PartialTreeId
username: string | null
}
/*
* UnknownProviderPlugin can be any Companion plugin (such as Google Drive).
Expand All @@ -92,8 +155,8 @@ export type UnknownProviderPlugin<
M extends Meta,
B extends Body,
> = UnknownPlugin<M, B, UnknownProviderPluginState> & {
rootFolderId: string | null
title: string
rootFolderId: string | null
files: UppyFile<M, B>[]
icon: () => h.JSX.Element
provider: CompanionClientProvider
Expand All @@ -114,16 +177,10 @@ export type UnknownProviderPlugin<
* `SearchProvider` does operate on Companion plugins with `uppy.getPlugin()`.
*/
export type UnknownSearchProviderPluginState = {
isInputMode?: boolean
searchTerm?: string | null
isInputMode: boolean
} & Pick<
UnknownProviderPluginState,
| 'loading'
| 'files'
| 'folders'
| 'currentSelection'
| 'filterInput'
| 'didFirstRender'
'loading' | 'searchString' | 'partialTree' | 'currentFolderId'
>
export type UnknownSearchProviderPlugin<
M extends Meta,
Expand Down Expand Up @@ -300,6 +357,9 @@ export interface UppyEventMap<M extends Meta, B extends Body>
'upload-start': (files: UppyFile<M, B>[]) => void
}

/** `OmitFirstArg<typeof someArray>` is the type of the returned value of `someArray.slice(1)`. */
type OmitFirstArg<T> = T extends [any, ...infer U] ? U : never

const defaultUploadState = {
totalProgress: 0,
allowNewUpload: true,
Expand Down Expand Up @@ -799,14 +859,23 @@ export class Uppy<M extends Meta, B extends Body> {
}
}

validateRestrictions(
file: ValidateableFile<M, B>,
files: ValidateableFile<M, B>[] = this.getFiles(),
): RestrictionError<M, B> | null {
validateSingleFile(file: ValidateableFile<M, B>): string | null {
try {
this.#restricter.validateSingleFile(file)
} catch (err) {
return err.message
}
return null
}

validateAggregateRestrictions(
files: ValidateableFile<M, B>[],
): string | null {
const existingFiles = this.getFiles()
try {
this.#restricter.validate(files, [file])
this.#restricter.validateAggregateRestrictions(existingFiles, files)
} catch (err) {
return err as any
return err.message
}
return null
}
Expand Down
6 changes: 5 additions & 1 deletion packages/@uppy/core/src/_common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
background-color: $blue;
border-radius: 4px;

&:hover {
&:not(:disabled):hover {
background-color: darken($blue, 10%);
}

Expand All @@ -145,6 +145,10 @@

@include blue-border-focus--dark;
}

&.uppy-c-btn--disabled {
background-color: rgb(142, 178, 219);
}
}

.uppy-c-btn-link {
Expand Down
2 changes: 2 additions & 0 deletions packages/@uppy/core/src/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export default {
0: 'You have to select at least %{smart_count} file',
1: 'You have to select at least %{smart_count} files',
},
aggregateExceedsSize:
'You selected %{size} of files, but maximum allowed size is %{sizeAllowed}',
exceedsSize: '%{file} exceeds maximum allowed size of %{size}',
missingRequiredMetaField: 'Missing required meta fields',
missingRequiredMetaFieldOnFile:
Expand Down
23 changes: 10 additions & 13 deletions packages/@uppy/facebook/src/Facebook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,16 @@ export default class Facebook<M extends Meta, B extends Body> extends UIPlugin<
}

render(state: unknown): ComponentChild {
const viewOptions: {
viewType?: string
showFilter?: boolean
showTitles?: boolean
} = {}
if (
this.getPluginState().files.length &&
!this.getPluginState().folders.length
) {
viewOptions.viewType = 'grid'
viewOptions.showFilter = false
viewOptions.showTitles = false
const { partialTree } = this.getPluginState()
const folders = partialTree.filter((i) => i.type === 'folder')

if (folders.length === 0) {
return this.view.render(state, {
viewType: 'grid',
showFilter: false,
showTitles: false,
})
}
return this.view.render(state, viewOptions)
return this.view.render(state)
}
}
18 changes: 0 additions & 18 deletions packages/@uppy/google-drive/src/DriveProviderViews.ts

This file was deleted.

8 changes: 4 additions & 4 deletions packages/@uppy/google-drive/src/GoogleDrive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import { ProviderViews } from '@uppy/provider-views'
import { h, type ComponentChild } from 'preact'

import type { UppyFile, Body, Meta } from '@uppy/utils/lib/UppyFile'
import type { UnknownProviderPluginState } from '@uppy/core/lib/Uppy'
import DriveProviderViews from './DriveProviderViews.ts'
import type { UnknownProviderPluginState } from '@uppy/core/lib/Uppy.ts'
import locale from './locale.ts'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore We don't want TS to generate types for the package.json
Expand Down Expand Up @@ -78,6 +77,7 @@ export default class GoogleDrive<
</g>
</svg>
)
this.rootFolderId = 'root'

this.opts.companionAllowedHosts = getAllowedHosts(
this.opts.companionAllowedHosts,
Expand All @@ -102,9 +102,9 @@ export default class GoogleDrive<
}

install(): void {
this.view = new DriveProviderViews(this, {
this.view = new ProviderViews(this, {
provider: this.provider,
loadAllFiles: true,
loadAllFiles: false,
})

const { target } = this.opts
Expand Down