diff --git a/apps/studio/data/organizations/organizations-query.ts b/apps/studio/data/organizations/organizations-query.ts index 88c29412143..b11d81b6635 100644 --- a/apps/studio/data/organizations/organizations-query.ts +++ b/apps/studio/data/organizations/organizations-query.ts @@ -1,11 +1,12 @@ import { QueryClient, useQuery } from '@tanstack/react-query' - import { components } from 'api-types' -import { get, handleError } from 'data/fetchers' -import { MANAGED_BY, ManagedBy } from 'lib/constants/infrastructure' -import { useProfile } from 'lib/profile' -import type { Organization, ResponseError, UseCustomQueryOptions } from 'types' + import { organizationKeys } from './keys' +import { get, handleError } from '@/data/fetchers' +import { MANAGED_BY, ManagedBy } from '@/lib/constants/infrastructure' +import { useProfile } from '@/lib/profile' +import { useService } from '@/lib/services/context' +import type { Organization, ResponseError, UseCustomQueryOptions } from '@/types' export type OrganizationBase = components['schemas']['OrganizationResponse'] @@ -54,9 +55,10 @@ export const useOrganizationsQuery = ({ ...options }: UseCustomQueryOptions = {}) => { const { profile } = useProfile() + const { getOrganizations: fetchOrganizations } = useService('organizations') return useQuery({ queryKey: organizationKeys.list(), - queryFn: ({ signal }) => getOrganizations({ signal }), + queryFn: ({ signal }) => fetchOrganizations({ signal }), enabled: enabled && profile !== undefined, ...options, staleTime: 30 * 60 * 1000, diff --git a/apps/studio/data/organizations/organizations-service-live.ts b/apps/studio/data/organizations/organizations-service-live.ts new file mode 100644 index 00000000000..89c02bdc5f6 --- /dev/null +++ b/apps/studio/data/organizations/organizations-service-live.ts @@ -0,0 +1,6 @@ +import { getOrganizations } from './organizations-query' +import type { OrganizationsService } from './organizations-service' + +export const organizationsServiceLive: OrganizationsService = { + getOrganizations, +} diff --git a/apps/studio/data/organizations/organizations-service.ts b/apps/studio/data/organizations/organizations-service.ts new file mode 100644 index 00000000000..64a1b90271e --- /dev/null +++ b/apps/studio/data/organizations/organizations-service.ts @@ -0,0 +1,5 @@ +import type { Organization } from '@/types' + +export interface OrganizationsService { + getOrganizations: (params: { signal?: AbortSignal }) => Promise +} diff --git a/apps/studio/data/permissions/permissions-query.ts b/apps/studio/data/permissions/permissions-query.ts index 6e47549e96b..ec13f6b2a83 100644 --- a/apps/studio/data/permissions/permissions-query.ts +++ b/apps/studio/data/permissions/permissions-query.ts @@ -1,10 +1,11 @@ import { useQuery } from '@tanstack/react-query' - import { useIsLoggedIn } from 'common' -import { get, handleError } from 'data/fetchers' -import { IS_PLATFORM } from 'lib/constants' -import type { Permission, ResponseError, UseCustomQueryOptions } from 'types' + import { permissionKeys } from './keys' +import { get, handleError } from '@/data/fetchers' +import { IS_PLATFORM } from '@/lib/constants' +import { useService } from '@/lib/services/context' +import type { Permission, ResponseError, UseCustomQueryOptions } from '@/types' export type PermissionsResponse = Permission[] @@ -35,10 +36,11 @@ export const usePermissionsQuery = ({ ...options }: UseCustomQueryOptions = {}) => { const isLoggedIn = useIsLoggedIn() + const { getPermissions: fetchPermissions } = useService('permissions') return useQuery({ queryKey: permissionKeys.list(), - queryFn: ({ signal }) => getPermissions(signal), + queryFn: ({ signal }) => fetchPermissions(signal), ...options, enabled: IS_PLATFORM && enabled && isLoggedIn, staleTime: 5 * 60 * 1000, diff --git a/apps/studio/data/permissions/permissions-service-live.ts b/apps/studio/data/permissions/permissions-service-live.ts new file mode 100644 index 00000000000..b2e5c5d9b26 --- /dev/null +++ b/apps/studio/data/permissions/permissions-service-live.ts @@ -0,0 +1,6 @@ +import { getPermissions } from './permissions-query' +import type { PermissionsService } from './permissions-service' + +export const permissionsServiceLive: PermissionsService = { + getPermissions, +} diff --git a/apps/studio/data/permissions/permissions-service.ts b/apps/studio/data/permissions/permissions-service.ts new file mode 100644 index 00000000000..b42198153cb --- /dev/null +++ b/apps/studio/data/permissions/permissions-service.ts @@ -0,0 +1,7 @@ +import type { Permission } from 'types' + +export type PermissionsResponse = Permission[] + +export interface PermissionsService { + getPermissions: (signal?: AbortSignal) => Promise +} diff --git a/apps/studio/data/prefetchers/project.$ref.tsx b/apps/studio/data/prefetchers/project.$ref.tsx index 8709c0f2d6d..642b1fdb05d 100644 --- a/apps/studio/data/prefetchers/project.$ref.tsx +++ b/apps/studio/data/prefetchers/project.$ref.tsx @@ -3,11 +3,13 @@ import { useRouter } from 'next/router' import { PropsWithChildren, useCallback } from 'react' import { prefetchProjectDetail } from 'data/projects/project-detail-query' +import { useService } from 'lib/services/context' import PrefetchableLink, { PrefetchableLinkProps } from './PrefetchableLink' export function usePrefetchProjectIndexPage() { const router = useRouter() const queryClient = useQueryClient() + const projectsService = useService('projects') return useCallback( ({ projectRef }: { projectRef?: string }) => { @@ -15,13 +17,11 @@ export function usePrefetchProjectIndexPage() { router.prefetch(`/project/${projectRef}`) // Prefetch data - prefetchProjectDetail(queryClient, { - ref: projectRef, - }).catch(() => { + prefetchProjectDetail(queryClient, { ref: projectRef }, projectsService).catch(() => { // eat prefetching errors as they are not critical }) }, - [queryClient, router] + [queryClient, router, projectsService] ) } diff --git a/apps/studio/data/profile/profile-query.ts b/apps/studio/data/profile/profile-query.ts index f7553f9b96b..406cbdf15be 100644 --- a/apps/studio/data/profile/profile-query.ts +++ b/apps/studio/data/profile/profile-query.ts @@ -1,10 +1,11 @@ import { useQuery } from '@tanstack/react-query' -import { get, handleError } from 'data/fetchers' -import { IS_PLATFORM } from 'lib/constants' -import type { ResponseError, UseCustomQueryOptions } from 'types' import { profileKeys } from './keys' import type { Profile } from './types' +import { get, handleError } from '@/data/fetchers' +import { IS_PLATFORM } from '@/lib/constants' +import { useService } from '@/lib/services/context' +import type { ResponseError, UseCustomQueryOptions } from '@/types' export async function getProfile(signal?: AbortSignal) { const { data, error } = await get('/platform/profile', { @@ -31,9 +32,10 @@ export const useProfileQuery = ({ enabled = true, ...options }: UseCustomQueryOptions = {}) => { + const { getProfile: fetchProfile } = useService('profile') return useQuery({ queryKey: profileKeys.profile(), - queryFn: ({ signal }) => getProfile(signal), + queryFn: ({ signal }) => fetchProfile(signal), staleTime: 1000 * 60 * 30, ...options, enabled, diff --git a/apps/studio/data/profile/profile-service-live.ts b/apps/studio/data/profile/profile-service-live.ts new file mode 100644 index 00000000000..38b9af1aaf2 --- /dev/null +++ b/apps/studio/data/profile/profile-service-live.ts @@ -0,0 +1,6 @@ +import { getProfile } from './profile-query' +import type { ProfileService } from './profile-service' + +export const profileServiceLive: ProfileService = { + getProfile, +} diff --git a/apps/studio/data/profile/profile-service.ts b/apps/studio/data/profile/profile-service.ts new file mode 100644 index 00000000000..2e49b44a725 --- /dev/null +++ b/apps/studio/data/profile/profile-service.ts @@ -0,0 +1,5 @@ +import type { Profile } from './types' + +export interface ProfileService { + getProfile: (signal?: AbortSignal) => Promise +} diff --git a/apps/studio/data/projects/project-detail-query.ts b/apps/studio/data/projects/project-detail-query.ts index 195155bb520..89cacc97018 100644 --- a/apps/studio/data/projects/project-detail-query.ts +++ b/apps/studio/data/projects/project-detail-query.ts @@ -1,11 +1,13 @@ import { QueryClient, useQuery, useQueryClient } from '@tanstack/react-query' import { useCallback } from 'react' -import type { components } from 'data/api' -import { get, handleError, isValidConnString } from 'data/fetchers' -import type { ResponseError, UseCustomQueryOptions } from 'types' import { projectKeys } from './keys' import { OrgProjectsResponse } from './org-projects-infinite-query' +import type { ProjectsService } from './projects-service' +import type { components } from '@/data/api' +import { get, handleError, isValidConnString } from '@/data/fetchers' +import { useService } from '@/lib/services/context' +import type { ResponseError, UseCustomQueryOptions } from '@/types' type ProjectDetailVariables = { ref?: string } export type ProjectDetail = components['schemas']['ProjectDetailResponse'] @@ -45,10 +47,12 @@ export const useProjectDetailQuery = ( enabled = true, ...options }: UseCustomQueryOptions = {} -) => - useQuery({ +) => { + const { getProjectDetail: fetchProjectDetail } = useService('projects') + + return useQuery({ queryKey: projectKeys.detail(ref), - queryFn: ({ signal }) => getProjectDetail({ ref }, signal), + queryFn: ({ signal }) => fetchProjectDetail({ ref }, signal), enabled: enabled && typeof ref !== 'undefined', staleTime: 30 * 1000, refetchInterval: (query) => { @@ -64,11 +68,16 @@ export const useProjectDetailQuery = ( }, ...options, }) +} -export function prefetchProjectDetail(client: QueryClient, { ref }: ProjectDetailVariables) { +export function prefetchProjectDetail( + client: QueryClient, + { ref }: ProjectDetailVariables, + service: { getProjectDetail: ProjectsService['getProjectDetail'] } +) { return client.fetchQuery({ queryKey: projectKeys.detail(ref), - queryFn: ({ signal }) => getProjectDetail({ ref }, signal), + queryFn: ({ signal }) => service.getProjectDetail({ ref }, signal), }) } diff --git a/apps/studio/data/projects/projects-service-live.ts b/apps/studio/data/projects/projects-service-live.ts new file mode 100644 index 00000000000..629fe13a79a --- /dev/null +++ b/apps/studio/data/projects/projects-service-live.ts @@ -0,0 +1,6 @@ +import { getProjectDetail } from './project-detail-query' +import type { ProjectsService } from './projects-service' + +export const projectsServiceLive: ProjectsService = { + getProjectDetail, +} diff --git a/apps/studio/data/projects/projects-service.ts b/apps/studio/data/projects/projects-service.ts new file mode 100644 index 00000000000..fc7cef01d6e --- /dev/null +++ b/apps/studio/data/projects/projects-service.ts @@ -0,0 +1,5 @@ +import type { Project } from './project-detail-query' + +export interface ProjectsService { + getProjectDetail: (params: { ref?: string }, signal?: AbortSignal) => Promise +} diff --git a/apps/studio/lib/services/live-registry.ts b/apps/studio/lib/services/live-registry.ts index b8cca41de65..04e07f4ac92 100644 --- a/apps/studio/lib/services/live-registry.ts +++ b/apps/studio/lib/services/live-registry.ts @@ -1,10 +1,18 @@ import { authServiceLive } from './auth-service' import { featureFlagServiceLive } from './feature-flag-service' import type { ServiceRegistry } from './registry' +import { organizationsServiceLive } from '@/data/organizations/organizations-service-live' +import { permissionsServiceLive } from '@/data/permissions/permissions-service-live' +import { profileServiceLive } from '@/data/profile/profile-service-live' +import { projectsServiceLive } from '@/data/projects/projects-service-live' export function createLiveRegistry(): ServiceRegistry { return { auth: authServiceLive, featureFlags: featureFlagServiceLive, + organizations: organizationsServiceLive, + permissions: permissionsServiceLive, + profile: profileServiceLive, + projects: projectsServiceLive, } } diff --git a/apps/studio/lib/services/registry.ts b/apps/studio/lib/services/registry.ts index 46b0c7a6629..1da0083c209 100644 --- a/apps/studio/lib/services/registry.ts +++ b/apps/studio/lib/services/registry.ts @@ -1,5 +1,9 @@ import type { AuthService } from './auth-service' import type { FeatureFlagService } from './feature-flag-service' +import type { OrganizationsService } from '@/data/organizations/organizations-service' +import type { PermissionsService } from '@/data/permissions/permissions-service' +import type { ProfileService } from '@/data/profile/profile-service' +import type { ProjectsService } from '@/data/projects/projects-service' /** * Central registry of all injectable services. @@ -9,4 +13,8 @@ import type { FeatureFlagService } from './feature-flag-service' export interface ServiceRegistry { auth: AuthService featureFlags: FeatureFlagService + organizations: OrganizationsService + permissions: PermissionsService + profile: ProfileService + projects: ProjectsService }