From fa4c629f7b7b97a5a0325a119ee5b1d1af45de82 Mon Sep 17 00:00:00 2001 From: psiddharthdesign <107192927+psiddharthdesign@users.noreply.github.com> Date: Tue, 30 Jul 2024 18:24:53 +0530 Subject: [PATCH] supabase realtime updates on digger runs --- .../@navbar/[...catchAll]/page.tsx | 3 - .../AllRunsDetails.tsx | 90 ++++++++++++++++++- .../(specific-project-pages)/page.tsx | 79 +--------------- .../runs/[runId]/ProjectRunDetails.tsx | 30 ++++++- src/data/user/tfvars.ts | 0 .../user/supabaseUserClientComponentClient.ts | 5 -- ...20240730102713_realtime-to-digger-runs.sql | 4 + 7 files changed, 123 insertions(+), 88 deletions(-) create mode 100644 src/data/user/tfvars.ts create mode 100644 supabase/migrations/20240730102713_realtime-to-digger-runs.sql diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/org/[organizationId]/(specific-organization-pages)/@navbar/[...catchAll]/page.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/org/[organizationId]/(specific-organization-pages)/@navbar/[...catchAll]/page.tsx index 425023f1..104a5d09 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/org/[organizationId]/(specific-organization-pages)/@navbar/[...catchAll]/page.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/org/[organizationId]/(specific-organization-pages)/@navbar/[...catchAll]/page.tsx @@ -11,9 +11,6 @@ import { Suspense } from 'react'; export async function generateMetadata({ params }: { params: unknown }) { try { const { organizationId } = organizationParamSchema.parse(params); - console.log('----------------------------------------') - console.log('in [...catchAll]/page organizationId', organizationId) - console.log('----------------------------------------') const organizationTitle = await getOrganizationTitle(organizationId); return { diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/AllRunsDetails.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/AllRunsDetails.tsx index ab0fb901..f5b99b1d 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/AllRunsDetails.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/AllRunsDetails.tsx @@ -1,11 +1,95 @@ 'use client'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Tables } from "@/lib/database.types"; +import { Skeleton } from "@/components/ui/skeleton"; +import { getRunsByProjectId } from "@/data/user/runs"; +import { supabaseUserClientComponentClient } from "@/supabase-clients/user/supabaseUserClientComponentClient"; +import { useQuery } from "@tanstack/react-query"; import { motion } from "framer-motion"; +import { useEffect } from "react"; import { AllRunsTable } from "./AllRunsTable"; -export default function AllRunsDetails({ runs, project }: { runs: Tables<'digger_runs'>[], project: Tables<'projects'> }) { +export default function AllRunsDetails({ + projectId, + projectSlug +}: { + projectId: string; + projectSlug: string; +}) { + + const { data: runs, refetch, isLoading } = useQuery( + ['runs', projectId], + async () => { + return getRunsByProjectId(projectId); + }, + { + refetchOnWindowFocus: false, + } + ); + + useEffect(() => { + const channel = supabaseUserClientComponentClient + .channel('digger_runs_realtime') + .on( + 'postgres_changes', + { + event: 'INSERT', + schema: 'public', + table: 'digger_runs', + filter: `project_id=eq.${projectId}` + }, + (payload) => { + refetch(); + } + ) + .on( + 'postgres_changes', + { + event: 'UPDATE', + schema: 'public', + table: 'digger_runs', + filter: `project_id=eq.${projectId}` + }, + (payload) => { + refetch(); + }, + ) + .subscribe(); + + return () => { + channel.unsubscribe(); + }; + }, [projectId, refetch]); + + if (isLoading) { + return ( +
+
+ {[...Array(3)].map((_, index) => ( +
+ + + + +
+ ))} +
+
+ ); + } + + if (!runs) { + return + + Project Runs + View all runs for this project + + +

No runs found

+
+
+ } + return ( - + diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/page.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/page.tsx index 5c4d5a5a..a559a4a5 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/page.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/page.tsx @@ -1,8 +1,7 @@ - - -import { getProjectById, getSlimProjectBySlug } from "@/data/user/projects"; +import { getSlimProjectBySlug } from "@/data/user/projects"; import { projectSlugParamSchema } from "@/utils/zod-schemas/params"; import type { Metadata } from "next"; +import AllRunsDetails from "./AllRunsDetails"; type ProjectPageProps = { params: { @@ -22,84 +21,14 @@ export async function generateMetadata({ }; } - -import { getRunsByProjectId } from "@/data/user/runs"; -import AllRunsDetails from "./AllRunsDetails"; - -// const dummyRuns: Run[] = [ -// { -// runId: "run-001", -// commitId: "abc123", -// status: "queued", -// date: "2023-06-01", -// user: "Alice" -// }, -// { -// runId: "run-002", -// commitId: "def456", -// status: "pending approval", -// date: "2023-06-02", -// user: "Bob" -// }, -// { -// runId: "run-003", -// commitId: "ghi789", -// status: "running", -// date: "2023-06-03", -// user: "Charlie" -// }, -// { -// runId: "run-004", -// commitId: "jkl012", -// status: "approved", -// date: "2023-06-04", -// user: "Diana" -// }, -// { -// runId: "run-005", -// commitId: "mno345", -// status: "succeeded", -// date: "2023-06-05", -// user: "Ethan" -// }, -// { -// runId: "run-006", -// commitId: "pqr678", -// status: "failed", -// date: "2023-06-06", -// user: "Fiona" -// }, -// { -// runId: "run-007", -// commitId: "stu901", -// status: "queued", -// date: "2023-06-07", -// user: "George" -// }, -// { -// runId: "run-008", -// commitId: "vwx234", -// status: "running", -// date: "2023-06-08", -// user: "Hannah" -// } -// ]; - -// const runs = dummyRuns; - - export default async function ProjectPage({ params }: { params: unknown }) { const { projectSlug } = projectSlugParamSchema.parse(params); const slimProject = await getSlimProjectBySlug(projectSlug); - const project = await getProjectById(slimProject.id); - const runs = await getRunsByProjectId(slimProject.id); + return (
- +
); }; \ No newline at end of file diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/runs/[runId]/ProjectRunDetails.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/runs/[runId]/ProjectRunDetails.tsx index 316c2909..dbc5b1c1 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/runs/[runId]/ProjectRunDetails.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/runs/[runId]/ProjectRunDetails.tsx @@ -8,6 +8,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/comp import { approveRun, rejectRun } from "@/data/user/runs"; import { useSAToastMutation } from "@/hooks/useSAToastMutation"; import { ToSnakeCase, ToTitleCase } from "@/lib/utils"; +import { supabaseUserClientComponentClient } from "@/supabase-clients/user/supabaseUserClientComponentClient"; import { Table } from "@/types"; import { DotFilledIcon } from "@radix-ui/react-icons"; import { AnimatePresence, motion } from 'framer-motion'; @@ -15,7 +16,7 @@ import { CheckCircle2, Clock, GitPullRequest, LinkIcon, Loader2, Play, XCircle } import Image from 'next/image'; import Link from "next/link"; import { useRouter } from 'next/navigation'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { statusColors } from "../../(specific-project-pages)/AllRunsTable"; @@ -121,7 +122,7 @@ export const ProjectRunDetails: React.FC<{ applyTerraformOutput: string | null applyWorkflowRunUrl: string | null fullRepoName: string | null -}> = ({ run, loggedInUser, isUserOrgAdmin, tfOutput, workflowRunUrl, applyTerraformOutput, applyWorkflowRunUrl, fullRepoName }) => { +}> = ({ run: initialRun, loggedInUser, isUserOrgAdmin, tfOutput, workflowRunUrl, applyTerraformOutput, applyWorkflowRunUrl, fullRepoName }) => { const router = useRouter(); const [activeStage, setActiveStage] = useState<'plan' | 'apply'>('plan'); @@ -149,6 +150,31 @@ export const ProjectRunDetails: React.FC<{ } ); + const [run, setRun] = useState(initialRun); + + + useEffect(() => { + const channel = supabaseUserClientComponentClient + .channel(`digger_run_${run.id}`) + .on( + 'postgres_changes', + { + event: 'UPDATE', + schema: 'public', + table: 'digger_runs', + filter: `id=eq.${run.id}` + }, + (payload) => { + setRun(payload.new as Table<'digger_runs'>); + } + ) + .subscribe(); + + return () => { + supabaseUserClientComponentClient.removeChannel(channel); + }; + }, [run.id]); + return (
({ - options: { - global: { - fetch, - }, - }, cookieOptions: optionalCookieOptions, }); diff --git a/supabase/migrations/20240730102713_realtime-to-digger-runs.sql b/supabase/migrations/20240730102713_realtime-to-digger-runs.sql new file mode 100644 index 00000000..cf9e156f --- /dev/null +++ b/supabase/migrations/20240730102713_realtime-to-digger-runs.sql @@ -0,0 +1,4 @@ + ALTER PUBLICATION supabase_realtime ADD TABLE public.digger_runs; + ALTER TABLE public.digger_runs REPLICA IDENTITY FULL; + +CREATE INDEX ON digger_runs (project_id); \ No newline at end of file