diff --git a/README.md b/README.md index b81b491..e4e80ad 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,52 @@ -
-GHBanner -
+# Git Watcher Pro -# Run and deploy your AI Studio app +Git Watcher Pro is a lightweight, proactive Git repository monitor for Windows. It sits in your system tray and monitors your local repositories for changes, keeping you synced with your remote servers. -This contains everything you need to run your app locally. +![Dashboard](docs/images/dashboard.png) -View your app in AI Studio: https://ai.studio/apps/drive/1NNtM1N_9cpRVQ7KoDZrJoSs90I9ZMeCA +## Features -## Run Locally +- **Real-time Monitoring:** Automatically checks for changes in your Git repositories. +- **Smart Status:** Shows if you are ahead, behind, or have dirty files. +- **Auto-Pull:** Optionally configure repositories to automatically pull changes when behind. +- **System Tray Integration:** Runs quietly in the background; minimize to tray to keep your taskbar clean. +- **Smart Auth:** Easily connect to private GitHub repositories using the clipboard-based Smart Connect feature. +- **Portable:** No installation required. Just run the executable. +- **Startup:** Can be configured to launch automatically with Windows. -**Prerequisites:** Node.js +![Settings](docs/images/settings.png) +## Getting Started -1. Install dependencies: - `npm install` -2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key -3. Run the app: - `npm run dev` +### Prerequisites + +- Windows 10/11 +- Git installed and available in PATH. + +### Installation + +1. Download the latest release (Portable .exe). +2. Run `Git Watcher Pro.exe`. + +### Development + +1. **Install dependencies:** + ```bash + npm install + ``` + +2. **Run in development mode:** + ```bash + npm run dev + ``` + *Note: In a headless environment, use `npm run preview` to see the UI.* + +3. **Build:** + ```bash + npm run build + ``` + This produces an installer and a portable executable in `dist/`. + +## License + +MIT diff --git a/docs/images/dashboard.png b/docs/images/dashboard.png new file mode 100644 index 0000000..31525f1 Binary files /dev/null and b/docs/images/dashboard.png differ diff --git a/docs/images/settings.png b/docs/images/settings.png new file mode 100644 index 0000000..a6ce969 Binary files /dev/null and b/docs/images/settings.png differ diff --git a/electron/assets/icon.png b/electron/assets/icon.png index c190e85..a48fa79 100644 Binary files a/electron/assets/icon.png and b/electron/assets/icon.png differ diff --git a/electron/main.ts b/electron/main.ts index 815cec9..98e9b4f 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -22,7 +22,7 @@ const PRELOAD_PATH = join(ROOT_PATH, 'dist-electron/preload.cjs') const store = new Store({ defaults: { repos: [], - settings: { checkInterval: 60, githubToken: '', launchAtStartup: true } + settings: { checkInterval: 60, githubToken: '', launchAtStartup: true, startMinimized: false } } }) @@ -163,10 +163,12 @@ function startClipboardWatcher() { // --- App Lifecycle --- function createWindow(): void { + const startMinimized = store.get('settings.startMinimized') as boolean; + mainWindow = new BrowserWindow({ width: 950, height: 700, - show: false, + show: false, // Always start hidden, we show it later if not startMinimized frame: false, backgroundColor: '#1e1e1e', autoHideMenuBar: true, @@ -179,7 +181,9 @@ function createWindow(): void { }) mainWindow.on('ready-to-show', () => { - mainWindow?.show() + if (!startMinimized) { + mainWindow?.show() + } }) mainWindow.on('close', (event) => { @@ -285,6 +289,15 @@ app.whenReady().then(() => { if (checkIntervalTimer) clearInterval(checkIntervalTimer); checkIntervalTimer = setInterval(checkRepos, newSettings.checkInterval * 1000); } + + // Handle Launch at Startup + if (newSettings.launchAtStartup !== undefined) { + app.setLoginItemSettings({ + openAtLogin: newSettings.launchAtStartup, + path: app.getPath('exe') + }); + } + return true; }); diff --git a/package-lock.json b/package-lock.json index 2dd2033..66bc242 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "git-watcher-pro", "version": "1.0.0", "dependencies": { + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -1302,6 +1305,42 @@ "node": ">=14" } }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", @@ -1317,6 +1356,141 @@ } } }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-icons": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", + "integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==", + "license": "MIT", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", + "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", @@ -1335,6 +1509,91 @@ } } }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -1850,8 +2109,9 @@ "version": "18.3.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, + "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -5780,6 +6040,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" diff --git a/package.json b/package.json index a120c87..89f2a72 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,10 @@ "appId": "com.gitwatcher.app", "productName": "Git Watcher Pro", "win": { - "target": "nsis", + "target": [ + "nsis", + "portable" + ], "sign": null, "forceCodeSigning": false, "verifyUpdateCodeSignature": false @@ -27,6 +30,9 @@ } }, "dependencies": { + "@radix-ui/react-checkbox": "^1.3.3", + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", diff --git a/src/Settings.tsx b/src/Settings.tsx index ce5a5f2..ba0eb74 100644 --- a/src/Settings.tsx +++ b/src/Settings.tsx @@ -1,9 +1,16 @@ import { useState, useEffect } from 'react'; +import { Button } from './components/ui/Button'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './components/ui/Card'; +import { Input } from './components/ui/Input'; +import { Label } from './components/ui/Label'; +import { Checkbox } from './components/ui/Checkbox'; +import { Loader2, ExternalLink, Check, Copy, Wand2 } from 'lucide-react'; export const Settings = () => { const [githubToken, setGithubToken] = useState(''); const [checkInterval, setCheckInterval] = useState(60); const [launchAtStartup, setLaunchAtStartup] = useState(true); + const [startMinimized, setStartMinimized] = useState(false); const [isConnecting, setIsConnecting] = useState(false); const [isSmartWaiting, setIsSmartWaiting] = useState(false); @@ -18,6 +25,7 @@ export const Settings = () => { setCheckInterval(settings.checkInterval || 60); setGithubToken(settings.githubToken || ''); setLaunchAtStartup(settings.launchAtStartup !== false); + setStartMinimized(settings.startMinimized || false); } }); @@ -38,6 +46,7 @@ export const Settings = () => { checkInterval: parseInt(checkInterval.toString()), githubToken, launchAtStartup, + startMinimized, ...override }; @@ -72,124 +81,150 @@ export const Settings = () => { }; return ( -
-

