Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { DocsButton } from '@/components/ui/DocsButton'
import { UpgradePlanButton } from '@/components/ui/UpgradePlanButton'
import { useEnablePhysicalBackupsMutation } from '@/data/database/enable-physical-backups-mutation'
import { useProjectDetailQuery } from '@/data/projects/project-detail-query'
import { MAX_REPLICAS_ABOVE_XL, MAX_REPLICAS_BELOW_XL } from '@/data/read-replicas/replicas-query'
import { READ_REPLICAS_MAX_COUNT } from '@/data/read-replicas/replicas-query'
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { DOCS_URL } from '@/lib/constants'
Expand Down Expand Up @@ -222,11 +222,11 @@ export const ReadReplicaEligibilityWarnings = () => {
title={`You can only deploy up to ${maxNumberOfReplicas} read replicas at once`}
>
<p>If you'd like to spin up another read replica, please drop an existing replica first.</p>
{maxNumberOfReplicas === MAX_REPLICAS_BELOW_XL && (
{maxNumberOfReplicas < READ_REPLICAS_MAX_COUNT && (
<>
<p>
Alternatively, you may deploy up to{' '}
<span className="text-foreground">{MAX_REPLICAS_ABOVE_XL}</span> replicas if your
<span className="text-foreground">{READ_REPLICAS_MAX_COUNT}</span> replicas if your
project is on an XL compute or higher.
</p>
<UpgradePlanButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { useMemo } from 'react'

import { useOverdueInvoicesQuery } from '@/data/invoices/invoices-overdue-query'
import {
MAX_REPLICAS_ABOVE_XL,
MAX_REPLICAS_BELOW_XL,
getMaxReplicas,
READ_REPLICA_COMPUTE_CAPS,
useReadReplicasQuery,
} from '@/data/read-replicas/replicas-query'
import { useProjectAddonsQuery } from '@/data/subscriptions/project-addons-query'
Expand Down Expand Up @@ -41,14 +41,10 @@ export const useCheckEligibilityDeployReplica = () => {
const currentComputeAddon = addons?.selected_addons.find(
(addon) => addon.type === 'compute_instance'
)?.variant.identifier
const isMinimallyOnSmallCompute =
currentComputeAddon !== undefined && currentComputeAddon !== 'ci_micro'

const maxNumberOfReplicas = ['ci_micro', 'ci_small', 'ci_medium', 'ci_large'].includes(
currentComputeAddon ?? 'ci_micro'
)
? MAX_REPLICAS_BELOW_XL
: MAX_REPLICAS_ABOVE_XL
const isBelowSmallCompute =
currentComputeAddon === undefined || READ_REPLICA_COMPUTE_CAPS[currentComputeAddon] === 0
const maxNumberOfReplicas = getMaxReplicas(currentComputeAddon)
const isReachedMaxReplicas =
(databases ?? []).filter((db) => db.identifier !== projectRef).length >= maxNumberOfReplicas

Expand All @@ -62,19 +58,18 @@ export const useCheckEligibilityDeployReplica = () => {
isAWSProvider &&
hasReadReplicaAccess &&
isWalgEnabled &&
currentComputeAddon !== undefined &&
!hasOverdueInvoices &&
!isAwsK8s &&
!isProWithSpendCapEnabled &&
isMinimallyOnSmallCompute
!isBelowSmallCompute

return {
can: canDeployReplica,
hasOverdueInvoices,
isAWSProvider,
isAwsK8s,
isPgVersionBelow15: currentPgVersion < 15,
isBelowSmallCompute: !isMinimallyOnSmallCompute,
isBelowSmallCompute,
isWalgNotEnabled: !isWalgEnabled,
isProWithSpendCapEnabled,
isReachedMaxReplicas,
Expand Down
14 changes: 7 additions & 7 deletions apps/studio/components/interfaces/Storage/FilesBuckets/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { CreateBucketModal } from '../CreateBucketModal'
import { EmptyBucketState } from '../EmptyBucketState'
import { CreateBucketButton } from '../NewBucketButton'
import { STORAGE_BUCKET_SORT } from '../Storage.constants'
import { useStoragePreference } from '../StorageExplorer/useStoragePreference'
import { BucketsTable } from './BucketsTable'
import AlertError from '@/components/ui/AlertError'
import { InlineLink } from '@/components/ui/InlineLink'
Expand All @@ -34,13 +35,14 @@ import { useStorageExplorerStateSnapshot } from '@/state/storage-explorer'
export const FilesBuckets = () => {
const { ref } = useParams()
const snap = useStorageExplorerStateSnapshot()
const { sortBucket, setSortBucket } = useStoragePreference(snap.projectRef)

const [filterString, setFilterString] = useState('')
const debouncedFilterString = useDebounce(filterString, 250)
const normalizedSearch = debouncedFilterString.trim()

const sortColumn = snap.sortBucket === STORAGE_BUCKET_SORT.ALPHABETICAL ? 'name' : 'created_at'
const sortOrder = snap.sortBucket === STORAGE_BUCKET_SORT.ALPHABETICAL ? 'asc' : 'desc'
const sortColumn = sortBucket === STORAGE_BUCKET_SORT.ALPHABETICAL ? 'name' : 'created_at'
const sortOrder = sortBucket === STORAGE_BUCKET_SORT.ALPHABETICAL ? 'asc' : 'desc'

const [visible, setVisible] = useQueryState(
'new',
Expand Down Expand Up @@ -118,15 +120,13 @@ export const FilesBuckets = () => {
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button type="default" icon={<ArrowDownNarrowWide />}>
Sorted by {snap.sortBucket === 'alphabetical' ? 'name' : 'created at'}
Sorted by {sortBucket === 'alphabetical' ? 'name' : 'created at'}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-40">
<DropdownMenuRadioGroup
value={snap.sortBucket}
onValueChange={(value) =>
snap.setSortBucket(value as STORAGE_BUCKET_SORT)
}
value={sortBucket}
onValueChange={(value) => setSortBucket(value as STORAGE_BUCKET_SORT)}
>
<DropdownMenuRadioItem value="alphabetical">
Sort by name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
STORAGE_SORT_BY_ORDER,
STORAGE_VIEWS,
} from '../Storage.constants'
import { useStoragePreference } from './useStoragePreference'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useStorageExplorerStateSnapshot } from '@/state/storage-explorer'

Expand All @@ -21,14 +22,31 @@ interface ColumnContextMenuProps {

export const ColumnContextMenu = ({ id = '' }: ColumnContextMenuProps) => {
const {
projectRef,
columns,
selectedItems,
setSelectedItems,
setView,
setSortBy,
setSortByOrder,
setSelectedFilePreview,
refetchAllOpenedFolders,
addNewFolderPlaceholder,
} = useStorageExplorerStateSnapshot()
const {
setView,
setSortBy: setPreferenceSortBy,
setSortByOrder: setPreferenceSortByOrder,
} = useStoragePreference(projectRef)

const setSortBy = async (value: STORAGE_SORT_BY) => {
setPreferenceSortBy(value)
setSelectedFilePreview(undefined)
await refetchAllOpenedFolders()
}

const setSortByOrder = async (value: STORAGE_SORT_BY_ORDER) => {
setPreferenceSortByOrder(value)
setSelectedFilePreview(undefined)
await refetchAllOpenedFolders()
}

const { can: canUpdateFiles } = useAsyncCheckPermissions(PermissionAction.STORAGE_WRITE, '*')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ColumnContextMenu } from './ColumnContextMenu'
import { FileExplorerColumn } from './FileExplorerColumn'
import { FolderContextMenu } from './FolderContextMenu'
import { ItemContextMenu } from './ItemContextMenu'
import { useStoragePreference } from './useStoragePreference'
import { useStorageExplorerStateSnapshot } from '@/state/storage-explorer'

export interface FileExplorerProps {
Expand All @@ -33,6 +34,7 @@ export const FileExplorer = ({
}: FileExplorerProps) => {
const fileExplorerRef = useRef<any>(null)
const snap = useStorageExplorerStateSnapshot()
const { view } = useStoragePreference(snap.projectRef)

useEffect(() => {
if (fileExplorerRef) {
Expand All @@ -48,7 +50,7 @@ export const FileExplorer = ({
ref={fileExplorerRef}
className={cn(
'file-explorer flex flex-grow overflow-x-auto justify-between h-full w-full relative',
snap.view === STORAGE_VIEWS.LIST && 'flex-col'
view === STORAGE_VIEWS.LIST && 'flex-col'
)}
>
<ColumnContextMenu id={CONTEXT_MENU_KEYS.STORAGE_COLUMN} />
Expand All @@ -59,7 +61,7 @@ export const FileExplorer = ({
<FileExplorerColumn
column={{ id: '', name: '', path: '', items: [], status: STORAGE_ROW_STATUS.LOADING }}
/>
) : snap.view === STORAGE_VIEWS.COLUMNS ? (
) : view === STORAGE_VIEWS.COLUMNS ? (
<div className="flex">
{columns.map((column, index) => (
<FileExplorerColumn
Expand All @@ -75,7 +77,7 @@ export const FileExplorer = ({
/>
))}
</div>
) : snap.view === STORAGE_VIEWS.LIST ? (
) : view === STORAGE_VIEWS.LIST ? (
<>
{columns.length > 0 && (
<FileExplorerColumn
Expand All @@ -92,7 +94,7 @@ export const FileExplorer = ({
)}
</>
) : (
<div>Unknown view: {snap.view}</div>
<div>Unknown view: {view}</div>
)}
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from '../Storage.constants'
import type { StorageColumn, StorageItemWithColumn } from '../Storage.types'
import { FileExplorerRow } from './FileExplorerRow'
import { useStoragePreference } from './useStoragePreference'
import { InfiniteListDefault, LoaderForIconMenuItems } from '@/components/ui/InfiniteList'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { BASE_PATH } from '@/lib/constants'
Expand Down Expand Up @@ -83,6 +84,7 @@ export const FileExplorerColumn = ({
const fileExplorerColumnRef = useRef<any>(null)

const snap = useStorageExplorerStateSnapshot()
const { view } = useStoragePreference(snap.projectRef)
const { can: canUpdateStorage } = useAsyncCheckPermissions(PermissionAction.STORAGE_WRITE, '*')

useEffect(() => {
Expand Down Expand Up @@ -156,19 +158,19 @@ export const FileExplorerColumn = ({

const itemProps = useMemo(
() => ({
view: snap.view,
view: view,
columnIndex: index,
selectedItems,
}),
[snap.view, index, selectedItems]
[view, index, selectedItems]
)

return (
<div
ref={fileExplorerColumnRef}
className={cn(
fullWidth ? 'w-full' : 'w-64 border-r border-overlay',
snap.view === STORAGE_VIEWS.LIST && 'h-full',
view === STORAGE_VIEWS.LIST && 'h-full',
'hide-scrollbar relative flex flex-shrink-0 flex-col overflow-auto'
)}
onContextMenu={displayMenu}
Expand All @@ -181,7 +183,7 @@ export const FileExplorerColumn = ({
}}
>
{/* Checkbox selection for select all */}
{snap.view === STORAGE_VIEWS.COLUMNS && (
{view === STORAGE_VIEWS.COLUMNS && (
<div
className={cn(
'sticky top-0 z-10 mb-0 flex items-center bg-table-header-light px-2.5 [[data-theme*=dark]_&]:bg-table-header-dark',
Expand All @@ -202,7 +204,7 @@ export const FileExplorerColumn = ({
)}

{/* List Interface Header */}
{snap.view === STORAGE_VIEWS.LIST && (
{view === STORAGE_VIEWS.LIST && (
<div className="sticky top-0 py-2 z-10 flex min-w-min items-center border-b border-overlay bg-surface-100 px-2.5">
<div className="flex w-[40%] min-w-[250px] items-center">
<SelectAllCheckbox />
Expand Down Expand Up @@ -283,7 +285,7 @@ export const FileExplorerColumn = ({
/>

{/* List interface footer */}
{snap.view === STORAGE_VIEWS.LIST && (
{view === STORAGE_VIEWS.LIST && (
<div className="shrink-0 rounded-b-md z-10 flex min-w-min items-center bg-panel-footer-light px-2.5 py-2 [[data-theme*=dark]_&]:bg-panel-footer-dark w-full">
<p className="text-sm">
{formatBytes(columnItemsSize)} for {columnItems.length} items
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ const {
mockUseStorageExplorerStateSnapshot,
mockUseAsyncCheckPermissions,
mockIsAPIDocsSidePanelEnabled,
mockUseStoragePreference,
} = vi.hoisted(() => ({
mockTrack: vi.fn(),
mockUseStorageExplorerStateSnapshot: vi.fn(),
mockUseAsyncCheckPermissions: vi.fn(),
mockIsAPIDocsSidePanelEnabled: vi.fn(),
mockUseStoragePreference: vi.fn(),
}))

vi.mock('lib/telemetry/track', () => ({ useTrack: () => mockTrack }))
Expand All @@ -31,6 +33,9 @@ vi.mock('components/interfaces/App/FeaturePreview/FeaturePreviewContext', () =>
vi.mock('components/ui/APIDocsButton', () => ({
APIDocsButton: () => null,
}))
vi.mock('./useStoragePreference', () => ({
useStoragePreference: (...args: any[]) => mockUseStoragePreference(...args),
}))

function makeColumn(name: string) {
return {
Expand All @@ -41,13 +46,10 @@ function makeColumn(name: string) {
}
}

function createSnapshot(view: STORAGE_VIEWS = STORAGE_VIEWS.COLUMNS) {
function createSnapshot() {
return {
projectRef: 'test-ref',
columns: [makeColumn('my-bucket'), makeColumn('images'), makeColumn('2024')],
sortBy: STORAGE_SORT_BY.NAME,
setSortBy: vi.fn(),
sortByOrder: STORAGE_SORT_BY_ORDER.ASC,
setSortByOrder: vi.fn(),
popColumn: vi.fn(),
popColumnAtIndex: vi.fn(),
popOpenedFolders: vi.fn(),
Expand All @@ -60,8 +62,19 @@ function createSnapshot(view: STORAGE_VIEWS = STORAGE_VIEWS.COLUMNS) {
selectedBucket: { id: 'bucket-id', name: 'my-bucket' },
isSearching: false,
setIsSearching: vi.fn(),
}
}

function createPreference(view: STORAGE_VIEWS = STORAGE_VIEWS.COLUMNS) {
return {
view,
setView: vi.fn(),
sortBy: STORAGE_SORT_BY.NAME,
setSortBy: vi.fn(),
sortByOrder: STORAGE_SORT_BY_ORDER.ASC,
setSortByOrder: vi.fn(),
sortBucket: 'created_at',
setSortBucket: vi.fn(),
}
}

Expand All @@ -71,8 +84,10 @@ describe('FileExplorerHeader', () => {
mockUseStorageExplorerStateSnapshot.mockReset()
mockUseAsyncCheckPermissions.mockReset()
mockIsAPIDocsSidePanelEnabled.mockReset()
mockUseStoragePreference.mockReset()

mockUseStorageExplorerStateSnapshot.mockReturnValue(createSnapshot())
mockUseStoragePreference.mockReturnValue(createPreference())
mockUseAsyncCheckPermissions.mockReturnValue({ can: true })
mockIsAPIDocsSidePanelEnabled.mockReturnValue(false)
})
Expand Down Expand Up @@ -202,7 +217,7 @@ describe('FileExplorerHeader', () => {
})

it('does not render Navigate in list view', () => {
mockUseStorageExplorerStateSnapshot.mockReturnValue(createSnapshot(STORAGE_VIEWS.LIST))
mockUseStoragePreference.mockReturnValue(createPreference(STORAGE_VIEWS.LIST))

render(
<FileExplorerHeader
Expand Down
Loading
Loading