tests styles

This commit is contained in:
Saxon Fletcher committed 2025-07-24 17:03:01 +10:00
1 parent c8eaaa8a50
commit d2a310aa88
5 files changed
+85 -86

No files matched your search

@@ -31,6 +31,7 @@ interface TestRowProps {
prependQuery?: DatabaseTest | null
canRun?: boolean
onSelectTest: (test: DatabaseTest) => void
index: number
}
// Utility function to validate test query format
@@ -40,7 +41,7 @@ const isValidTestQuery = (query: string): boolean => {
}
const TestRow = forwardRef<TestRowHandle, TestRowProps>(
({ test, prependQuery, canRun = false, onSelectTest }, ref) => {
({ test, prependQuery, canRun = false, onSelectTest, index }, ref) => {
const project = useSelectedProject()
const [isRunning, setIsRunning] = useState(false)
const [status, setStatus] = useState<'queued' | 'passed' | 'failed' | undefined>()
@@ -126,52 +127,58 @@ const TestRow = forwardRef<TestRowHandle, TestRowProps>(
if (status === 'failed') {
return <Badge variant="destructive">Failed</Badge>
}
return <Badge variant="outline">Not run</Badge>
return null
}
return (
<>
<TableRow key={test.id}>
<TableCell>
<p className="text-sm cursor-pointer" onClick={() => onSelectTest(test)}>
{test.name}
</p>
</TableCell>
<TableCell>{getStatusBadge()}</TableCell>
<TableCell>{lastRun ? dayjs(lastRun).fromNow() : 'Never'}</TableCell>
<TableCell className="text-right">
<div className="flex items-center justify-end gap-2">
{canRun && (
<ButtonTooltip
type="default"
icon={<Play />}
loading={isRunning}
disabled={isRunning || status === 'queued' || !isTestQueryValid}
onClick={handleRunTest}
tooltip={{
content: {
side: 'bottom',
text: !isTestQueryValid
? 'Test query must start with BEGIN; and end with ROLLBACK;'
: undefined,
},
}}
/>
)}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button type="text" icon={<MoreVertical />} />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={() => setIsDeleteModalOpen(true)}>
<Trash size={14} />
<span className="ml-2">Remove test</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<div
key={test.id}
className="flex text-sm items-center gap-3 border-b px-4 py-3 last:border-b-0"
>
<span className="flex items-center justify-center w-5 h-5 text-xs rounded bg border border-default text-foreground-lighter">
{index + 1}
</span>
<p className="cursor-pointer flex-1" onClick={() => onSelectTest(test)}>
{test.name}
</p>
<div className="flex items-center gap-2">
<div className="text-foreground-light text-xs">
{lastRun ? dayjs(lastRun).fromNow() : null}
</div>
</TableCell>
</TableRow>
{getStatusBadge()}
</div>
<div className="flex items-center justify-end gap-2">
{canRun && (
<ButtonTooltip
type="default"
icon={<Play />}
loading={isRunning}
disabled={isRunning || status === 'queued' || !isTestQueryValid}
onClick={handleRunTest}
tooltip={{
content: {
side: 'bottom',
text: !isTestQueryValid
? 'Test query must start with BEGIN; and end with ROLLBACK;'
: undefined,
},
}}
/>
)}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button type="text" icon={<MoreVertical />} />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={() => setIsDeleteModalOpen(true)}>
<Trash size={14} />
<span className="ml-2">Remove test</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
<ConfirmationModal
visible={isDeleteModalOpen}
title="Delete test"
@@ -1,7 +1,7 @@
import { partition } from 'lodash'
import { useRouter } from 'next/router'
import { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react'
import { Search, MoreVertical, Trash } from 'lucide-react'
import { Search, MoreVertical, Trash, Settings2, FlaskConical } from 'lucide-react'
import {
Alert,
Button,
@@ -39,10 +39,11 @@ const isValidTestQuery = (query: string): boolean => {
// Simple component for setup test rows - just name and actions
interface SetupTestRowProps {
test: DatabaseTest
index: number
onSelectTest: (test: DatabaseTest) => void
}
const SetupTestRow = ({ test, onSelectTest }: SetupTestRowProps) => {
const SetupTestRow = ({ test, index, onSelectTest }: SetupTestRowProps) => {
const project = useSelectedProject()
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false)
@@ -58,7 +59,10 @@ const SetupTestRow = ({ test, onSelectTest }: SetupTestRowProps) => {
}
return (
<div className="w-full flex justify-between items-center p-4">
<div className="w-full flex justify-between items-center p-4 gap-3 border-b last:border-b-0">
<span className="flex items-center justify-center w-5 h-5 text-xs rounded bg border border-default text-foreground-lighter">
{index + 1}
</span>
<p className="text-sm cursor-pointer w-full" onClick={() => onSelectTest(test)}>
{test.name}
</p>
@@ -230,8 +234,8 @@ const DatabaseTestsList = forwardRef<TestsListHandle, DatabaseTestsListProps>(
environment.
</p>
) : (
tests.map((test) => (
<SetupTestRow key={test.id} test={test} onSelectTest={onSelectTest} />
tests.map((test, index) => (
<SetupTestRow key={test.id} index={index} test={test} onSelectTest={onSelectTest} />
))
)}
</div>
@@ -240,28 +244,19 @@ const DatabaseTestsList = forwardRef<TestsListHandle, DatabaseTestsListProps>(
// Regular tests view with full TestRow component
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Status</TableHead>
<TableHead>Last Run</TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{tests.map((test) => (
<TestRow
ref={(el) => (testRowRefs.current[test.id] = el)}
key={test.id}
test={test}
prependQuery={setupTest}
canRun={true}
onSelectTest={onSelectTest}
/>
))}
</TableBody>
</Table>
<div>
{tests.map((test, index) => (
<TestRow
ref={(el) => (testRowRefs.current[test.id] = el)}
key={test.id}
index={index}
test={test}
prependQuery={setupTest}
canRun={true}
onSelectTest={onSelectTest}
/>
))}
</div>
)
}
@@ -286,7 +281,10 @@ const DatabaseTestsList = forwardRef<TestsListHandle, DatabaseTestsListProps>(
{/* Setup Tests Group - Always show */}
<Card>
<CardHeader className="px-4">
<CardTitle className="text-sm font-medium">Before Tests</CardTitle>
<div className="flex items-center gap-2">
<Settings2 strokeWidth={1.5} size={16} className="text-foreground-lighter" />
<CardTitle>Before Tests</CardTitle>
</div>
</CardHeader>
{renderTestTable(filteredSetupTests, true)}
</Card>
@@ -295,7 +293,10 @@ const DatabaseTestsList = forwardRef<TestsListHandle, DatabaseTestsListProps>(
{filteredRegularTests.length > 0 && (
<Card>
<CardHeader className="px-4">
<CardTitle className="text-sm font-medium">Tests</CardTitle>
<div className="flex items-center gap-2">
<FlaskConical strokeWidth={1.5} size={16} className="text-foreground-lighter" />
<CardTitle>Tests</CardTitle>
</div>
</CardHeader>
{renderTestTable(filteredRegularTests, false)}
</Card>
@@ -1,7 +1,6 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { useSqlTitleGenerateMutation } from 'data/ai/sql-title-mutation'
import { uuidv4 } from 'lib/helpers'
import { databaseTestsKeys } from './database-tests-key'
import { DatabaseTest } from './database-tests-query'
@@ -18,20 +17,16 @@ export const useDatabaseTestCreateMutation = ({
onSuccess?: () => void
} = {}) => {
const queryClient = useQueryClient()
const { mutateAsync: generateSqlTitle } = useSqlTitleGenerateMutation()
return useMutation({
mutationFn: async ({ projectRef, query }: DatabaseTestCreateVariables) => {
// AI title generation
const { title } = await generateSqlTitle({ sql: query })
mutationFn: async ({ projectRef, query, name }: DatabaseTestCreateVariables) => {
// This is a mock implementation.
// In a real scenario, you would save the test to a file or a database table.
const key = databaseTestsKeys.list(projectRef)
const currentTests = queryClient.getQueryData<DatabaseTest[]>(key) ?? []
const newTest: DatabaseTest = {
id: uuidv4(),
name: title,
name,
query,
}
queryClient.setQueryData(key, [...currentTests, newTest])
@@ -1,7 +1,6 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { useSqlTitleGenerateMutation } from 'data/ai/sql-title-mutation'
import { databaseTestsKeys } from './database-tests-key'
import { DatabaseTest } from './database-tests-query'
@@ -18,19 +17,13 @@ export const useDatabaseTestUpdateMutation = ({
onSuccess?: () => void
} = {}) => {
const queryClient = useQueryClient()
const { mutateAsync: generateSqlTitle } = useSqlTitleGenerateMutation()
return useMutation({
mutationFn: async ({ projectRef, id, query, name }: DatabaseTestUpdateVariables) => {
// Generate AI title if name is not provided
const finalName = name ?? (await generateSqlTitle({ sql: query })).title
// This is a mock implementation.
// In a real scenario, you would update the test in a file or a database table.
const key = databaseTestsKeys.list(projectRef)
const currentTests = queryClient.getQueryData<DatabaseTest[]>(key) ?? []
const updatedTests = currentTests.map((test) =>
test.id === id ? { ...test, name: finalName, query } : test
test.id === id ? { ...test, name, query } : test
)
queryClient.setQueryData(key, updatedTests)
@@ -63,8 +63,10 @@ const DatabaseTestsPage: NextPageWithLayout = () => {
updateTest({
projectRef: project?.ref!,
id: test.id,
name: test.name,
query,
})
setEditorPanel({ open: false })
},
})
}
@@ -84,6 +86,7 @@ ROLLBACK;
onSave: (query) => {
createTest({
projectRef: project?.ref!,
name: 'New test',
connectionString: project?.connectionString,
query,
})