import { useVirtualizer } from '@tanstack/react-virtual' import { ChevronUp, Search, X } from 'lucide-react' import { forwardRef, useEffect, useState, type HTMLAttributes, type ReactNode } from 'react' import { Button, cn, Collapsible, CollapsibleContent, CollapsibleTrigger } from 'ui' import { ShimmeringLoader } from 'ui-patterns' import { Input } from 'ui-patterns/DataInputs/Input' import { PageSection, PageSectionContent, PageSectionDescription, PageSectionMeta, PageSectionSummary, PageSectionTitle, } from 'ui-patterns/PageSection' import { StoragePoliciesBucketRow } from './StoragePoliciesBucketRow' import StoragePoliciesPlaceholder from './StoragePoliciesPlaceholder' import type { Policy } from '@/components/interfaces/Auth/Policies/PolicyTableRow/PolicyTableRow.utils' import { useMainScrollContainer } from '@/components/layouts/MainScrollContainerContext' import { NoSearchResults } from '@/components/ui/NoSearchResults' import { type Bucket } from '@/data/storage/buckets-query' import { useStaticEffectEvent } from '@/hooks/useStaticEffectEvent' export type SelectBucketPolicyForAction = { addPolicy: (bucketName?: string, table?: string) => void editPolicy: (policy: Policy, bucketName?: string, table?: string) => void deletePolicy: (policy: Policy) => void } type BucketsPoliciesProps = { buckets: { bucket: Bucket; policies: Policy[] }[] search?: string debouncedSearch?: string setSearch: (search: string) => void actions: SelectBucketPolicyForAction pagination: { hasNextPage: boolean isFetchingNextPage: boolean fetchNextPage: () => void } } export const BucketsPolicies = ({ buckets, search, debouncedSearch, setSearch, actions, pagination, }: BucketsPoliciesProps): ReactNode => { const [expanded, setExpanded] = useState(true) const showEmptyState = buckets.length === 0 && (!debouncedSearch || debouncedSearch.length === 0) return ( Buckets Write policies for each bucket to control access to the bucket and its contents {showEmptyState && } {buckets.length > 0 && (
{ const str = e.target.value setSearch(str) }} icon={} actions={ search ? (
)} {!!search && search.length > 0 && buckets.length === 0 && ( setSearch('')} /> )}
) } type BucketsPoliciesVirtualizedListProps = { items: { bucket: Bucket; policies: Policy[] }[] actions: SelectBucketPolicyForAction pagination: BucketsPoliciesProps['pagination'] } const BucketsPoliciesVirtualizedList = ({ items, actions, pagination, }: BucketsPoliciesVirtualizedListProps) => { const { hasNextPage, isFetchingNextPage, fetchNextPage } = pagination const itemCount = hasNextPage ? items.length + 1 : items.length const scrollElement = useMainScrollContainer() const virtualizer = useVirtualizer({ count: itemCount, estimateSize: () => 129, overscan: 5, getItemKey: (index) => items[index]?.bucket.name ?? `bucket-${index}`, getScrollElement: () => scrollElement, }) const virtualItems = virtualizer.getVirtualItems() const lastItem = virtualItems[virtualItems.length - 1] const fetchNext = useStaticEffectEvent(() => { if (lastItem && lastItem.index >= items.length - 1 && hasNextPage && !isFetchingNextPage) { fetchNextPage() } }) useEffect(fetchNext, [lastItem, fetchNext]) return (
{virtualItems.map((virtualRow) => { const isLoaderRow = virtualRow.index > items.length - 1 const commonStyle = { position: 'absolute' as const, top: 0, left: 0, width: '100%', transform: `translateY(${virtualRow.start}px)`, } if (isLoaderRow) { return ( ) } const item = items[virtualRow.index] if (!item) return null return (
) })}
) } type BucketsPoliciesLoaderProps = HTMLAttributes const BucketsPoliciesLoader = forwardRef( (props: BucketsPoliciesLoaderProps, ref) => (

Loading more...

) ) BucketsPoliciesLoader.displayName = 'BucketsPoliciesLoader'