Files
supabase/apps/studio/components/interfaces/Storage/BucketFilePickerDialog/BucketFilePickerState.tsx
Ivan Vasilov dc3c8684cc chore(deps): upgrade valtio to v2 (#48031)
Audited all proxy()/useSnapshot() usage against the v1→v2 migration
guide; no breaking changes apply (no reused proxy() inputs, no
promise-valued state, all consumers already client components).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Updated the Valtio dependency to a newer version for improved
compatibility.

* **Bug Fixes**
* Improved AI assistant persistence in IndexedDB so chat sessions
reliably save (while keeping only the most recent 20 messages per chat).
* Hardened tabs restoration from storage to fall back to fresh defaults
when data is missing, invalid, or fails validation.

* **Refactor**
* Switched multiple studio panels to use fresh initial-state factories
for initialization and reset reliability.
* Updated advisor state so the derived notification filter count is no
longer exposed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-17 15:51:54 +02:00

87 lines
2.7 KiB
TypeScript

import { createContext, PropsWithChildren, useContext, useMemo } from 'react'
import { proxy, useSnapshot } from 'valtio'
import { StorageItemWithColumn } from '@/components/interfaces/Storage/Storage.types'
import type { Bucket } from '@/data/storage/buckets-query'
function createBucketFilePickerState({
bucket,
maxFiles,
acceptedFileExtensions,
}: {
bucket: Bucket
maxFiles: number
acceptedFileExtensions?: string[]
}) {
const state = proxy({
bucket: bucket,
maxFiles: maxFiles,
acceptedFileExtensions: acceptedFileExtensions,
columns: [] as string[],
popColumn: () => {
const lastColumnIndex = state.columns.length - 1
state.columns = state.columns.slice(0, lastColumnIndex)
},
popColumnAtIndex: (index: number) => {
state.columns = state.columns.slice(0, index)
},
pushColumnAtIndex: (column: string, index: number) => {
state.columns = state.columns.slice(0, index).concat([column])
},
selectedItems: [] as StorageItemWithColumn[],
setSelectedItems: (items: StorageItemWithColumn[]) => (state.selectedItems = items),
clearSelectedItems: (columnIndex?: number) => {
if (columnIndex !== undefined) {
state.selectedItems = state.selectedItems.filter((item) => item.columnIndex !== columnIndex)
} else {
state.selectedItems = []
}
},
itemSearchString: '',
setItemSearchString: (value: string) => (state.itemSearchString = value),
selectedFilePreview: undefined as StorageItemWithColumn | undefined,
setSelectedFilePreview: (file?: StorageItemWithColumn) => (state.selectedFilePreview = file),
})
return state
}
export type BucketFilePickerState = ReturnType<typeof createBucketFilePickerState>
const createDefaultStateConfig = () => ({
bucket: {} as Bucket,
maxFiles: 1 as const,
})
const BucketFilePickerStateContext = createContext<BucketFilePickerState>(
createBucketFilePickerState(createDefaultStateConfig())
)
export const BucketFilePickerStateContextProvider = ({
bucket,
maxFiles,
acceptedFileExtensions,
children,
}: PropsWithChildren<{ bucket: Bucket; maxFiles: number; acceptedFileExtensions?: string[] }>) => {
const state = useMemo(
() => createBucketFilePickerState({ bucket, maxFiles, acceptedFileExtensions }),
// eslint-disable-next-line react-hooks/exhaustive-deps
[bucket, maxFiles, acceptedFileExtensions?.join(',')]
)
return (
<BucketFilePickerStateContext.Provider value={state}>
{children}
</BucketFilePickerStateContext.Provider>
)
}
export function useBucketFilePickerStateSnapshot(options?: Parameters<typeof useSnapshot>[1]) {
const state = useContext(BucketFilePickerStateContext)
return useSnapshot(state, options) as BucketFilePickerState
}