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

Merged
merged 187 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 177 commits
Commits
Show all changes
187 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
e447cb7
prettier - undo indentation harm done by prettier
lakesare Jun 4, 2024
0b6571b
`getBreadcrumbs()` - add tests, and rewrite to avoid using `.toRevers…
lakesare Jun 5, 2024
947bba3
merge
lakesare Jun 5, 2024
07ed69b
`<SearchInput/>` - make it work for eslint
lakesare Jun 5, 2024
bf0ed8d
everywhere - remove `eslint-disable react/require-default-props`
lakesare Jun 5, 2024
d358c9a
<GridItem/>, <ListItem/> - refactor to avoid prop drilling
lakesare Jun 6, 2024
294a301
<ListItem/> - disable checkboxes for GoogleDrive team drives
lakesare Jun 6, 2024
a65dae3
merge (fixing up some lines from the previous merge)
lakesare Jun 6, 2024
258c379
merge (fixing up some lines from the previous merge)
lakesare Jun 6, 2024
b54d12e
everywhere - remove TEMP development values
lakesare Jun 6, 2024
464f614
`this.validateSingleFile()` - switch to `.restrictionError`
lakesare Jun 7, 2024
c94b893
`afterToggleCheckbox.ts` - refactor, add comments
lakesare Jun 7, 2024
ab6a13c
`afterToggleCheckbox.ts` - refactor to use ids instead of whole objects
lakesare Jun 7, 2024
55af6d8
`afterToggleCheckbox.ts` - try to satisfy prettier
lakesare Jun 7, 2024
657ef98
fixing 10 (try to satisfy `npx webpack`)
lakesare Jun 12, 2024
4081f06
fixing 11 (try to satisfy `npx webpack`)
lakesare Jun 12, 2024
452800b
Antoine: use Math.min & Math.max in `getClickedRange()`
lakesare Jun 13, 2024
3651e0c
fixing 12 (run `yarn run format`)
lakesare Jun 13, 2024
419e2e2
`clone.ts` - rename to `shallowClone.ts`
lakesare Jun 13, 2024
dae378c
Antoine: in `package.json`, move `devDependencies` up
lakesare Jun 13, 2024
1181a46
Antoine: rename `getNOfSelectedFiles()` to `getNumberOfSelectedFiles()`
lakesare Jun 13, 2024
495c92a
`getNumberOfSelectedFiles()` - better comments
lakesare Jun 13, 2024
b7e901f
Antoine: remove `<form/>` tag
lakesare Jun 13, 2024
7dccd0e
Antoine: change `{}` to `Object.create(null)`, write tests
lakesare Jun 13, 2024
dea7e51
Antoine: `<SearchInput/>` - return dynamic <form/> element
lakesare Jun 14, 2024
563435a
`<SearchInput/>` - return `buttonCSSClassName`
lakesare Jun 14, 2024
c68e440
merge
lakesare Jun 17, 2024
6d4ce89
`GoogleDrive.tsx` - make team drive checkboxes visible
lakesare Jun 17, 2024
545e443
merge (quite manual/with non-automatic updates)
lakesare Jun 18, 2024
f2de550
merge (more)
lakesare Jun 18, 2024
21986c5
Mifi: update packages/@uppy/provider-views/src/ProviderView/ProviderV…
lakesare Jun 19, 2024
034a603
Merge branch '4.x' into lakesare/provider-folders
lakesare Jun 19, 2024
afbc548
merge (more changes)
lakesare Jun 19, 2024
126401c
Merge branch 'lakesare/provider-folders' of https://github.com/transl…
lakesare Jun 19, 2024
bb0b2b8
`Facebook.tsx`, `GooglePhotos.tsx` - render in 'grid' style on per-fo…
lakesare Jun 20, 2024
fc7c777
`<GridItem/>` - use the `.thumbnail` whenever possible (improves imag…
lakesare Jun 20, 2024
8655bf5
`prettier` - ensure `PartialTree` is always strongly indented in tests
lakesare Jun 20, 2024
c073e5d
merge
lakesare Jun 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
14 changes: 5 additions & 9 deletions packages/@uppy/core/src/Uppy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2160,7 +2160,7 @@ describe('src/Core', () => {
)
})

it('should check if a file validateRestrictions', () => {
it('should report error on validateSingleFile', () => {
const core = new Core({
restrictions: {
minFileSize: 300000,
Expand All @@ -2185,17 +2185,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 @@ -58,23 +58,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 = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe id, parentId and data can be pulled out into a common type, e.g. PartialTreeBase and then PartialTreeFile and PartialTreeFolderNode can extend from it? to reduce duplication and make it more clear which fields they have in common

Copy link
Collaborator Author

@lakesare lakesare Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having PartialTreeBase would add a level of indirection without making these types more readable/easier to work with.

In general - I avoided having many types here, because I want people who work on these files to largely remember existing types by heart (that's just 4 types - PartialTree, ~File, ~FolderNode, ~FolderRoot).

E.g., one really seductive type was PartialTreeDisplayedNode = ~File | ~FolderNode (because these are the only nodes that can be seen in the interface, meaning most functions expect ~File | ~FolderNode as an argument), but I decided against it to cut down on the number of types the developer would have to memorize.

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 @@ -89,8 +152,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 @@ -111,16 +174,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 @@ -296,6 +353,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 @@ -780,14 +840,23 @@ export class Uppy<M extends Meta, B extends Body = Record<string, never>> {
}
}

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
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)
}
}
20 changes: 12 additions & 8 deletions packages/@uppy/google-drive/src/DriveProviderViews.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import type {
PartialTreeFile,
PartialTreeFolderNode,
} from '@uppy/core/lib/Uppy'
import { ProviderViews } from '@uppy/provider-views'
import type { CompanionFile } from '@uppy/utils/lib/CompanionFile'
import type { Body, Meta } from '@uppy/utils/lib/UppyFile'

export default class DriveProviderViews<
M extends Meta,
B extends Body,
> extends ProviderViews<M, B> {
toggleCheckbox(e: Event, file: CompanionFile): void {
e.stopPropagation()
e.preventDefault()

// Shared Drives aren't selectable; for all else, defer to the base ProviderView.
if (!file.custom!.isSharedDrive) {
super.toggleCheckbox(e, file)
toggleCheckbox(
item: PartialTreeFolderNode | PartialTreeFile,
isShiftKeyPressed: boolean,
): void {
// We don't allow to check team drives; but we leave the checkboxes visible to show the 'partial' state
// (For a full explanation, see https://github.com/transloadit/uppy/issues/5232)
if (!item.data.custom?.isSharedDrive) {
super.toggleCheckbox(item, isShiftKeyPressed)
}
}
}
3 changes: 3 additions & 0 deletions packages/@uppy/provider-views/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
"p-queue": "^8.0.0",
"preact": "^10.5.13"
},
"devDependencies": {
"vitest": "^1.6.0"
},
"peerDependencies": {
"@uppy/core": "workspace:^"
},
Expand Down
52 changes: 17 additions & 35 deletions packages/@uppy/provider-views/src/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,35 @@
import type { UnknownProviderPluginState } from '@uppy/core/lib/Uppy'
import type { PartialTreeFolder } from '@uppy/core/lib/Uppy'
import { h, Fragment } from 'preact'
import type { Body, Meta } from '@uppy/utils/lib/UppyFile'
import type ProviderView from './ProviderView/index.js'

type BreadcrumbProps = {
getFolder: () => void
title: string
isLast: boolean
}

const Breadcrumb = (props: BreadcrumbProps) => {
const { getFolder, title, isLast } = props

return (
<Fragment>
<button
type="button"
className="uppy-u-reset uppy-c-btn"
onClick={getFolder}
>
{title}
</button>
{!isLast ? ' / ' : ''}
</Fragment>
)
}

type BreadcrumbsProps<M extends Meta, B extends Body> = {
getFolder: ProviderView<M, B>['getFolder']
openFolder: ProviderView<M, B>['openFolder']
title: string
breadcrumbsIcon: h.JSX.Element
breadcrumbs: UnknownProviderPluginState['breadcrumbs']
breadcrumbs: PartialTreeFolder[]
}

export default function Breadcrumbs<M extends Meta, B extends Body>(
props: BreadcrumbsProps<M, B>,
) {
const { getFolder, title, breadcrumbsIcon, breadcrumbs } = props
): h.JSX.Element {
const { openFolder, title, breadcrumbsIcon, breadcrumbs } = props

return (
<div className="uppy-Provider-breadcrumbs">
<div className="uppy-Provider-breadcrumbsIcon">{breadcrumbsIcon}</div>
{breadcrumbs.map((directory, i) => (
<Breadcrumb
key={directory.id}
getFolder={() => getFolder(directory.requestPath, directory.name)}
title={i === 0 ? title : (directory.name as string)}
isLast={i + 1 === breadcrumbs.length}
/>
{breadcrumbs.map((folder, index) => (
<Fragment>
<button
key={folder.id}
type="button"
className="uppy-u-reset uppy-c-btn"
onClick={() => openFolder(folder.id)}
>
{folder.type === 'root' ? title : folder.data.name}
</button>
{breadcrumbs.length === index + 1 ? '' : ' / '}
</Fragment>
))}
</div>
)
Expand Down
Loading