mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 09:55:06 +03:00
Chore/cron fixes (#37626)
* Fix query to fetch cron jobs resulting in duplicate if job previous run succeeded, but latest failed * Fix integration tabs child label * Add a key to the rows in the data grid. * Fix the small loading state when clicking the create cron job button. * Wrap try catch around getDatabaseCronJob when validating cron job name --------- Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
This commit is contained in:
1 parent
5e3518ffd6
commit
310d2d575f
5 files changed
+48
-24
No files matched your search
@@ -203,6 +203,7 @@ export const CreateCronJobSheet = ({
|
||||
const { project } = useProjectContext()
|
||||
const { data: org } = useSelectedOrganizationQuery()
|
||||
const [searchQuery] = useQueryState('search', parseAsString.withDefault(''))
|
||||
const [isLoadingGetCronJob, setIsLoadingGetCronJob] = useState(false)
|
||||
|
||||
const isEditing = !!selectedCronJob?.jobname
|
||||
const [showEnableExtensionModal, setShowEnableExtensionModal] = useState(false)
|
||||
@@ -215,7 +216,8 @@ export const CreateCronJobSheet = ({
|
||||
const pgNetExtensionInstalled = pgNetExtension?.installed_version != undefined
|
||||
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
const { mutate: upsertCronJob, isLoading } = useDatabaseCronJobCreateMutation()
|
||||
const { mutate: upsertCronJob, isLoading: isUpserting } = useDatabaseCronJobCreateMutation()
|
||||
const isLoading = isLoadingGetCronJob || isUpserting
|
||||
|
||||
const canToggleExtensions = useCheckPermissions(
|
||||
PermissionAction.TENANT_SQL_ADMIN_WRITE,
|
||||
@@ -306,18 +308,25 @@ export const CreateCronJobSheet = ({
|
||||
if (!project) return console.error('Project is required')
|
||||
|
||||
if (!isEditing) {
|
||||
const checkExistingJob = await getDatabaseCronJob({
|
||||
projectRef: project.ref,
|
||||
connectionString: project.connectionString,
|
||||
name,
|
||||
})
|
||||
const nameExists = !!checkExistingJob
|
||||
|
||||
if (nameExists) {
|
||||
return form.setError('name', {
|
||||
type: 'manual',
|
||||
message: 'A cron job with this name already exists',
|
||||
try {
|
||||
setIsLoadingGetCronJob(true)
|
||||
const checkExistingJob = await getDatabaseCronJob({
|
||||
projectRef: project.ref,
|
||||
connectionString: project.connectionString,
|
||||
name,
|
||||
})
|
||||
const nameExists = !!checkExistingJob
|
||||
|
||||
if (nameExists) {
|
||||
return form.setError('name', {
|
||||
type: 'manual',
|
||||
message: 'A cron job with this name already exists',
|
||||
})
|
||||
}
|
||||
} catch (error: any) {
|
||||
toast.error(`Failed to validate cron job name: ${error.message}`)
|
||||
} finally {
|
||||
setIsLoadingGetCronJob(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,6 +378,7 @@ export const CreateCronJobSheet = ({
|
||||
},
|
||||
}
|
||||
)
|
||||
setIsLoadingGetCronJob(false)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -193,9 +193,10 @@ export const CronjobsTab = () => {
|
||||
}}
|
||||
onScroll={handleScroll}
|
||||
renderers={{
|
||||
renderRow(_, props) {
|
||||
renderRow(key, props) {
|
||||
return (
|
||||
<Row
|
||||
key={props.row.jobid}
|
||||
{...props}
|
||||
onClick={(e) => {
|
||||
const { jobid, jobname } = props.row
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { PropsWithChildren, useEffect, useRef, useState } from 'react'
|
||||
|
||||
import { IntegrationDefinition } from 'components/interfaces/Integrations/Landing/Integrations.constants'
|
||||
import { useInstalledIntegrations } from 'components/interfaces/Integrations/Landing/useInstalledIntegrations'
|
||||
import { Header } from 'components/layouts/Integrations/header'
|
||||
import ProjectLayout from 'components/layouts/ProjectLayout/ProjectLayout'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { ProductMenu } from 'components/ui/ProductMenu'
|
||||
import { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types'
|
||||
import ProductMenuItem from 'components/ui/ProductMenu/ProductMenuItem'
|
||||
import { useScroll } from 'framer-motion'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useSelectedProject, useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { withAuth } from 'hooks/misc/withAuth'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { IntegrationTabs } from './tabs'
|
||||
import { Menu, Separator } from 'ui'
|
||||
import ProductMenuItem from 'components/ui/ProductMenu/ProductMenuItem'
|
||||
import { GenericSkeletonLoader } from 'ui-patterns'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { IntegrationTabs } from './tabs'
|
||||
|
||||
/**
|
||||
* Layout component for the Integrations section
|
||||
@@ -156,7 +155,7 @@ const IntegrationTopHeaderLayout = ({ ...props }: PropsWithChildren) => {
|
||||
const IntegrationsLayoutSide = ({ ...props }: PropsWithChildren) => {
|
||||
const router = useRouter()
|
||||
const page = router.pathname.split('/')[4]
|
||||
const project = useSelectedProject()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const {
|
||||
installedIntegrations: integrations,
|
||||
|
||||
@@ -97,7 +97,9 @@ export const IntegrationTabs = ({ scroll, isSticky }: IntegrationTabsProps) => {
|
||||
>
|
||||
<NavMenuItem active={true} className="flex items-center gap-2">
|
||||
{tab.childIcon}
|
||||
<Link href={`${tabUrl}/${childId}`}>
|
||||
<Link
|
||||
href={`${tabUrl}/${childId}${childLabel ? `?child-label=${childLabel}` : ''}`}
|
||||
>
|
||||
{childLabel ? childLabel : childId}
|
||||
</Link>
|
||||
</NavMenuItem>
|
||||
|
||||
@@ -22,6 +22,7 @@ export type CronJob = {
|
||||
status: string
|
||||
}
|
||||
|
||||
// [Joshen] Just to call out that I had AI help me with this, so please let me know if this can be optimized
|
||||
const getCronJobSql = ({ searchTerm, page }: { searchTerm?: string; page: number }) =>
|
||||
`
|
||||
WITH latest_runs AS (
|
||||
@@ -31,6 +32,17 @@ WITH latest_runs AS (
|
||||
MAX(start_time) AS latest_run
|
||||
FROM cron.job_run_details
|
||||
GROUP BY jobid, status
|
||||
), most_recent_runs AS (
|
||||
SELECT
|
||||
jobid,
|
||||
status,
|
||||
latest_run
|
||||
FROM latest_runs lr1
|
||||
WHERE latest_run = (
|
||||
SELECT MAX(latest_run)
|
||||
FROM latest_runs lr2
|
||||
WHERE lr2.jobid = lr1.jobid
|
||||
)
|
||||
)
|
||||
SELECT
|
||||
job.jobid,
|
||||
@@ -38,13 +50,13 @@ SELECT
|
||||
job.schedule,
|
||||
job.command,
|
||||
job.active,
|
||||
lr.latest_run,
|
||||
lr.status
|
||||
mr.latest_run,
|
||||
mr.status
|
||||
FROM
|
||||
cron.job job
|
||||
LEFT JOIN latest_runs lr ON job.jobid = lr.jobid
|
||||
${!!searchTerm ? `WHERE job.jobname ILIKE '%${searchTerm}%'` : ''}
|
||||
LEFT JOIN most_recent_runs mr ON job.jobid = mr.jobid
|
||||
ORDER BY job.jobid
|
||||
${!!searchTerm ? `WHERE job.jobname ILIKE '%${searchTerm}%'` : ''}
|
||||
LIMIT ${CRON_JOBS_PAGE_LIMIT}
|
||||
OFFSET ${page * CRON_JOBS_PAGE_LIMIT};
|
||||
`.trim()
|
||||
|
||||
Reference in new issue
Block a user