diff --git a/apps/studio/components/interfaces/Home/ServiceStatus.tsx b/apps/studio/components/interfaces/Home/ServiceStatus.tsx
index 146c58ef5a0..46f466f1ec4 100644
--- a/apps/studio/components/interfaces/Home/ServiceStatus.tsx
+++ b/apps/studio/components/interfaces/Home/ServiceStatus.tsx
@@ -17,6 +17,7 @@ import {
Popover_Shadcn_,
} from 'ui'
import { PopoverSeparator } from '@ui/components/shadcn/ui/popover'
+import { useProjectEventsQuery } from 'data/project-events/project-events-query'
const SERVICE_STATUS_THRESHOLD = 5 // minutes
@@ -30,7 +31,7 @@ const StatusMessage = ({
isProjectNew: boolean
}) => {
if (isLoading) return 'Checking status'
- if (isProjectNew) return 'Coming up...'
+ if (isProjectNew && !isSuccess) return 'Coming up...'
if (isSuccess) return 'No issues'
return 'Unable to connect'
}
@@ -44,7 +45,9 @@ const StatusIcon = ({
isSuccess: boolean
isProjectNew: boolean
}) => {
- if (isLoading || isProjectNew) return
+ if (isLoading) return
+ if (isProjectNew && !isSuccess)
+ return
if (isSuccess) return
return
}
@@ -168,40 +171,40 @@ const ServiceStatus = () => {
const isLoadingChecks = services.some((service) => service.isLoading)
const allServicesOperational = services.every((service) => service.isSuccess)
- // If the project is less than 5 minutes old, and status is not operational, then it's likely the service is still starting up
- const isProjectNew =
+ const [dateRange] = useState<{ startDate: string; endDate: string }>({
+ startDate: dayjs().subtract(30, 'minute').toISOString(),
+ endDate: dayjs().toISOString(),
+ })
+
+ const { data: restoreProjectEvents, isLoading: projectEventsLoading } = useProjectEventsQuery({
+ ref,
+ startDate: dateRange.startDate,
+ endDate: dateRange.endDate,
+ eventTypes: [
+ 'project.infra_restart_or_resize_initiated',
+ 'project.restore_initiated',
+ 'project.restored_from_logical_backup',
+ 'project.restored_from_pitr',
+ ],
+ })
+
+ console.log('events', restoreProjectEvents)
+
+ const projectWasRestoredRecently = !projectEventsLoading && !!restoreProjectEvents?.length
+
+ // If the project is less than SERVICE_STATUS_THRESHOLD minutes old, and status is not operational, then it's likely the service is still starting up
+ const isProjectNewOrRestoredRecently =
+ projectWasRestoredRecently ||
dayjs.utc().diff(dayjs.utc(project?.inserted_at), 'minute') < SERVICE_STATUS_THRESHOLD ||
project?.status === 'COMING_UP'
- useEffect(() => {
- let timer: any
-
- if (isProjectNew) {
- const secondsSinceProjectCreated = dayjs
- .utc()
- .diff(dayjs.utc(project?.inserted_at), 'seconds')
- const remainingTimeTillNextCheck = SERVICE_STATUS_THRESHOLD * 60 - secondsSinceProjectCreated
-
- timer = setTimeout(() => {
- refetchServiceStatus()
- refetchPostgresServiceStatus()
- refetchEdgeFunctionServiceStatus()
- }, remainingTimeTillNextCheck * 1000)
- }
-
- return () => {
- clearTimeout(timer)
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [isProjectNew])
-
return (
) : (
{
{service.name}
@@ -234,7 +237,7 @@ const ServiceStatus = () => {
diff --git a/apps/studio/data/project-events/keys.ts b/apps/studio/data/project-events/keys.ts
new file mode 100644
index 00000000000..dedec09a85d
--- /dev/null
+++ b/apps/studio/data/project-events/keys.ts
@@ -0,0 +1,9 @@
+export const projectEventsKeys = {
+ list: (
+ ref?: string,
+ startDate?: string,
+ endDate?: string,
+ eventTypes?: string[],
+ limit?: number
+ ) => ['projects', ref, 'events', startDate, endDate, eventTypes, limit] as const,
+}
diff --git a/apps/studio/data/project-events/project-events-query.ts b/apps/studio/data/project-events/project-events-query.ts
new file mode 100644
index 00000000000..ee934363057
--- /dev/null
+++ b/apps/studio/data/project-events/project-events-query.ts
@@ -0,0 +1,46 @@
+import { useQuery, UseQueryOptions } from '@tanstack/react-query'
+
+import type { components } from 'data/api'
+import { get, handleError } from 'data/fetchers'
+import type { ResponseError } from 'types'
+import { projectEventsKeys } from './keys'
+
+export type ProjectEventsVariables = {
+ ref?: string
+ startDate?: string
+ endDate?: string
+ eventTypes?: string[]
+ limit?: number
+}
+
+export type ProjectSecret = components['schemas']['SecretResponse']
+
+export async function getProjectEvents(
+ { ref, startDate, endDate, eventTypes, limit }: ProjectEventsVariables,
+ signal?: AbortSignal
+) {
+ if (!ref) throw new Error('Project ref is required')
+
+ const { data, error } = await get(`/v1/projects/{ref}/events`, {
+ params: { path: { ref }, query: { startDate, endDate, eventTypes, limit } },
+ signal,
+ })
+
+ if (error) handleError(error)
+
+ // TODO: undo type cast when API types are updated
+ return data as { event_type: string; inserted_at: string }[]
+}
+
+export type ProjectEventsData = Awaited
>
+export type ProjectEventsError = ResponseError
+
+export const useProjectEventsQuery = (
+ { ref, startDate, endDate, eventTypes, limit }: ProjectEventsVariables,
+ { enabled = true, ...options }: UseQueryOptions = {}
+) =>
+ useQuery(
+ projectEventsKeys.list(ref, startDate, endDate, eventTypes, limit),
+ ({ signal }) => getProjectEvents({ ref, startDate, endDate, eventTypes, limit }, signal),
+ { enabled: enabled && typeof ref !== 'undefined', ...options }
+ )