-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
453 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 127 additions & 0 deletions
127
...pages)/org/[organizationId]/(specific-organization-pages)/activity/AllActivityDetails.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
'use client'; | ||
|
||
import { getRunsByProjectId } from "@/data/user/runs"; | ||
import { supabaseUserClientComponentClient } from "@/supabase-clients/user/supabaseUserClientComponentClient"; | ||
import { useQuery } from "@tanstack/react-query"; | ||
import { useEffect } from "react"; | ||
|
||
export default function AllActivityDetails({ | ||
projectId, | ||
projectSlug | ||
}: { | ||
projectId: string; | ||
projectSlug: string; | ||
}) { | ||
|
||
const { data: runs, refetch, isLoading } = useQuery( | ||
['runs', projectId], | ||
async () => { | ||
console.log('runs fetching'); | ||
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 ( | ||
<div className="w-full"> | ||
<div className="space-y-4"> | ||
{[...Array(3)].map((_, index) => ( | ||
<div key={index} className="flex space-x-4"> | ||
<Skeleton className="h-12 w-1/4" /> | ||
<Skeleton className="h-12 w-1/4" /> | ||
<Skeleton className="h-12 w-1/4" /> | ||
<Skeleton className="h-12 w-1/4" /> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
} | ||
if (!runs) { | ||
return <Card> | ||
<CardHeader> | ||
<CardTitle>Project Runs</CardTitle> | ||
<CardDescription>View all runs for this project</CardDescription> | ||
</CardHeader> | ||
<CardContent> | ||
<p>No runs found</p> | ||
</CardContent> | ||
</Card> | ||
} | ||
return ( | ||
<motion.div | ||
initial={{ opacity: 0, y: 10 }} | ||
animate={{ opacity: 1, y: 0 }} | ||
exit={{ opacity: 0, y: -10 }} | ||
transition={{ duration: 0.1 }} | ||
> | ||
<Card className="w-full"> | ||
<motion.div | ||
initial={{ opacity: 0, y: -5 }} | ||
animate={{ opacity: 1, y: 0 }} | ||
transition={{ duration: 0.15, delay: 0.1 }} | ||
> | ||
<CardHeader> | ||
<CardTitle>Project Runs</CardTitle> | ||
<CardDescription>View all runs for this project</CardDescription> | ||
</CardHeader> | ||
</motion.div> | ||
<CardContent> | ||
<motion.div | ||
initial={{ opacity: 0 }} | ||
animate={{ opacity: 1 }} | ||
transition={{ duration: 0.15, delay: 0.2 }} | ||
> | ||
<AllActivityTable runs={runs} projectSlug={projectSlug} /> | ||
</motion.div> | ||
</CardContent> | ||
</Card> | ||
</motion.div> | ||
); | ||
*/ | ||
return ( | ||
<div>TEST</div> | ||
) | ||
} |
99 changes: 99 additions & 0 deletions
99
...n-pages)/org/[organizationId]/(specific-organization-pages)/activity/AllActivityTable.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; | ||
import { Tables } from "@/lib/database.types"; | ||
import { ToSnakeCase } from "@/lib/utils"; | ||
import { AnimatePresence, motion } from "framer-motion"; | ||
import { Activity } from "lucide-react"; | ||
import moment from "moment"; | ||
import Link from "next/link"; | ||
|
||
export type StatusColor = { | ||
[key: string]: string; | ||
}; | ||
|
||
export const statusColors: StatusColor = { | ||
queued: 'bg-yellow-200/50 text-yellow-800 dark:bg-yellow-900/50 dark:text-yellow-200', | ||
pending_plan: 'bg-amber-200/50 text-amber-800 dark:bg-amber-900/50 dark:text-amber-200', | ||
running_plan: 'bg-purple-200/50 text-purple-800 dark:bg-purple-900/50 dark:text-purple-200', | ||
pending_approval: 'bg-blue-200/50 text-blue-800 dark:bg-blue-900/50 dark:text-blue-200', | ||
approved: 'bg-green-200/50 text-green-800 dark:bg-green-900/50 dark:text-green-200', | ||
pending_apply: 'bg-green-200/50 text-green-800 dark:bg-green-900/50 dark:text-green-200', | ||
running_apply: 'bg-indigo-200/50 text-indigo-800 dark:bg-indigo-900/50 dark:text-indigo-200', | ||
succeeded: 'bg-green-200/50 text-green-800 dark:bg-green-900/50 dark:text-green-200', | ||
failed: 'bg-red-200/50 text-red-800 dark:bg-red-900/50 dark:text-red-200', | ||
discarded: 'bg-neutral-200 text-neutral-800 dark:bg-neutral-950 dark:text-neutral-200', | ||
}; | ||
|
||
|
||
export const AllActivityTable = ({ runs, projectSlug }: { runs: Tables<'digger_runs'>[], projectSlug: string }) => { | ||
const sortedRuns = [...runs].sort((a, b) => { | ||
// Sort primarily by created_at in descending order (most recent first) | ||
return moment(b.created_at).valueOf() - moment(a.created_at).valueOf(); | ||
}); | ||
|
||
return ( | ||
<Table> | ||
<TableHeader> | ||
<TableRow> | ||
<TableHead className="text-left">Run ID</TableHead> | ||
<TableHead className="text-left">Commit ID</TableHead> | ||
<TableHead className="text-left">Status</TableHead> | ||
<TableHead className="text-left">Last updated</TableHead> | ||
<TableHead className="text-left">User</TableHead> | ||
</TableRow> | ||
</TableHeader> | ||
<TableBody> | ||
<AnimatePresence> | ||
{sortedRuns.length > 0 ? ( | ||
sortedRuns.map((run) => ( | ||
<motion.tr | ||
key={run.id} | ||
initial={{ opacity: 0, y: -20 }} | ||
animate={{ opacity: 1, y: 0 }} | ||
exit={{ opacity: 0, y: 20 }} | ||
transition={{ duration: 0.3 }} | ||
> | ||
<TableCell> | ||
<Link href={`/project/${projectSlug}/runs/${run.id}`}> | ||
<span className="cursor-pointer hover:underline"> | ||
{run.id.length > 8 ? `${run.id.substring(0, 8)}...` : run.id} | ||
</span> | ||
</Link> | ||
</TableCell> | ||
<TableCell>{run.commit_id}</TableCell> | ||
<TableCell> | ||
<span className={`px-2 py-1 rounded-full text-xs font-medium ${statusColors[ToSnakeCase(run.status)] || ''}`}> | ||
{run.status.toUpperCase()} | ||
</span> | ||
</TableCell> | ||
<TableCell>{moment(run.updated_at).fromNow()}</TableCell> | ||
<TableCell>{run.approval_author}</TableCell> | ||
</motion.tr> | ||
)) | ||
) : ( | ||
<TableRow> | ||
<TableCell colSpan={5} className="w-full justify-center"> | ||
<motion.div | ||
className="flex flex-col items-center justify-center mx-auto max-w-96 h-64 text-center" | ||
initial={{ opacity: 0, y: 20 }} | ||
animate={{ opacity: 1, y: 0 }} | ||
transition={{ duration: 0.5 }} | ||
> | ||
<motion.div | ||
className="rounded-full bg-gray-100 p-4 dark:bg-gray-800" | ||
whileHover={{ scale: 1.05 }} | ||
whileTap={{ scale: 0.95 }} | ||
> | ||
<Activity className="h-8 w-8 text-gray-400" /> | ||
</motion.div> | ||
<p className="mt-2 text-sm text-foreground"> | ||
Runs will appear here once they are initiated. Note you need to setup your repo with digger_workflow.yml to be able to trigger runs, for more information refer to the which includes example workflow file <Link href="https://docs.digger.dev/team/getting-started/gha-aws" className="text-blue-500 underline" >Docs quickstart</Link> | ||
</p> | ||
</motion.div> | ||
</TableCell> | ||
</TableRow> | ||
)} | ||
</AnimatePresence> | ||
</TableBody> | ||
</Table> | ||
); | ||
}; |
123 changes: 123 additions & 0 deletions
123
...s)/org/[organizationId]/(specific-organization-pages)/activity/OrganizationTeamsTable.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
"use client"; | ||
import { T } from '@/components/ui/Typography'; | ||
import { Card } from '@/components/ui/card'; | ||
import { | ||
Table, | ||
TableBody, | ||
TableCell, | ||
TableHead, | ||
TableHeader, | ||
TableRow, | ||
} from '@/components/ui/table'; | ||
import { | ||
flexRender, | ||
getCoreRowModel, | ||
getFilteredRowModel, | ||
getPaginationRowModel, | ||
getSortedRowModel, | ||
useReactTable, | ||
type ColumnDef, | ||
type SortingState, | ||
} from '@tanstack/react-table'; | ||
import moment from 'moment'; | ||
import Link from 'next/link'; | ||
import { useState } from 'react'; | ||
|
||
type TeamWithAdminName = { | ||
adminName: string | null | undefined; | ||
created_at: string | null; | ||
id: number; | ||
name: string; | ||
organization_id: string; | ||
}; | ||
|
||
type Props = { | ||
teams: TeamWithAdminName[]; | ||
}; | ||
|
||
export function OrganizationTeamsTable({ teams }: Props) { | ||
const columns: ColumnDef<TeamWithAdminName>[] = [ | ||
{ | ||
accessorKey: 'name', | ||
header: 'Name', | ||
cell: ({ row }) => ( | ||
<Link href={`/org/${row.original.organization_id}/team/${row.original.id}`} className='hover:underline'> | ||
{row.getValue('name')} | ||
</Link> | ||
), | ||
}, | ||
{ | ||
accessorKey: 'created_at', | ||
header: 'Created At', | ||
cell: ({ row }) => { | ||
const date = moment(row.getValue('created_at') as string); | ||
return date.format('MMM DD YYYY, HH:mm [hrs]'); | ||
}, | ||
}, | ||
{ | ||
accessorKey: 'adminName', | ||
header: 'Created by', | ||
cell: ({ row }) => row.getValue('adminName') || 'unknown', | ||
}, | ||
]; | ||
|
||
const [sorting, setSorting] = useState<SortingState>([]); | ||
const table = useReactTable({ | ||
data: teams, | ||
columns, | ||
getCoreRowModel: getCoreRowModel(), | ||
getSortedRowModel: getSortedRowModel(), | ||
getPaginationRowModel: getPaginationRowModel(), | ||
getFilteredRowModel: getFilteredRowModel(), | ||
onSortingChange: setSorting, | ||
state: { | ||
sorting, | ||
}, | ||
}); | ||
|
||
if (teams.length === 0) { | ||
return ( | ||
<Card> | ||
<div className='flex justify-center w-full items-center h-[180px]'> | ||
<T.Subtle>No teams found</T.Subtle> | ||
</div> | ||
</Card> | ||
); | ||
} | ||
|
||
return ( | ||
<div className="w-full"> | ||
<Card className="p-4"> | ||
<Table> | ||
<TableHeader> | ||
{table.getHeaderGroups().map(headerGroup => ( | ||
<TableRow key={headerGroup.id}> | ||
{headerGroup.headers.map(header => ( | ||
<TableHead key={header.id} className="text-left font-normal text-sm text-muted-foreground"> | ||
{header.isPlaceholder | ||
? null | ||
: flexRender( | ||
header.column.columnDef.header, | ||
header.getContext() | ||
)} | ||
</TableHead> | ||
))} | ||
</TableRow> | ||
))} | ||
</TableHeader> | ||
<TableBody> | ||
{table.getRowModel().rows.map(row => ( | ||
<TableRow key={row.id} className="hover:bg-muted/50"> | ||
{row.getVisibleCells().map(cell => ( | ||
<TableCell key={cell.id} className="py-2"> | ||
{flexRender(cell.column.columnDef.cell, cell.getContext())} | ||
</TableCell> | ||
))} | ||
</TableRow> | ||
))} | ||
</TableBody> | ||
</Table> | ||
</Card> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.