Home / Function/ CronjobsTab() — supabase Function Reference

CronjobsTab() — supabase Function Reference

Architecture documentation for the CronjobsTab() function in CronJobsTab.tsx from the supabase codebase.

Entity Profile

Dependency Diagram

graph TD
  4aa23104_375b_2179_f30c_8719c622dc59["CronjobsTab()"]
  d91e1395_336c_8cc8_1c97_273b3e7449f5["useCronJobsData()"]
  4aa23104_375b_2179_f30c_8719c622dc59 -->|calls| d91e1395_336c_8cc8_1c97_273b3e7449f5
  48ed8408_4785_11cd_f1ca_334a6290780f["formatCronJobColumns()"]
  4aa23104_375b_2179_f30c_8719c622dc59 -->|calls| 48ed8408_4785_11cd_f1ca_334a6290780f
  style 4aa23104_375b_2179_f30c_8719c622dc59 fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx lines 30–229

export const CronjobsTab = () => {
  const router = useRouter()
  const { ref } = useParams()
  const { data: project } = useSelectedProjectQuery()
  const { data: org } = useSelectedOrganizationQuery()

  const [searchQuery, setSearchQuery] = useQueryState('search', parseAsString.withDefault(''))
  const [search, setSearch] = useState(searchQuery)

  const handleSearchSubmit = () => {
    const trimmed = search.trim()
    setSearchQuery(trimmed.length > 0 ? trimmed : null)
  }
  const handleClearSearch = () => {
    setSearch('')
    setSearchQuery(null)
  }

  const { grid, count } = useCronJobsData({
    projectRef: project?.ref,
    connectionString: project?.connectionString,
    searchQuery,
  })

  const deletingCronJobIdRef = useRef<string | null>(null)

  const { setValue: setCronJobForEditing, value: cronJobForEditing } = useQueryStateWithSelect({
    urlKey: 'edit',
    select: (jobid: string) => {
      if (!jobid) return undefined
      const job = grid.rows.find((j) => j.jobid.toString() === jobid)
      return job
        ? { jobname: job.jobname, schedule: job.schedule, active: job.active, command: job.command }
        : undefined
    },
    enabled: grid.rows.length > 0 && !grid.isLoading,
    onError: () => toast.error(`Cron job not found`),
  })

  const { setValue: setCronJobForDeletion, value: cronJobForDeletion } = useQueryStateWithSelect({
    urlKey: 'delete',
    select: (jobid: string) =>
      jobid ? grid.rows.find((j) => j.jobid.toString() === jobid) : undefined,
    enabled: grid.rows.length > 0 && !grid.isLoading,
    onError: (_error, selectedId) =>
      handleErrorOnDelete(deletingCronJobIdRef, selectedId, `Cron job not found`),
  })

  const { data: extensions = [] } = useDatabaseExtensionsQuery({
    projectRef: project?.ref,
    connectionString: project?.connectionString,
  })

  const pgCronExtension = extensions.find((ext) => ext.name === 'pg_cron')
  const supportsSeconds = pgCronExtension?.installed_version
    ? isGreaterThanOrEqual(pgCronExtension.installed_version, '1.5')
    : false

  const { mutate: sendEvent } = useSendEventMutation()

  const columns = useMemo(
    () =>
      formatCronJobColumns({
        onSelectEdit: (job: CronJob) => {
          sendEvent({
            action: 'cron_job_update_clicked',
            groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
          })
          setCronJobForEditing(job.jobid.toString())
        },
        onSelectDelete: (job: CronJob) => {
          sendEvent({
            action: 'cron_job_delete_clicked',
            groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
          })
          setCronJobForDeletion(job.jobid.toString())
        },
      }),
    [org?.slug, ref, sendEvent, setCronJobForEditing, setCronJobForDeletion]
  )

  const xScroll = useRef<number>(0)

  const handleScroll = (event: UIEvent<HTMLDivElement>) => {
    const isScrollingHorizontally = xScroll.current !== event.currentTarget.scrollLeft
    xScroll.current = event.currentTarget.scrollLeft

    if (
      grid.isLoading ||
      grid.isFetchingNextPage ||
      isScrollingHorizontally ||
      !isAtBottom(event) ||
      !grid.hasNextPage
    ) {
      return
    }

    grid.fetchNextPage()
  }

  // Create job sheet
  const [createCronJobSheetShown, setCreateCronJobSheetShown] = useQueryState(
    'new',
    parseAsBoolean.withDefault(false).withOptions({ clearOnDefault: true })
  )

  const onOpenCreateJobSheet = () => {
    sendEvent({
      action: 'cron_job_create_clicked',
      groups: { project: project?.ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
    })
    setCreateCronJobSheetShown(true)
  }

  // Row click handler
  const handleRowClick = (row: CronJob, event: MouseEvent<HTMLDivElement>) => {
    const { jobid, jobname } = row
    const url = `/project/${ref}/integrations/cron/jobs/${jobid}?child-label=${encodeURIComponent(
      jobname || `Job #${jobid}`
    )}`

    sendEvent({
      action: 'cron_job_history_clicked',
      groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
    })

    createNavigationHandler(url, router)(event)
  }

  const [isDirty, setIsDirty] = useState(false)
  const onClose = () => {
    setCronJobForEditing(null)
    setCreateCronJobSheetShown(false)
    cleanPointerEventsNoneOnBody(500)
  }
  const { confirmOnClose, modalProps: closeConfirmationModalProps } = useConfirmOnClose({
    checkIsDirty: () => isDirty,
    onClose: () => {
      setIsDirty(false)
      onClose()
    },
  })

  return (
    <>
      <div className="h-full w-full space-y-4">
        <div className="h-full w-full flex flex-col relative">
          <CronJobsTabHeader
            search={search}
            isRefreshing={grid.isRefetching && !grid.isFetchingNextPage}
            onSearchChange={setSearch}
            onSearchSubmit={handleSearchSubmit}
            onClearSearch={handleClearSearch}
            onRefresh={grid.refetch}
            onCreateJob={onOpenCreateJobSheet}
          />
          <LoadingLine loading={grid.isLoading || grid.isRefetching || grid.isFetchingNextPage} />
          {grid.isMinimal && <CronJobRunDetailsOverflowNoticeV2 refetchJobs={grid.refetch} />}
          <CronJobsTabDataGrid
            columns={columns}
            rows={grid.rows}
            isLoading={grid.isLoading}
            error={grid.error}
            searchQuery={searchQuery}
            onScroll={handleScroll}
            onRowClick={handleRowClick}
          />
          <CronJobsFooter count={count} />
        </div>
      </div>

      {cronJobForDeletion && (
        <DeleteCronJob
          visible={!!cronJobForDeletion}
          onClose={() => {
            deletingCronJobIdRef.current = null
            setCronJobForDeletion(null)
          }}
          onDeleteStart={(jobId) => {
            deletingCronJobIdRef.current = jobId
          }}
          cronJob={cronJobForDeletion}
        />
      )}

      <Sheet open={!!createCronJobSheetShown || !!cronJobForEditing} onOpenChange={confirmOnClose}>
        <SheetContent size="default" tabIndex={undefined}>
          <CreateCronJobSheet
            selectedCronJob={cronJobForEditing ?? EMPTY_CRON_JOB}
            supportsSeconds={supportsSeconds}
            onDirty={setIsDirty}
            onClose={onClose}
            onCloseWithConfirmation={confirmOnClose}
          />
        </SheetContent>
      </Sheet>
      <CloseConfirmationModal {...closeConfirmationModalProps} />
    </>
  )
}

Subdomains

Frequently Asked Questions

What does CronjobsTab() do?
CronjobsTab() is a function in the supabase codebase.
What does CronjobsTab() call?
CronjobsTab() calls 2 function(s): formatCronJobColumns, useCronJobsData.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free