uppy/packages/@uppy/utils/src/CompanionClientProvider.ts
Prakash 5ba2c1c8d3
Server side search @uppy/Companion (#6003)
## High Level View

<img width="3367" height="1576" alt="Global Search (1)"
src="https://github.com/user-attachments/assets/134e8658-5cbd-4816-87a1-3bd42603089d"
/>


- Search View replicated , through minimal components `<GlobalSearchView
/>` and `<SearchResultItem />`
- Both components take only the minimal state needed to render the
search view no dependency on PartialTree. search response from companion
server is directly passed to GlobalSearchView for file state.
- `#buildPath` creates missing parent nodes in partialTree (if any) and
opens the folder in the normal way using a minimal wrapper over
openFolder function.
- Both interactions : "checking a file/folder" and "opening a folder"
use the same function `#buildPath` to build the path, then use the
already existing `openFolder` and `toggleCheckBox`.
- Max search results: 1000. Pagination removed for simplicity (can be
added later).
- From a UI/UX standpoint, all functionality works as expected.
- The only limitation is occasional inconsistent partial checked states
when the tree isn’t fully built — unavoidable since percolateUp and
percolateDown require the complete partialTree to sync state correctly.
This issue isn’t critical; even in other cases, we already mark folders
"checked" whereas they may be empty if not yet fetched.
- I figured out it's better to just derive the checkedState from
PartialTree , and then pass it to `GlobalSearchView` rather than keep it
separate and then worrying about checked state syncs across two views
for UI to look right.
- IMO this is the most simplest approach I could come up with. without
sacrificing any user functionality and it carefully reuses all the util
code.

---------

Co-authored-by: Merlijn Vos <merlijn@soverin.net>
Co-authored-by: Mikael Finstad <finstaden@gmail.com>
2025-10-08 21:18:17 +02:00

56 lines
1.6 KiB
TypeScript

import type { CompanionFile } from './CompanionFile.js'
export type RequestOptions = {
method?: string
data?: Record<string, unknown>
skipPostResponse?: boolean
signal?: AbortSignal
authFormData?: unknown
qs?: Record<string, string>
}
/**
* CompanionClientProvider is subset of the types of the `Provider`
* class from @uppy/companion-client.
*
* This is needed as the `Provider` class is passed around in Uppy and we
* need to have shared types for it. Although we are duplicating some types,
* this is still safe as `Provider implements CompanionClientProvider`
* so any changes here will error there and vice versa.
*
* TODO: remove this once companion-client and provider-views are merged into a single plugin.
*/
export interface CompanionClientProvider {
name: string
provider: string
login(options?: RequestOptions): Promise<void>
logout<ResBody>(options?: RequestOptions): Promise<ResBody>
fetchPreAuthToken(): Promise<void>
fileUrl: (a: string) => string
list(
directory: string | null,
options: RequestOptions,
): Promise<{
username: string
nextPagePath: string | null
items: CompanionFile[]
}>
// Optional: not every provider implements server-side search.
search?: (
text: string,
options?: RequestOptions & {
path?: string | null | undefined
cursor?: string | undefined
},
) => Promise<{
username: string
nextPagePath: string | null
items: CompanionFile[]
}>
}
export interface CompanionClientSearchProvider {
name: string
provider: string
fileUrl: (a: string) => string
search<ResBody>(text: string, queries?: string): Promise<ResBody>
}