Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CI

on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

jobs:
lint-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies
run: bun install

- name: Run lint
run: bun run lint

- name: Run tests
run: bun run test

- name: Run build
run: bun run build
2 changes: 1 addition & 1 deletion src/components/Header.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import { describe, expect, it, vi } from 'vitest';
import Header from './Header';

// Mock TanStack Router Link
Expand Down
4 changes: 2 additions & 2 deletions src/components/app-sidebar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import { describe, expect, it, vi } from 'vitest';
import { RouterProvider, createMemoryHistory, createRootRoute, createRouter } from '@tanstack/react-router';
import { AppSidebar } from './app-sidebar';
import { SidebarProvider } from '@/components/ui/sidebar';
import { createRouter, createMemoryHistory, RouterProvider, createRootRoute } from '@tanstack/react-router';

// Mock useIsMobile hook
vi.mock('@/hooks/use-mobile', () => ({
Expand Down
4 changes: 2 additions & 2 deletions src/components/app-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const navigate = useNavigate()
const { data: session } = authClient.useSession()

const userName = session?.user?.name || session?.user?.email || 'User'
const userName = session?.user.name || session?.user.email || 'User'
const userInitial = userName.charAt(0).toUpperCase()

const handleLogout = async () => {
Expand Down Expand Up @@ -114,7 +114,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-medium">{userName}</span>
{session?.user?.email && session?.user?.name && (
{session?.user.email && session.user.name && (
<span className="truncate text-xs text-muted-foreground">{session.user.email}</span>
)}
</div>
Expand Down
10 changes: 5 additions & 5 deletions src/components/editor-canvas.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import { describe, expect, it, vi } from 'vitest';
import { EditorCanvas } from './editor-canvas';
import type { CanvasField } from './fields/field-preview';

const mockFields: CanvasField[] = [
const mockFields: Array<CanvasField> = [
{ id: '1', type: 'text', label: 'Field 1' },
{ id: '2', type: 'number', label: 'Field 2' },
];
Expand Down Expand Up @@ -98,7 +98,7 @@ describe('EditorCanvas', () => {
// We know from FieldPreview tests that there are buttons.
// Let's find the first remove button.
// FieldPreview structure: settings button, then trash button.
const buttons = screen.getAllByRole('button');
screen.getAllByRole('button');
// Filter for the trash button (it has text-destructive class usually, or we can look specifically).
// Or we can rely on mock from FieldPreview? deeper integration test here.

Expand All @@ -109,7 +109,7 @@ describe('EditorCanvas', () => {

// We can find by icon class if we render real icons, but querying by class is fragile.
// Let's try:
const removeButtons = document.querySelectorAll('.text-destructive.hover\\:bg-destructive\\/10');
document.querySelectorAll('.text-destructive.hover\\:bg-destructive\\/10');
// This is implementation detail reliance.

// Better: mock FieldPreview? No, we want integration.
Expand Down
2 changes: 1 addition & 1 deletion src/components/editor-sidebar-tabs.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import { describe, expect, it, vi } from 'vitest';
import { TabsLine } from './editor-sidebar-tabs';

describe('TabsLine', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/field-properties.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { FieldProperties } from './field-properties';
import type { CanvasField } from './fields/field-preview';

Expand Down
6 changes: 3 additions & 3 deletions src/components/field-properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
*/

import { useEffect, useState } from 'react'
import { ChevronDown } from 'lucide-react'
import { ValidationRuleBuilder } from './validation-rule-builder'
import type { CanvasField } from './fields/field-preview'
import type { ValidationConfig } from '@/lib/validation-engine'
import { Button } from '@/components/ui/button'
import {
Dialog,
Expand All @@ -38,9 +41,6 @@ import {
CollapsibleContent,
CollapsibleTrigger,
} from '@/components/ui/collapsible'
import { ChevronDown } from 'lucide-react'
import { ValidationRuleBuilder } from './validation-rule-builder'
import type { ValidationConfig } from '@/lib/validation-engine'

interface FieldPropertiesProps {
field: CanvasField | null // Field being edited (null when no field selected)
Expand Down
2 changes: 1 addition & 1 deletion src/components/fields/field-items.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { describe, expect, it } from 'vitest';
import { FieldItems } from './field-items';

describe('FieldItems', () => {
Expand Down
5 changes: 3 additions & 2 deletions src/components/fields/field-preview.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import { FieldPreview, type CanvasField } from './field-preview';
import { describe, expect, it, vi } from 'vitest';
import { FieldPreview } from './field-preview';
import type {CanvasField} from './field-preview';

const mockField: CanvasField = {
id: 'test-id',
Expand Down
2 changes: 1 addition & 1 deletion src/components/fields/field-preview.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Settings, Star, Trash2 } from 'lucide-react'
import type { ValidationConfig } from '@/lib/validation-engine'
import { Card } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Checkbox } from '@/components/ui/checkbox'
import { Label } from '@/components/ui/label'
import { Button } from '@/components/ui/button'
import { Field, FieldContent, FieldLabel } from '@/components/ui/field'
import { Slider } from '@/components/ui/slider'
import type { ValidationConfig } from '@/lib/validation-engine'

export interface CanvasField {
id: string
Expand Down
2 changes: 1 addition & 1 deletion src/components/nav-main.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use client'

import { ChevronRight } from 'lucide-react'
import type { LucideIcon } from 'lucide-react'
import { Link } from '@tanstack/react-router'
import type { LucideIcon } from 'lucide-react'

import {
Collapsible,
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/badge.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { describe, expect, it } from 'vitest';
import { Badge } from './badge';

describe('Badge', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/button.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import { describe, expect, it, vi } from 'vitest';
import { Button } from './button';

describe('Button', () => {
Expand Down
8 changes: 3 additions & 5 deletions src/components/ui/complex-primitives.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import { Switch } from './switch';
import { Slider } from './slider';
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription
SheetTrigger
} from './sheet';

describe('Interactive UI Components', () => {
Expand Down
4 changes: 1 addition & 3 deletions src/components/ui/field.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { render, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { describe, expect, it } from 'vitest';
import {
Field,
FieldLabel,
FieldContent,
FieldDescription,
FieldError,
FieldGroup,
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ function FieldError({
...new Map(errors.map((error) => [error?.message, error])).values(),
]

if (uniqueErrors?.length == 1) {
if (uniqueErrors.length == 1) {
return uniqueErrors[0]?.message
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/input.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import { describe, expect, it } from 'vitest';
import { Input } from './input';

describe('Input', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/ui/primitives.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import { Checkbox } from './checkbox';
import { Separator } from './separator';
import { Skeleton } from './skeleton';
Expand Down
3 changes: 2 additions & 1 deletion src/components/ui/toast.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from "react"
import * as ToastPrimitives from "@radix-ui/react-toast"
import { cva, type VariantProps } from "class-variance-authority"
import { cva } from "class-variance-authority"
import { X } from "lucide-react"
import type {VariantProps} from "class-variance-authority";

import { cn } from "@/lib/utils"

Expand Down
4 changes: 2 additions & 2 deletions src/components/validation-rule-builder.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { render, screen } from '@testing-library/react';
import { describe, it, expect, vi, beforeAll } from 'vitest';
import { ValidationRuleBuilder } from './validation-rule-builder';
import { beforeAll, describe, expect, it, vi } from 'vitest';
import userEvent from '@testing-library/user-event';
import { ValidationRuleBuilder } from './validation-rule-builder';

// Mock pointer capture for Radix UI
beforeAll(() => {
Expand Down
27 changes: 12 additions & 15 deletions src/components/validation-rule-builder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
* are pre-configured and users just need to set parameters.
*/

import { useState, useMemo } from 'react'
import { Plus, X, Info, AlertTriangle, CheckCircle2 } from 'lucide-react'
import { useMemo, useState } from 'react'
import { AlertTriangle, CheckCircle2, Info, Plus, X } from 'lucide-react'
import type { RuleTemplate, ValidationConfig } from '@/lib/validation-engine';
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
Expand All @@ -32,11 +33,11 @@ import {
TooltipTrigger,
} from '@/components/ui/tooltip'
import {
RULE_TEMPLATES,
getRulesForFieldType,
PREDEFINED_PATTERNS,
type ValidationConfig,
type RuleTemplate,
RULE_TEMPLATES,


getRulesForFieldType
} from '@/lib/validation-engine'

interface ValidationRuleBuilderProps {
Expand Down Expand Up @@ -75,21 +76,17 @@ const CATEGORY_COLORS: Record<string, string> = {
'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-200',
}

interface ActiveRule {
ruleId: string
params?: Record<string, unknown>
}

export function ValidationRuleBuilder({
fieldType,
currentValidation = {},
onChange,
}: ValidationRuleBuilderProps) {
// State for currently active validation rules on this field
const [activeRules, setActiveRules] = useState<ActiveRule[]>(() => {
const [activeRules, setActiveRules] = useState<Array<ActiveRule>>(() => {
// Initialize active rules from existing validation config
// This ensures the UI reflects the current validation state
const rules: ActiveRule[] = []
const rules: Array<ActiveRule> = []
if (currentValidation.minLength !== undefined) {
rules.push({
ruleId: 'minLength',
Expand Down Expand Up @@ -135,9 +132,9 @@ export function ValidationRuleBuilder({

// Group rules by category
const rulesByCategory = useMemo(() => {
const grouped: Record<string, RuleTemplate[]> = {}
const grouped: Record<string, Array<RuleTemplate>> = {}
for (const rule of applicableRules) {
if (!grouped[rule.category]) {
if (!(rule.category in grouped)) {
grouped[rule.category] = []
}
grouped[rule.category].push(rule)
Expand All @@ -147,7 +144,7 @@ export function ValidationRuleBuilder({

// Build validation config from active rules
const buildConfig = (
rules: ActiveRule[],
rules: Array<ActiveRule>,
required?: boolean,
): ValidationConfig => {
const config: ValidationConfig = {
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/use-mobile.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { renderHook, act } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { act, renderHook } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { useIsMobile } from './use-mobile';

describe('useIsMobile', () => {
Expand Down
Loading