Skip to content

Commit 1f2bfb9

Browse files
authored
chore: storage settings entitlements (supabase#39879)
* chore: storage settings entitlements * Clean up * Simplified * Types * Format * Simplified * unit * unit * removed * codegen * Fixed
1 parent 085e68c commit 1f2bfb9

File tree

4 files changed

+73
-16
lines changed

4 files changed

+73
-16
lines changed

apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export function DiskManagementForm() {
8989
},
9090
})
9191

92-
const { hasAccess, entitlementConfig } = useCheckEntitlements('instances.compute_update')
92+
const { hasAccess } = useCheckEntitlements('instances.compute_update')
9393

9494
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(false)
9595
const [refetchInterval, setRefetchInterval] = useState<number | false>(false)

apps/studio/components/interfaces/Storage/StorageSettings/StorageSettings.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import {
5252
StorageSizeUnits,
5353
} from './StorageSettings.constants'
5454
import { convertFromBytes, convertToBytes } from './StorageSettings.utils'
55+
import { useCheckEntitlements } from 'hooks/misc/useCheckEntitlements'
5556

5657
const formId = 'storage-settings-form'
5758

@@ -87,6 +88,8 @@ export const StorageSettings = () => {
8788
!!config && !config.capabilities.list_v2 && config.external.upstreamTarget === 'canary'
8889

8990
const { data: organization } = useSelectedOrganizationQuery()
91+
const { getEntitlementNumericValue, isEntitlementUnlimited } =
92+
useCheckEntitlements('storage.max_file_size')
9093
const isFreeTier = organization?.plan.id === 'free'
9194
const isSpendCapOn =
9295
organization?.plan.id === 'pro' && organization?.usage_billing_enabled === false
@@ -109,14 +112,12 @@ export const StorageSettings = () => {
109112
})
110113

111114
const maxBytes = useMemo(() => {
112-
if (organization?.plan.id === 'free') {
113-
return STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_FREE_PLAN
114-
} else if (organization?.usage_billing_enabled) {
115+
if (organization?.usage_billing_enabled || isEntitlementUnlimited()) {
115116
return STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_UNCAPPED
116117
} else {
117-
return STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_CAPPED
118+
return getEntitlementNumericValue() ?? STORAGE_FILE_SIZE_LIMIT_MAX_BYTES_CAPPED
118119
}
119-
}, [organization])
120+
}, [organization, isEntitlementUnlimited, getEntitlementNumericValue])
120121

121122
const FormSchema = z
122123
.object({

apps/studio/data/entitlements/entitlements-query.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type EntitlementsVariables = {
1111
export type EntitlementConfig =
1212
components['schemas']['ListEntitlementsResponse']['entitlements'][0]['config']
1313
export type Entitlement = components['schemas']['ListEntitlementsResponse']['entitlements'][0]
14+
export type EntitlementType = Entitlement['type']
1415

1516
export async function getEntitlements({ slug }: EntitlementsVariables, signal?: AbortSignal) {
1617
if (!slug) throw new Error('slug is required')

apps/studio/hooks/misc/useCheckEntitlements.ts

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,57 @@
11
import { useEntitlementsQuery } from 'data/entitlements/entitlements-query'
22
import { useMemo } from 'react'
33
import { useSelectedOrganizationQuery } from './useSelectedOrganization'
4-
import type { EntitlementConfig } from 'data/entitlements/entitlements-query'
4+
import type {
5+
Entitlement,
6+
EntitlementConfig,
7+
EntitlementType,
8+
} from 'data/entitlements/entitlements-query'
9+
10+
function isNumericConfig(
11+
config: EntitlementConfig,
12+
type: EntitlementType
13+
): config is { enabled: boolean; unlimited: boolean; value: number } {
14+
return type === 'numeric'
15+
}
16+
17+
function isSetConfig(
18+
config: EntitlementConfig,
19+
type: EntitlementType
20+
): config is { enabled: boolean; set: string[] } {
21+
return type === 'set'
22+
}
23+
24+
function isBooleanConfig(
25+
config: EntitlementConfig,
26+
type: EntitlementType
27+
): config is { enabled: boolean } {
28+
return type === 'boolean'
29+
}
30+
31+
function getEntitlementNumericValue(entitlement: Entitlement | null): number | undefined {
32+
const entitlementConfig = entitlement?.config
33+
return entitlementConfig &&
34+
entitlement.type &&
35+
isNumericConfig(entitlementConfig, entitlement.type)
36+
? entitlementConfig.value
37+
: undefined
38+
}
39+
40+
function isEntitlementUnlimited(entitlement: Entitlement | null): boolean {
41+
const entitlementConfig = entitlement?.config
42+
return entitlementConfig &&
43+
entitlement.type &&
44+
isNumericConfig(entitlementConfig, entitlement.type)
45+
? entitlementConfig.unlimited
46+
: false
47+
}
48+
49+
function getEntitlementSetValues(entitlement: Entitlement | null): string[] {
50+
const entitlementConfig = entitlement?.config
51+
return entitlementConfig && entitlement.type && isSetConfig(entitlementConfig, entitlement.type)
52+
? entitlementConfig.set
53+
: []
54+
}
555

656
export function useCheckEntitlements(
757
featureKey: string,
@@ -29,27 +79,32 @@ export function useCheckEntitlements(
2979
isSuccess: isSuccessEntitlements,
3080
} = useEntitlementsQuery({ slug: finalOrgSlug! }, { enabled })
3181

32-
const { hasAccess, entitlementConfig } = useMemo((): {
33-
hasAccess: boolean
34-
entitlementConfig: EntitlementConfig
82+
const { entitlement } = useMemo((): {
83+
entitlement: Entitlement | null
3584
} => {
3685
// If no organization slug, no access
37-
if (!finalOrgSlug) return { hasAccess: false, entitlementConfig: { enabled: false } }
86+
if (!finalOrgSlug) return { entitlement: null }
3887

3988
const entitlement = entitlementsData?.entitlements.find(
4089
(entitlement) => entitlement.feature.key === featureKey
4190
)
42-
const entitlementConfig = entitlement?.config ?? { enabled: false }
43-
44-
if (!entitlement) return { hasAccess: false, entitlementConfig: { enabled: false } }
4591

46-
return { hasAccess: entitlement.hasAccess, entitlementConfig }
92+
return {
93+
entitlement: entitlement ?? null,
94+
}
4795
}, [entitlementsData, featureKey, finalOrgSlug])
4896

4997
const isLoading = shouldGetSelectedOrg ? isLoadingSelectedOrg : isLoadingEntitlements
5098
const isSuccess = shouldGetSelectedOrg
5199
? isSuccessSelectedOrg && isSuccessEntitlements
52100
: isSuccessEntitlements
53101

54-
return { hasAccess, entitlementConfig, isLoading, isSuccess }
102+
return {
103+
hasAccess: entitlement?.hasAccess ?? false,
104+
isLoading,
105+
isSuccess,
106+
getEntitlementNumericValue: () => getEntitlementNumericValue(entitlement),
107+
isEntitlementUnlimited: () => isEntitlementUnlimited(entitlement),
108+
getEntitlementSetValues: () => getEntitlementSetValues(entitlement),
109+
}
55110
}

0 commit comments

Comments
 (0)