Skip to content

Commit 310d2d5

Browse files
joshenlimivasilov
andauthored
Chore/cron fixes (supabase#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 <[email protected]>
1 parent 5e3518f commit 310d2d5

File tree

5 files changed

+48
-24
lines changed

5 files changed

+48
-24
lines changed

apps/studio/components/interfaces/Integrations/CronJobs/CreateCronJobSheet.tsx

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ export const CreateCronJobSheet = ({
203203
const { project } = useProjectContext()
204204
const { data: org } = useSelectedOrganizationQuery()
205205
const [searchQuery] = useQueryState('search', parseAsString.withDefault(''))
206+
const [isLoadingGetCronJob, setIsLoadingGetCronJob] = useState(false)
206207

207208
const isEditing = !!selectedCronJob?.jobname
208209
const [showEnableExtensionModal, setShowEnableExtensionModal] = useState(false)
@@ -215,7 +216,8 @@ export const CreateCronJobSheet = ({
215216
const pgNetExtensionInstalled = pgNetExtension?.installed_version != undefined
216217

217218
const { mutate: sendEvent } = useSendEventMutation()
218-
const { mutate: upsertCronJob, isLoading } = useDatabaseCronJobCreateMutation()
219+
const { mutate: upsertCronJob, isLoading: isUpserting } = useDatabaseCronJobCreateMutation()
220+
const isLoading = isLoadingGetCronJob || isUpserting
219221

220222
const canToggleExtensions = useCheckPermissions(
221223
PermissionAction.TENANT_SQL_ADMIN_WRITE,
@@ -306,18 +308,25 @@ export const CreateCronJobSheet = ({
306308
if (!project) return console.error('Project is required')
307309

308310
if (!isEditing) {
309-
const checkExistingJob = await getDatabaseCronJob({
310-
projectRef: project.ref,
311-
connectionString: project.connectionString,
312-
name,
313-
})
314-
const nameExists = !!checkExistingJob
315-
316-
if (nameExists) {
317-
return form.setError('name', {
318-
type: 'manual',
319-
message: 'A cron job with this name already exists',
311+
try {
312+
setIsLoadingGetCronJob(true)
313+
const checkExistingJob = await getDatabaseCronJob({
314+
projectRef: project.ref,
315+
connectionString: project.connectionString,
316+
name,
320317
})
318+
const nameExists = !!checkExistingJob
319+
320+
if (nameExists) {
321+
return form.setError('name', {
322+
type: 'manual',
323+
message: 'A cron job with this name already exists',
324+
})
325+
}
326+
} catch (error: any) {
327+
toast.error(`Failed to validate cron job name: ${error.message}`)
328+
} finally {
329+
setIsLoadingGetCronJob(false)
321330
}
322331
}
323332

@@ -369,6 +378,7 @@ export const CreateCronJobSheet = ({
369378
},
370379
}
371380
)
381+
setIsLoadingGetCronJob(false)
372382
}
373383

374384
return (

apps/studio/components/interfaces/Integrations/CronJobs/CronJobsTab.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,10 @@ export const CronjobsTab = () => {
193193
}}
194194
onScroll={handleScroll}
195195
renderers={{
196-
renderRow(_, props) {
196+
renderRow(key, props) {
197197
return (
198198
<Row
199+
key={props.row.jobid}
199200
{...props}
200201
onClick={(e) => {
201202
const { jobid, jobname } = props.row

apps/studio/components/layouts/Integrations/layout.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
import { useRouter } from 'next/router'
22
import { PropsWithChildren, useEffect, useRef, useState } from 'react'
33

4-
import { IntegrationDefinition } from 'components/interfaces/Integrations/Landing/Integrations.constants'
54
import { useInstalledIntegrations } from 'components/interfaces/Integrations/Landing/useInstalledIntegrations'
65
import { Header } from 'components/layouts/Integrations/header'
76
import ProjectLayout from 'components/layouts/ProjectLayout/ProjectLayout'
7+
import AlertError from 'components/ui/AlertError'
88
import { ProductMenu } from 'components/ui/ProductMenu'
99
import { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types'
10+
import ProductMenuItem from 'components/ui/ProductMenu/ProductMenuItem'
1011
import { useScroll } from 'framer-motion'
11-
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
12+
import { useSelectedProject, useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
1213
import { withAuth } from 'hooks/misc/withAuth'
1314
import { useFlag } from 'hooks/ui/useFlag'
14-
import { IntegrationTabs } from './tabs'
1515
import { Menu, Separator } from 'ui'
16-
import ProductMenuItem from 'components/ui/ProductMenu/ProductMenuItem'
1716
import { GenericSkeletonLoader } from 'ui-patterns'
18-
import AlertError from 'components/ui/AlertError'
17+
import { IntegrationTabs } from './tabs'
1918

2019
/**
2120
* Layout component for the Integrations section
@@ -156,7 +155,7 @@ const IntegrationTopHeaderLayout = ({ ...props }: PropsWithChildren) => {
156155
const IntegrationsLayoutSide = ({ ...props }: PropsWithChildren) => {
157156
const router = useRouter()
158157
const page = router.pathname.split('/')[4]
159-
const project = useSelectedProject()
158+
const { data: project } = useSelectedProjectQuery()
160159

161160
const {
162161
installedIntegrations: integrations,

apps/studio/components/layouts/Integrations/tabs.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ export const IntegrationTabs = ({ scroll, isSticky }: IntegrationTabsProps) => {
9797
>
9898
<NavMenuItem active={true} className="flex items-center gap-2">
9999
{tab.childIcon}
100-
<Link href={`${tabUrl}/${childId}`}>
100+
<Link
101+
href={`${tabUrl}/${childId}${childLabel ? `?child-label=${childLabel}` : ''}`}
102+
>
101103
{childLabel ? childLabel : childId}
102104
</Link>
103105
</NavMenuItem>

apps/studio/data/database-cron-jobs/database-cron-jobs-infinite-query.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type CronJob = {
2222
status: string
2323
}
2424

25+
// [Joshen] Just to call out that I had AI help me with this, so please let me know if this can be optimized
2526
const getCronJobSql = ({ searchTerm, page }: { searchTerm?: string; page: number }) =>
2627
`
2728
WITH latest_runs AS (
@@ -31,20 +32,31 @@ WITH latest_runs AS (
3132
MAX(start_time) AS latest_run
3233
FROM cron.job_run_details
3334
GROUP BY jobid, status
35+
), most_recent_runs AS (
36+
SELECT
37+
jobid,
38+
status,
39+
latest_run
40+
FROM latest_runs lr1
41+
WHERE latest_run = (
42+
SELECT MAX(latest_run)
43+
FROM latest_runs lr2
44+
WHERE lr2.jobid = lr1.jobid
45+
)
3446
)
3547
SELECT
3648
job.jobid,
3749
job.jobname,
3850
job.schedule,
3951
job.command,
4052
job.active,
41-
lr.latest_run,
42-
lr.status
53+
mr.latest_run,
54+
mr.status
4355
FROM
4456
cron.job job
45-
LEFT JOIN latest_runs lr ON job.jobid = lr.jobid
46-
${!!searchTerm ? `WHERE job.jobname ILIKE '%${searchTerm}%'` : ''}
57+
LEFT JOIN most_recent_runs mr ON job.jobid = mr.jobid
4758
ORDER BY job.jobid
59+
${!!searchTerm ? `WHERE job.jobname ILIKE '%${searchTerm}%'` : ''}
4860
LIMIT ${CRON_JOBS_PAGE_LIMIT}
4961
OFFSET ${page * CRON_JOBS_PAGE_LIMIT};
5062
`.trim()

0 commit comments

Comments
 (0)