@argus-vrt/web 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.cta.json +15 -0
  2. package/DEPLOYMENT.md +154 -0
  3. package/Dockerfile +51 -0
  4. package/README.md +159 -0
  5. package/docker-compose.prod.yml +38 -0
  6. package/docker-compose.yml +15 -0
  7. package/drizzle/0000_slim_makkari.sql +61 -0
  8. package/drizzle/meta/0000_snapshot.json +452 -0
  9. package/drizzle/meta/_journal.json +13 -0
  10. package/drizzle.config.ts +10 -0
  11. package/package.json +60 -0
  12. package/public/favicon.ico +0 -0
  13. package/public/logo-argus.svg +8 -0
  14. package/public/logo-variants/logo-argus-a.svg +9 -0
  15. package/public/logo-variants/logo-argus-modern.svg +11 -0
  16. package/public/logo-variants/logo-argus-peacock.svg +8 -0
  17. package/public/logo192.png +0 -0
  18. package/public/logo512.png +0 -0
  19. package/public/manifest.json +25 -0
  20. package/public/robots.txt +3 -0
  21. package/public/tanstack-circle-logo.png +0 -0
  22. package/public/tanstack-word-logo-white.svg +1 -0
  23. package/scripts/backfill-kind.ts +148 -0
  24. package/src/api-plugin.ts +169 -0
  25. package/src/components/image/ImageCompare.tsx +188 -0
  26. package/src/components/story/StoryFlatList.tsx +67 -0
  27. package/src/components/story/StoryGroupedTree.tsx +273 -0
  28. package/src/components/story/StoryTree.tsx +185 -0
  29. package/src/components/ui/Drawer.tsx +110 -0
  30. package/src/components/ui/SearchInput.tsx +95 -0
  31. package/src/components/ui/StatusBadge.tsx +59 -0
  32. package/src/components/ui/ViewModeToggle.tsx +39 -0
  33. package/src/db/index.ts +27 -0
  34. package/src/db/schema.ts +151 -0
  35. package/src/hooks/useDebounce.ts +23 -0
  36. package/src/hooks/useStoryTree.ts +205 -0
  37. package/src/lib/utils.ts +55 -0
  38. package/src/logo.svg +12 -0
  39. package/src/routeTree.gen.ts +177 -0
  40. package/src/router.tsx +17 -0
  41. package/src/routes/__root.tsx +174 -0
  42. package/src/routes/branches/$name.tsx +171 -0
  43. package/src/routes/branches/index.tsx +104 -0
  44. package/src/routes/index.tsx +178 -0
  45. package/src/routes/tests/$id.tsx +417 -0
  46. package/src/routes/tests/index.tsx +128 -0
  47. package/src/routes/upload.tsx +108 -0
  48. package/src/styles.css +213 -0
  49. package/tsconfig.json +28 -0
  50. package/vite.config.ts +30 -0