Settings

- -
-

General

- -
- - setCheckInterval(parseInt(e.target.value))} - onBlur={() => handleSave()} - style={{ background: '#2d2d30', border: '1px solid #444', color: 'white', padding: '6px', borderRadius: '4px', width: '80px' }} - /> -
- -
- -
+
+
+

Settings

+
+ {saveStatus && {saveStatus}} + +
+ +
+ + + General + Configure how the application behaves on your system. + + +
+ +
+ setCheckInterval(parseInt(e.target.value))} + onBlur={() => handleSave()} + /> + Frequency of repository checks +
+
- {/* GitHub Authentication Section */} -
-

GitHub Authentication

- -
-
-
-

- Connect your GitHub account to access private repositories. -

- - {/* Smart Auth Button */} - -
- - {isSmartWaiting && ( -
- Browser opened. Generate the token and just copy it to your clipboard. We'll detect it automatically! -
- )} +
+ { + setLaunchAtStartup(checked === true); + handleSave({ launchAtStartup: checked === true }); + }} + /> + +
- - -
-
- setGithubToken(e.target.value)} - style={{ flex: 1, background: '#1e1e1e', border: connectionStatus === 'error' ? '1px solid #f14c4c' : '1px solid #444', color: 'white', padding: '8px', borderRadius: '4px', fontFamily: 'monospace' }} - /> - + /> + +
+ + + + {/* GitHub Authentication Section */} + + + GitHub Authentication + Connect your GitHub account to access private repositories. + + +
+
+

+ To monitor private repositories, we need a Personal Access Token. + You can generate one manually or use our Smart Connect feature. +

+ +
-
-
- - Manual token generation ↗ - - Required scopes: repo, read:user + {isSmartWaiting && ( +
+ + + Browser opened. Generate the token on GitHub and just copy it to your clipboard. + We will detect it automatically! + +
+ )} + +
+ + +
+ setGithubToken(e.target.value)} + className={`font-mono ${connectionStatus === 'error' ? 'border-destructive focus-visible:ring-destructive' : ''}`} + /> + +
+
+ +
+ + Manual token generation + + | + Required scopes: repo, read:user +
-
-
-
- -
- - {saveStatus && {saveStatus}} + +
); -}; \ No newline at end of file +}; diff --git a/src/components/ui/Checkbox.tsx b/src/components/ui/Checkbox.tsx new file mode 100644 index 0000000..209a629 --- /dev/null +++ b/src/components/ui/Checkbox.tsx @@ -0,0 +1,27 @@ +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { CheckIcon } from "@radix-ui/react-icons" +import { cn } from "@/lib/utils" + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox } diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx new file mode 100644 index 0000000..62b3b66 --- /dev/null +++ b/src/components/ui/Input.tsx @@ -0,0 +1,24 @@ +import * as React from "react" +import { cn } from "@/lib/utils" + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" + +export { Input } diff --git a/src/components/ui/Label.tsx b/src/components/ui/Label.tsx new file mode 100644 index 0000000..e0d8e04 --- /dev/null +++ b/src/components/ui/Label.tsx @@ -0,0 +1,23 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/verification/dashboard_preview.png b/verification/dashboard_preview.png deleted file mode 100644 index e020fbf..0000000 Binary files a/verification/dashboard_preview.png and /dev/null differ diff --git a/verification/verify_changes.py b/verification/verify_changes.py deleted file mode 100644 index 6c2206a..0000000 --- a/verification/verify_changes.py +++ /dev/null @@ -1,21 +0,0 @@ -from playwright.sync_api import sync_playwright - -def verify_changes(): - with sync_playwright() as p: - browser = p.chromium.launch(headless=True) - page = browser.new_page() - try: - page.goto("http://localhost:4173") - page.wait_for_load_state("networkidle") - - # Take a screenshot of the Dashboard - page.screenshot(path="verification/dashboard_preview.png") - print("Screenshot taken: verification/dashboard_preview.png") - - except Exception as e: - print(f"Error: {e}") - finally: - browser.close() - -if __name__ == "__main__": - verify_changes()