diff --git a/apps/studio/components/to-be-cleaned/Storage/StorageSettings/CreateCredentialModal.tsx b/apps/studio/components/to-be-cleaned/Storage/StorageSettings/CreateCredentialModal.tsx index 133a33ade14..24a06db41ce 100644 --- a/apps/studio/components/to-be-cleaned/Storage/StorageSettings/CreateCredentialModal.tsx +++ b/apps/studio/components/to-be-cleaned/Storage/StorageSettings/CreateCredentialModal.tsx @@ -27,8 +27,6 @@ import { } from 'ui' import { Input } from 'ui-patterns/DataInputs/Input' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' -import { useProjectStorageConfigQuery } from 'data/config/project-storage-config-query' -import { ButtonTooltip } from 'components/ui/ButtonTooltip' interface CreateCredentialModalProps { visible: boolean @@ -42,10 +40,6 @@ export const CreateCredentialModal = ({ visible, onOpenChange }: CreateCredentia const canCreateCredentials = useCheckPermissions(PermissionAction.STORAGE_ADMIN_WRITE, '*') - const { data: config } = useProjectStorageConfigQuery({ projectRef }) - const isS3ConnectionEnabled = config?.features.s3Protocol.enabled - const disableCreation = !isProjectActive || !canCreateCredentials || !isS3ConnectionEnabled - const FormSchema = z.object({ description: z.string().min(3, { message: 'Description must be at least 3 characters long', @@ -84,20 +78,22 @@ export const CreateCredentialModal = ({ visible, onOpenChange }: CreateCredentia - - {disableCreation && ( + {(!isProjectActive || !canCreateCredentials) && ( {!isProjectActive ? 'Restore your project to create new access keys' - : !isS3ConnectionEnabled - ? 'Connection via S3 protocol is currently disabled' - : !canCreateCredentials - ? 'You need additional permissions to create new access keys' - : ''} + : !canCreateCredentials + ? 'You need additional permissions to create new access keys' + : ''} )} @@ -163,7 +159,7 @@ export const CreateCredentialModal = ({ visible, onOpenChange }: CreateCredentia ( + render={({ field }) => ( { const [deleteCred, setDeleteCred] = useState<{ id: string; description: string }>() const canReadS3Credentials = useCheckPermissions(PermissionAction.STORAGE_ADMIN_READ, '*') - const canUpdateStorageSettings = useCheckPermissions(PermissionAction.STORAGE_ADMIN_WRITE, '*') const { data: settings } = useProjectSettingsV2Query({ projectRef }) - const { - data: config, - error: configError, - isSuccess: isSuccessStorageConfig, - isError: isErrorStorageConfig, - } = useProjectStorageConfigQuery({ projectRef }) - const { data: storageCreds, isLoading: isLoadingStorageCreds } = useStorageCredentialsQuery( + const { data: storageCreds, ...storageCredsQuery } = useStorageCredentialsQuery( { projectRef }, { enabled: canReadS3Credentials } ) - const { mutate: updateStorageConfig, isLoading: isUpdating } = - useProjectStorageConfigUpdateUpdateMutation({ - onSuccess: (_, vars) => { - if (vars.features) form.reset({ s3ConnectionEnabled: vars.features.s3Protocol.enabled }) - toast.success('Successfully updated storage settings') - }, - }) - - const FormSchema = z.object({ s3ConnectionEnabled: z.boolean() }) - const form = useForm>({ - resolver: zodResolver(FormSchema), - defaultValues: { s3ConnectionEnabled: false }, - }) - const protocol = settings?.app_config?.protocol ?? 'https' const endpoint = settings?.app_config?.endpoint const hasStorageCreds = storageCreds?.data && storageCreds.data.length > 0 const s3connectionUrl = getConnectionURL(projectRef ?? '', protocol, endpoint) - const onSubmit: SubmitHandler> = async (data) => { - if (!projectRef) return console.error('Project ref is required') - if (!config) return console.error('Storage config is required') - updateStorageConfig({ - projectRef, - features: { - ...config?.features, - s3Protocol: { enabled: data.s3ConnectionEnabled }, - }, - }) - } - - useEffect(() => { - form.reset({ s3ConnectionEnabled: config?.features.s3Protocol.enabled }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isSuccessStorageConfig]) - return ( <> - -
- - {projectIsLoading ? ( - - ) : isProjectActive ? ( - - ( - - - - - - )} - /> - - {isErrorStorageConfig && ( -
- -
- )} - - - -
- - - - {!projectIsLoading && ( - - - - )} -
- - - -
- {!canUpdateStorageSettings ? ( -

- You need additional permissions to update storage settings -

- ) : ( -
- )} -
- - -
-
- - ) : ( - - - Project is paused - - To connect to your S3 bucket, you need to restore your project. - -
- -
-
- )} - - +
+ + {projectIsLoading ? ( + + ) : isProjectActive ? ( + + + + + {!projectIsLoading && ( + + + + )} + + ) : ( + + + Project is paused + + To connect to your S3 bucket, you need to restore your project. + +
+ +
+
+ )} +
{ ) : ( <> - {isLoadingStorageCreds ? ( + {storageCredsQuery.isLoading ? (
diff --git a/apps/studio/components/to-be-cleaned/Storage/StorageSettings/StorageSettings.tsx b/apps/studio/components/to-be-cleaned/Storage/StorageSettings/StorageSettings.tsx index 5ad69e661f2..acc0d6d5ca9 100644 --- a/apps/studio/components/to-be-cleaned/Storage/StorageSettings/StorageSettings.tsx +++ b/apps/studio/components/to-be-cleaned/Storage/StorageSettings/StorageSettings.tsx @@ -8,7 +8,6 @@ import * as z from 'zod' import { useParams } from 'common' import AlertError from 'components/ui/AlertError' -import { InlineLink } from 'components/ui/InlineLink' import NoPermission from 'components/ui/NoPermission' import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' import UpgradeToPro from 'components/ui/UpgradeToPro' @@ -36,6 +35,7 @@ import { } from 'ui' import { STORAGE_FILE_SIZE_LIMIT_MAX_BYTES, StorageSizeUnits } from './StorageSettings.constants' import { convertFromBytes, convertToBytes } from './StorageSettings.utils' +import { Markdown } from 'components/interfaces/Markdown' interface StorageSettingsState { fileSizeLimit: number @@ -54,7 +54,7 @@ const StorageSettings = () => { isLoading, isSuccess, isError, - } = useProjectStorageConfigQuery({ projectRef }) + } = useProjectStorageConfigQuery({ projectRef }, { enabled: IS_PLATFORM }) const organization = useSelectedOrganization() const { data: subscription, isSuccess: isSuccessSubscription } = useOrgSubscriptionQuery({ @@ -116,7 +116,7 @@ const StorageSettings = () => { resolver: zodResolver(FormSchema), defaultValues: initialValues, }) - const { fileSizeLimit: limit, unit: storageUnit } = form.watch() + const { fileSizeLimit: limit, unit: storageUnit, imageTransformationEnabled } = form.watch() const { mutate: updateStorageConfig, isLoading: isUpdating } = useProjectStorageConfigUpdateUpdateMutation({ @@ -127,14 +127,13 @@ const StorageSettings = () => { const onSubmit: SubmitHandler> = async (data) => { if (!projectRef) return console.error('Project ref is required') - if (!config) return console.error('Storage config is required') - updateStorageConfig({ projectRef, fileSizeLimit: convertToBytes(data.fileSizeLimit, data.unit), features: { - imageTransformation: { enabled: data.imageTransformationEnabled }, - s3Protocol: config.features.s3Protocol, + imageTransformation: { + enabled: data.imageTransformationEnabled, + }, }, }) } @@ -154,7 +153,7 @@ const StorageSettings = () => { {isSuccess && (
-
+

Upload file size limit

@@ -252,13 +251,7 @@ const StorageSettings = () => { )} />
-

- Optimize and resize images on the fly.{' '} - - Learn more - - . -

+
diff --git a/apps/studio/components/ui/InlineLink.tsx b/apps/studio/components/ui/InlineLink.tsx index f8f547457f8..b33d5981939 100644 --- a/apps/studio/components/ui/InlineLink.tsx +++ b/apps/studio/components/ui/InlineLink.tsx @@ -7,7 +7,7 @@ interface InlineLinkProps { export const InlineLink = ({ href, children }: PropsWithChildren) => { const className = - 'underline transition underline-offset-2 decoration-foreground-lighter hover:decoration-foreground text-foreground' + 'underline transition underline-offset-2 decoration-foreground-lighter hover:decoration-foreground' if (href.startsWith('http')) { return ( diff --git a/apps/studio/data/config/project-storage-config-query.ts b/apps/studio/data/config/project-storage-config-query.ts index 058fa95e9a9..56cbaf50708 100644 --- a/apps/studio/data/config/project-storage-config-query.ts +++ b/apps/studio/data/config/project-storage-config-query.ts @@ -4,7 +4,6 @@ import { components } from 'data/api' import { get, handleError } from 'data/fetchers' import type { ResponseError } from 'types' import { configKeys } from './keys' -import { IS_PLATFORM } from 'lib/constants' export type ProjectStorageConfigVariables = { projectRef?: string @@ -40,5 +39,5 @@ export const useProjectStorageConfigQuery = ( useQuery( configKeys.storage(projectRef), ({ signal }) => getProjectStorageConfig({ projectRef }, signal), - { enabled: enabled && IS_PLATFORM && typeof projectRef !== 'undefined', ...options } + { enabled: enabled && typeof projectRef !== 'undefined', ...options } ) diff --git a/apps/studio/data/config/project-storage-config-update-mutation.ts b/apps/studio/data/config/project-storage-config-update-mutation.ts index 3ded8ea5326..9c55eeb2ec9 100644 --- a/apps/studio/data/config/project-storage-config-update-mutation.ts +++ b/apps/studio/data/config/project-storage-config-update-mutation.ts @@ -1,15 +1,19 @@ import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' -import { handleError, patch } from 'data/fetchers' +import { patch } from 'lib/common/fetch' +import { API_URL } from 'lib/constants' import type { ResponseError } from 'types' import { configKeys } from './keys' -import { components } from 'api-types' -type StorageConfigUpdatePayload = components['schemas']['UpdateStorageConfigBody'] - -export type ProjectStorageConfigUpdateUpdateVariables = StorageConfigUpdatePayload & { +export type ProjectStorageConfigUpdateUpdateVariables = { projectRef: string + fileSizeLimit: number + features?: { + imageTransformation: { + enabled: boolean + } + } } export async function updateProjectStorageConfigUpdate({ @@ -17,12 +21,12 @@ export async function updateProjectStorageConfigUpdate({ fileSizeLimit, features, }: ProjectStorageConfigUpdateUpdateVariables) { - const { data, error } = await patch('/platform/projects/{ref}/config/storage', { - params: { path: { ref: projectRef } }, - body: { fileSizeLimit, features }, + const response = await patch(`${API_URL}/projects/${projectRef}/config/storage`, { + fileSizeLimit, + features, }) - if (error) handleError(error) - return data + if (response.error) throw response.error + return response } type ProjectStorageConfigUpdateUpdateData = Awaited< diff --git a/apps/studio/data/storage/s3-access-key-query.ts b/apps/studio/data/storage/s3-access-key-query.ts index 9bef91e3b3c..67a1e1acc4c 100644 --- a/apps/studio/data/storage/s3-access-key-query.ts +++ b/apps/studio/data/storage/s3-access-key-query.ts @@ -3,7 +3,6 @@ import { UseQueryOptions, useQuery } from '@tanstack/react-query' import { get, handleError } from 'data/fetchers' import { ResponseError } from 'types' import { storageCredentialsKeys } from './s3-access-key-keys' -import { IS_PLATFORM } from 'lib/constants' type StorageCredentialsVariables = { projectRef?: string } @@ -40,5 +39,5 @@ export const useStorageCredentialsQuery = ( useQuery( storageCredentialsKeys.credentials(projectRef), ({ signal }) => fetchStorageCredentials({ projectRef }, signal), - { enabled: enabled && IS_PLATFORM && typeof projectRef !== 'undefined', ...options } + { enabled: enabled && typeof projectRef !== 'undefined', ...options } ) diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api.d.ts index 0035062a5cd..1cf709bab4e 100644 --- a/packages/api-types/types/api.d.ts +++ b/packages/api-types/types/api.d.ts @@ -5681,10 +5681,6 @@ export interface components { } StorageFeatures: { imageTransformation: components['schemas']['StorageFeatureImageTransformation'] - s3Protocol: components['schemas']['StorageFeatureS3Protocol'] - } - StorageFeatureS3Protocol: { - enabled: boolean } StorageObject: { bucket_id: string