package/.cta.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "projectName": "web",
3
+ "mode": "file-router",
4
+ "typescript": true,
5
+ "tailwind": true,
6
+ "packageManager": "yarn",
7
+ "git": false,
8
+ "install": true,
9
+ "addOnOptions": {},
10
+ "version": 1,
11
+ "framework": "react-cra",
12
+ "chosenAddOns": [
13
+ "start"
14
+ ]
15
+ }
package/DEPLOYMENT.md ADDED
@@ -0,0 +1,154 @@
1
+ # Deploying Argus Web Dashboard
2
+
3
+ ## Docker Deployment (Recommended)
4
+
5
+ ### Quick Start
6
+
7
+ ```bash
8
+ cd packages/web
9
+
10
+ # Start the dashboard and database
11
+ docker compose -f docker-compose.prod.yml up -d
12
+
13
+ # Run database migrations (first time only)
14
+ docker compose -f docker-compose.prod.yml exec web \
15
+ npx drizzle-kit push
16
+
17
+ # Check logs
18
+ docker compose -f docker-compose.prod.yml logs -f
19
+ ```
20
+
21
+ The dashboard will be available at `http://localhost:3000`
22
+
23
+ ### Configuration
24
+
25
+ Create a `.env` file to customize settings:
26
+
27
+ ```bash
28
+ # .env
29
+ PORT=3000
30
+ DB_PASSWORD=your-secure-password
31
+
32
+ # Path to screenshots directory (for image serving)
33
+ SCREENSHOTS_PATH=/path/to/your/screenshots
34
+ ```
35
+
36
+ ### Image Serving
37
+
38
+ The dashboard needs access to the screenshot files to display them. You have two options:
39
+
40
+ #### Option A: Mount Screenshots Directory
41
+
42
+ If the dashboard runs on the same machine as your screenshots:
43
+
44
+ ```yaml
45
+ # In docker-compose.prod.yml
46
+ volumes:
47
+ - /Users/yourname/projects:/screenshots:ro
48
+ ```
49
+
50
+ Then images at `/Users/yourname/projects/app/.visual-screenshots/...` will be served.
51
+
52
+ #### Option B: Shared Network Storage
53
+
54
+ For team setups, mount a shared NFS/SMB volume:
55
+
56
+ ```yaml
57
+ volumes:
58
+ - type: nfs
59
+ source: your-nfs-server:/screenshots
60
+ target: /screenshots
61
+ ```
62
+
63
+ ### Production with Reverse Proxy (Nginx)
64
+
65
+ For HTTPS and domain setup:
66
+
67
+ ```nginx
68
+ # /etc/nginx/sites-available/argus
69
+ server {
70
+ listen 80;
71
+ server_name argus.yourcompany.com;
72
+ return 301 https://$server_name$request_uri;
73
+ }
74
+
75
+ server {
76
+ listen 443 ssl http2;
77
+ server_name argus.yourcompany.com;
78
+
79
+ ssl_certificate /etc/letsencrypt/live/argus.yourcompany.com/fullchain.pem;
80
+ ssl_certificate_key /etc/letsencrypt/live/argus.yourcompany.com/privkey.pem;
81
+
82
+ location / {
83
+ proxy_pass http://localhost:3000;
84
+ proxy_http_version 1.1;
85
+ proxy_set_header Upgrade $http_upgrade;
86
+ proxy_set_header Connection 'upgrade';
87
+ proxy_set_header Host $host;
88
+ proxy_set_header X-Real-IP $remote_addr;
89
+ proxy_cache_bypass $http_upgrade;
90
+ }
91
+ }
92
+ ```
93
+
94
+ ### Useful Commands
95
+
96
+ ```bash
97
+ # Start services
98
+ docker compose -f docker-compose.prod.yml up -d
99
+
100
+ # Stop services
101
+ docker compose -f docker-compose.prod.yml down
102
+
103
+ # View logs
104
+ docker compose -f docker-compose.prod.yml logs -f web
105
+
106
+ # Rebuild after code changes
107
+ docker compose -f docker-compose.prod.yml build --no-cache
108
+ docker compose -f docker-compose.prod.yml up -d
109
+
110
+ # Reset database (caution: deletes all data)
111
+ docker compose -f docker-compose.prod.yml down -v
112
+ docker compose -f docker-compose.prod.yml up -d
113
+ ```
114
+
115
+ ### Backup Database
116
+
117
+ ```bash
118
+ # Backup
119
+ docker compose -f docker-compose.prod.yml exec db \
120
+ pg_dump -U argus argus > backup.sql
121
+
122
+ # Restore
123
+ docker compose -f docker-compose.prod.yml exec -T db \
124
+ psql -U argus argus < backup.sql
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Environment Variables
130
+
131
+ | Variable | Default | Description |
132
+ |----------|---------|-------------|
133
+ | `PORT` | `3000` | Port for the web server |
134
+ | `DATABASE_URL` | (auto) | PostgreSQL connection string |
135
+ | `DB_PASSWORD` | `argus` | Database password |
136
+ | `SCREENSHOTS_PATH` | `./screenshots` | Path to mount for image serving |
137
+ | `NODE_ENV` | `production` | Node environment |
138
+
139
+ ---
140
+
141
+ ## Updating
142
+
143
+ ```bash
144
+ # Pull latest changes
145
+ git pull
146
+
147
+ # Rebuild and restart
148
+ docker compose -f docker-compose.prod.yml build
149
+ docker compose -f docker-compose.prod.yml up -d
150
+
151
+ # Run any new migrations
152
+ docker compose -f docker-compose.prod.yml exec web \
153
+ npx drizzle-kit push
154
+ ```
package/Dockerfile ADDED
@@ -0,0 +1,51 @@
1
+ # Build stage
2
+ FROM node:20-alpine AS builder
3
+
4
+ WORKDIR /app
5
+
6
+ # Install dependencies for the monorepo
7
+ COPY package.json yarn.lock ./
8
+ COPY packages/web/package.json ./packages/web/
9
+ COPY packages/shared/package.json ./packages/shared/
10
+
11
+ RUN corepack enable && corepack prepare yarn@4.12.0 --activate
12
+ RUN yarn install --immutable
13
+
14
+ # Copy source code
15
+ COPY packages/shared ./packages/shared
16
+ COPY packages/web ./packages/web
17
+
18
+ # Build shared package first
19
+ WORKDIR /app/packages/shared
20
+ RUN yarn build
21
+
22
+ # Build web app
23
+ WORKDIR /app/packages/web
24
+ RUN yarn build
25
+
26
+ # Production stage
27
+ FROM node:20-alpine AS runner
28
+
29
+ WORKDIR /app
30
+
31
+ # Create non-root user
32
+ RUN addgroup --system --gid 1001 nodejs
33
+ RUN adduser --system --uid 1001 argus
34
+
35
+ # Copy built assets
36
+ COPY --from=builder /app/packages/web/dist ./dist
37
+ COPY --from=builder /app/packages/web/package.json ./
38
+ COPY --from=builder /app/node_modules ./node_modules
39
+
40
+ # Set ownership
41
+ RUN chown -R argus:nodejs /app
42
+
43
+ USER argus
44
+
45
+ EXPOSE 3000
46
+
47
+ ENV NODE_ENV=production
48
+ ENV HOST=0.0.0.0
49
+ ENV PORT=3000
50
+
51
+ CMD ["node", "dist/server/server.js"]
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # @argus-vrt/web
2
+
3
+ **Web dashboard for reviewing visual regression test results.**
4
+
5
+ A self-hosted dashboard that pairs with [@argus-vrt/cli](https://www.npmjs.com/package/@argus-vrt/cli) to give your team a visual review interface for screenshot diffs — similar to Chromatic, but self-hosted.
6
+
7
+ ## Features
8
+
9
+ - **Test Overview** - Dashboard showing all test runs with status badges
10
+ - **Image Comparison** - Four view modes:
11
+ - Side by Side - Compare baseline and current screenshots
12
+ - Diff Only - View the difference image
13
+ - Overlay - See diff highlights overlaid on current screenshot with adjustable opacity
14
+ - Current Only - View just the current screenshot
15
+ - **Story Browser** - Three organization modes:
16
+ - Flat list - Simple alphabetical list
17
+ - Tree view - Grouped by component name
18
+ - Grouped view - Organized by directory structure
19
+ - **Search** - Typeahead search with Cmd/Ctrl+K keyboard shortcut
20
+ - **Filtering** - Filter stories by status (all, changed, new, passed)
21
+ - **Mobile Responsive** - Drawer-based navigation on mobile devices
22
+ - **Dark Mode** - Full dark mode support
23
+
24
+ ## Deployment
25
+
26
+ ### Quick Start with Docker
27
+
28
+ ```bash
29
+ # Clone the repo
30
+ git clone https://github.com/maxcwolf/argus.git
31
+ cd argus/packages/web
32
+
33
+ # Start the dashboard and database
34
+ docker compose -f docker-compose.prod.yml up -d
35
+
36
+ # Run database migrations (first time only)
37
+ docker compose -f docker-compose.prod.yml exec web npx drizzle-kit push
38
+ ```
39
+
40
+ The dashboard will be available at `http://localhost:3000`.
41
+
42
+ ### Configuration
43
+
44
+ Create a `.env` file to customize settings:
45
+
46
+ ```bash
47
+ PORT=3000
48
+ DB_PASSWORD=your-secure-password
49
+
50
+ # Path to screenshots directory (for image serving)
51
+ SCREENSHOTS_PATH=/path/to/your/screenshots
52
+ ```
53
+
54
+ ### Environment Variables
55
+
56
+ | Variable | Default | Description |
57
+ |----------|---------|-------------|
58
+ | `PORT` | `3000` | Server port |
59
+ | `DATABASE_URL` | (auto) | PostgreSQL connection string |
60
+ | `DB_PASSWORD` | `argus` | Database password |
61
+ | `SCREENSHOTS_PATH` | `./screenshots` | Path to mount for image serving |
62
+
63
+ See [DEPLOYMENT.md](./DEPLOYMENT.md) for full production deployment instructions including Nginx reverse proxy with HTTPS, image serving options, and database backup/restore.
64
+
65
+ ## Connecting the CLI
66
+
67
+ Once the dashboard is running, point your CLI at it by adding `apiUrl` to your project's `.argus.json`:
68
+
69
+ ```json
70
+ {
71
+ "apiUrl": "http://localhost:3000"
72
+ }
73
+ ```
74
+
75
+ Then upload results after running tests:
76
+
77
+ ```bash
78
+ npx argus test
79
+ ```
80
+
81
+ ## Tech Stack
82
+
83
+ - **Framework**: [TanStack Start](https://tanstack.com/start) with React 19
84
+ - **Routing**: [TanStack Router](https://tanstack.com/router) (file-based)
85
+ - **Database**: PostgreSQL with [Drizzle ORM](https://orm.drizzle.team/)
86
+ - **Styling**: [Tailwind CSS v4](https://tailwindcss.com/) with design tokens
87
+ - **Fonts**: Inter (body), Space Grotesk (headings), JetBrains Mono (code)
88
+
89
+ ---
90
+
91
+ ## Development
92
+
93
+ ### Prerequisites
94
+
95
+ - Node.js >= 20
96
+ - Yarn >= 4
97
+ - Docker (for PostgreSQL)
98
+
99
+ ### Setup
100
+
101
+ From the repository root:
102
+
103
+ ```bash
104
+ # Install all dependencies
105
+ yarn install
106
+
107
+ # Start PostgreSQL (from this directory)
108
+ cd packages/web
109
+ docker compose up -d
110
+
111
+ # Push database schema
112
+ yarn workspace @argus-vrt/web db:push
113
+
114
+ # Start dev server at http://localhost:3000
115
+ yarn workspace @argus-vrt/web dev
116
+ ```
117
+
118
+ Or if you're already in `packages/web`:
119
+
120
+ ```bash
121
+ docker compose up -d
122
+ yarn db:push
123
+ yarn dev
124
+ ```
125
+
126
+ ### Scripts
127
+
128
+ | Script | Description |
129
+ |--------|-------------|
130
+ | `yarn dev` | Start development server on port 3000 |
131
+ | `yarn build` | Build for production |
132
+ | `yarn preview` | Preview production build |
133
+ | `yarn test` | Run tests with Vitest |
134
+ | `yarn db:generate` | Generate Drizzle migrations |
135
+ | `yarn db:push` | Push schema changes to database |
136
+ | `yarn db:studio` | Open Drizzle Studio |
137
+
138
+ ### Project Structure
139
+
140
+ ```
141
+ src/
142
+ ├── components/
143
+ │ ├── image/ # Image comparison components
144
+ │ ├── story/ # Story list/tree components
145
+ │ └── ui/ # Shared UI components
146
+ ├── hooks/ # React hooks
147
+ ├── lib/ # Utilities
148
+ ├── routes/ # File-based routes
149
+ │ ├── __root.tsx # Root layout
150
+ │ ├── index.tsx # Dashboard home
151
+ │ ├── tests/ # Test detail pages
152
+ │ └── branches/ # Branch pages
153
+ ├── db/ # Database schema
154
+ └── styles.css # Global styles & design tokens
155
+ ```
156
+
157
+ ## License
158
+
159
+ MIT
@@ -0,0 +1,38 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ web:
5
+ build:
6
+ context: ../..
7
+ dockerfile: packages/web/Dockerfile
8
+ ports:
9
+ - "${PORT:-3000}:3000"
10
+ environment:
11
+ - DATABASE_URL=postgresql://argus:${DB_PASSWORD:-argus}@db:5432/argus
12
+ - NODE_ENV=production
13
+ depends_on:
14
+ db:
15
+ condition: service_healthy
16
+ volumes:
17
+ # Mount the screenshots directory so the web app can serve images
18
+ # Adjust this path to where your screenshots are stored
19
+ - ${SCREENSHOTS_PATH:-./screenshots}:/screenshots:ro
20
+ restart: unless-stopped
21
+
22
+ db:
23
+ image: postgres:16-alpine
24
+ environment:
25
+ POSTGRES_USER: argus
26
+ POSTGRES_PASSWORD: ${DB_PASSWORD:-argus}
27
+ POSTGRES_DB: argus
28
+ volumes:
29
+ - postgres_data:/var/lib/postgresql/data
30
+ healthcheck:
31
+ test: ["CMD-SHELL", "pg_isready -U argus"]
32
+ interval: 5s
33
+ timeout: 5s
34
+ retries: 5
35
+ restart: unless-stopped
36
+
37
+ volumes:
38
+ postgres_data:
@@ -0,0 +1,15 @@
1
+ services:
2
+ postgres:
3
+ image: postgres:16-alpine
4
+ container_name: rn-visual-testing-db
5
+ environment:
6
+ POSTGRES_USER: postgres
7
+ POSTGRES_PASSWORD: postgres
8
+ POSTGRES_DB: visual_testing
9
+ ports:
10
+ - "5432:5432"
11
+ volumes:
12
+ - postgres_data:/var/lib/postgresql/data
13
+
14
+ volumes:
15
+ postgres_data:
@@ -0,0 +1,61 @@
1
+ CREATE TYPE "public"."approval_decision" AS ENUM('APPROVE_ALL', 'REJECT_ALL', 'PARTIAL');--> statement-breakpoint
2
+ CREATE TYPE "public"."test_status" AS ENUM('PENDING', 'APPROVED', 'REJECTED', 'PARTIAL');--> statement-breakpoint
3
+ CREATE TABLE "approvals" (
4
+ "id" text PRIMARY KEY NOT NULL,
5
+ "test_id" text NOT NULL,
6
+ "user_id" text NOT NULL,
7
+ "decision" "approval_decision" NOT NULL,
8
+ "comment" text,
9
+ "created_at" timestamp DEFAULT now() NOT NULL,
10
+ CONSTRAINT "test_user_uniq" UNIQUE("test_id","user_id")
11
+ );
12
+ --> statement-breakpoint
13
+ CREATE TABLE "story_results" (
14
+ "id" text PRIMARY KEY NOT NULL,
15
+ "test_id" text NOT NULL,
16
+ "story_id" text NOT NULL,
17
+ "kind" text,
18
+ "component_name" text NOT NULL,
19
+ "story_name" text NOT NULL,
20
+ "baseline_url" text,
21
+ "current_url" text NOT NULL,
22
+ "diff_url" text,
23
+ "pixel_diff" real DEFAULT 0 NOT NULL,
24
+ "ssim_score" real DEFAULT 1 NOT NULL,
25
+ "has_diff" boolean DEFAULT false NOT NULL,
26
+ "is_new" boolean DEFAULT false NOT NULL,
27
+ "render_time" integer,
28
+ "memory_usage" integer,
29
+ "approved" boolean
30
+ );
31
+ --> statement-breakpoint
32
+ CREATE TABLE "tests" (
33
+ "id" text PRIMARY KEY NOT NULL,
34
+ "branch" text NOT NULL,
35
+ "base_branch" text DEFAULT 'main' NOT NULL,
36
+ "commit_hash" text NOT NULL,
37
+ "commit_message" text,
38
+ "status" "test_status" DEFAULT 'PENDING' NOT NULL,
39
+ "total_stories" integer NOT NULL,
40
+ "changed_count" integer NOT NULL,
41
+ "passed_count" integer NOT NULL,
42
+ "failed_count" integer NOT NULL,
43
+ "created_at" timestamp DEFAULT now() NOT NULL,
44
+ "user_id" text
45
+ );
46
+ --> statement-breakpoint
47
+ CREATE TABLE "users" (
48
+ "id" text PRIMARY KEY NOT NULL,
49
+ "email" text NOT NULL,
50
+ "name" text,
51
+ "avatar_url" text,
52
+ "created_at" timestamp DEFAULT now() NOT NULL,
53
+ CONSTRAINT "users_email_unique" UNIQUE("email")
54
+ );
55
+ --> statement-breakpoint
56
+ ALTER TABLE "approvals" ADD CONSTRAINT "approvals_test_id_tests_id_fk" FOREIGN KEY ("test_id") REFERENCES "public"."tests"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
57
+ ALTER TABLE "approvals" ADD CONSTRAINT "approvals_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
58
+ ALTER TABLE "story_results" ADD CONSTRAINT "story_results_test_id_tests_id_fk" FOREIGN KEY ("test_id") REFERENCES "public"."tests"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
59
+ ALTER TABLE "tests" ADD CONSTRAINT "tests_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
60
+ CREATE INDEX "test_diff_idx" ON "story_results" USING btree ("test_id","has_diff");--> statement-breakpoint
61
+ CREATE INDEX "branch_created_idx" ON "tests" USING btree ("branch","created_at");