-
Notifications
You must be signed in to change notification settings - Fork 11.3k
feat: Add Electron wrapper for desktop app #1964
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
723eefe
0046282
a57a36a
050e022
7c7f9ab
573b5c3
922ecef
15b21c0
b39885b
93e3070
d2492d2
9e33c83
8026e51
3da7ceb
ff77ba1
c113702
414be64
7074ea2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| name: Build Electron App | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - '*' # Triggers on version tags like v1.0.0 | ||
| workflow_dispatch: # Allows manual triggering | ||
|
|
||
| jobs: | ||
| build: | ||
| strategy: | ||
| matrix: | ||
| # os: [macos-latest, windows-latest] | ||
| os: [windows-latest] | ||
|
|
||
| runs-on: ${{ matrix.os }} | ||
| defaults: | ||
| run: | ||
| shell: bash | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Setup Bun | ||
| uses: oven-sh/setup-bun@v2 | ||
| with: | ||
| bun-version: latest | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
|
|
||
| - name: Setup Go | ||
| uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: '>=1.18.0' | ||
|
|
||
| - name: Build frontend | ||
| env: | ||
| CI: "" | ||
| NODE_OPTIONS: "--max-old-space-size=4096" | ||
| run: | | ||
| cd web | ||
| bun install | ||
| DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(git describe --tags) bun run build | ||
| cd .. | ||
|
|
||
| # - name: Build Go binary (macos/Linux) | ||
| # if: runner.os != 'Windows' | ||
| # run: | | ||
| # go mod download | ||
| # go build -ldflags "-s -w -X 'one-api/common.Version=$(git describe --tags)' -extldflags '-static'" -o new-api | ||
|
|
||
| - name: Build Go binary (Windows) | ||
| if: runner.os == 'Windows' | ||
| run: | | ||
| go mod download | ||
| go build -ldflags "-s -w -X 'one-api/common.Version=$(git describe --tags)'" -o new-api.exe | ||
|
|
||
| - name: Update Electron version | ||
| run: | | ||
| cd electron | ||
| VERSION=$(git describe --tags) | ||
| VERSION=${VERSION#v} # Remove 'v' prefix if present | ||
| npm version $VERSION --no-git-tag-version --allow-same-version | ||
|
|
||
| - name: Install Electron dependencies | ||
| run: | | ||
| cd electron | ||
| npm install | ||
|
|
||
| # - name: Build Electron app (macOS) | ||
| # if: runner.os == 'macOS' | ||
| # run: | | ||
| # cd electron | ||
| # npm run build:mac | ||
| # env: | ||
| # CSC_IDENTITY_AUTO_DISCOVERY: false # Skip code signing | ||
|
|
||
| - name: Build Electron app (Windows) | ||
| if: runner.os == 'Windows' | ||
| run: | | ||
| cd electron | ||
| npm run build:win | ||
|
|
||
| # - name: Upload artifacts (macOS) | ||
| # if: runner.os == 'macOS' | ||
| # uses: actions/upload-artifact@v4 | ||
| # with: | ||
| # name: macos-build | ||
| # path: | | ||
| # electron/dist/*.dmg | ||
| # electron/dist/*.zip | ||
|
|
||
| - name: Upload artifacts (Windows) | ||
| if: runner.os == 'Windows' | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: windows-build | ||
| path: | | ||
| electron/dist/*.exe | ||
|
|
||
| release: | ||
| needs: build | ||
| runs-on: ubuntu-latest | ||
| if: startsWith(github.ref, 'refs/tags/') | ||
|
|
||
| steps: | ||
| - name: Download all artifacts | ||
| uses: actions/download-artifact@v4 | ||
|
|
||
| - name: Create Release | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| files: | | ||
| # macos-build/* | ||
| windows-build/* | ||
| draft: false | ||
| prerelease: false | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # New API Electron Desktop App | ||
|
|
||
| This directory contains the Electron wrapper for New API, providing a native desktop application with system tray support for Windows, macOS, and Linux. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| ### 1. Go Binary (Required) | ||
| The Electron app requires the compiled Go binary to function. You have two options: | ||
|
|
||
| **Option A: Use existing binary (without Go installed)** | ||
| ```bash | ||
| # If you have a pre-built binary (e.g., new-api-macos) | ||
| cp ../new-api-macos ../new-api | ||
| ``` | ||
|
|
||
| **Option B: Build from source (requires Go)** | ||
| TODO | ||
|
|
||
| ### 3. Electron Dependencies | ||
| ```bash | ||
| cd electron | ||
| npm install | ||
| ``` | ||
|
|
||
| ## Development | ||
|
|
||
| Run the app in development mode: | ||
| ```bash | ||
| npm start | ||
| ``` | ||
|
|
||
| This will: | ||
| - Start the Go backend on port 3000 | ||
| - Open an Electron window with DevTools enabled | ||
| - Create a system tray icon (menu bar on macOS) | ||
| - Store database in `../data/new-api.db` | ||
|
|
||
| ## Building for Production | ||
|
|
||
| ### Quick Build | ||
| ```bash | ||
| # Ensure Go binary exists in parent directory | ||
| ls ../new-api # Should exist | ||
|
|
||
| # Build for current platform | ||
| npm run build | ||
|
|
||
| # Platform-specific builds | ||
| npm run build:mac # Creates .dmg and .zip | ||
| npm run build:win # Creates .exe installer | ||
| npm run build:linux # Creates .AppImage and .deb | ||
| ``` | ||
|
|
||
| ### Build Output | ||
| - Built applications are in `electron/dist/` | ||
| - macOS: `.dmg` (installer) and `.zip` (portable) | ||
| - Windows: `.exe` (installer) and portable exe | ||
| - Linux: `.AppImage` and `.deb` | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### Port | ||
| Default port is 3000. To change, edit `main.js`: | ||
| ```javascript | ||
| const PORT = 3000; // Change to desired port | ||
| ``` | ||
|
|
||
| ### Database Location | ||
| - **Development**: `../data/new-api.db` (project directory) | ||
| - **Production**: | ||
| - macOS: `~/Library/Application Support/New API/data/` | ||
| - Windows: `%APPDATA%/New API/data/` | ||
| - Linux: `~/.config/New API/data/` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| #!/bin/bash | ||
|
|
||
| set -e | ||
|
|
||
| echo "Building New API Electron App..." | ||
|
|
||
| echo "Step 1: Building frontend..." | ||
| cd ../web | ||
| DISABLE_ESLINT_PLUGIN='true' bun run build | ||
| cd ../electron | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| echo "Step 2: Building Go backend..." | ||
| cd .. | ||
|
|
||
| if [[ "$OSTYPE" == "darwin"* ]]; then | ||
| echo "Building for macOS..." | ||
| CGO_ENABLED=1 go build -ldflags="-s -w" -o new-api | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major ❓ Verification inconclusiveVerify CGO is required before enabling it. Setting If CGO is not required, remove 🏁 Script executed: #!/bin/bash
# Check if the codebase uses CGO
# Search for CGO-specific imports
rg -n -C2 'import\s+"C"' --type=go
# Search for CGO build tags
rg -n -C2 '//\s*go:build.*cgo' --type=go
# Search for .c, .cpp, .h files (C/C++ sources)
fd -e c -e cpp -e h -e ccLength of output: 0 Remove 🤖 Prompt for AI Agents |
||
| cd electron | ||
| npm install | ||
| npm run build:mac | ||
| elif [[ "$OSTYPE" == "linux-gnu"* ]]; then | ||
| echo "Building for Linux..." | ||
| CGO_ENABLED=1 go build -ldflags="-s -w" -o new-api | ||
| cd electron | ||
| npm install | ||
| npm run build:linux | ||
| elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then | ||
| echo "Building for Windows..." | ||
| CGO_ENABLED=1 go build -ldflags="-s -w" -o new-api.exe | ||
| cd electron | ||
| npm install | ||
| npm run build:win | ||
| else | ||
| echo "Unknown OS, building for current platform..." | ||
| CGO_ENABLED=1 go build -ldflags="-s -w" -o new-api | ||
| cd electron | ||
| npm install | ||
| npm run build | ||
| fi | ||
|
|
||
| echo "Build complete! Check electron/dist/ for output." | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| // Create a simple tray icon for macOS | ||
| // Run: node create-tray-icon.js | ||
|
|
||
| const fs = require('fs'); | ||
| const { createCanvas } = require('canvas'); | ||
|
|
||
| function createTrayIcon() { | ||
| // For macOS, we'll use a Template image (black and white) | ||
| // Size should be 22x22 for Retina displays (@2x would be 44x44) | ||
| const canvas = createCanvas(22, 22); | ||
| const ctx = canvas.getContext('2d'); | ||
|
|
||
| // Clear canvas | ||
| ctx.clearRect(0, 0, 22, 22); | ||
|
|
||
| // Draw a simple "API" icon | ||
| ctx.fillStyle = '#000000'; | ||
| ctx.font = 'bold 10px system-ui'; | ||
| ctx.textAlign = 'center'; | ||
| ctx.textBaseline = 'middle'; | ||
| ctx.fillText('API', 11, 11); | ||
|
|
||
| // Save as PNG | ||
| const buffer = canvas.toBuffer('image/png'); | ||
| fs.writeFileSync('tray-icon.png', buffer); | ||
|
|
||
| // For Template images on macOS (will adapt to menu bar theme) | ||
| fs.writeFileSync('tray-iconTemplate.png', buffer); | ||
| fs.writeFileSync('tray-iconTemplate@2x.png', buffer); | ||
|
|
||
| console.log('Tray icon created successfully!'); | ||
| } | ||
|
|
||
| // Check if canvas is installed | ||
| try { | ||
| createTrayIcon(); | ||
| } catch (err) { | ||
| console.log('Canvas module not installed.'); | ||
| console.log('For now, creating a placeholder. Install canvas with: npm install canvas'); | ||
|
|
||
| // Create a minimal 1x1 transparent PNG as placeholder | ||
| const minimalPNG = Buffer.from([ | ||
| 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, | ||
| 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, | ||
| 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, | ||
| 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xDB, 0x56, | ||
| 0xCA, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4C, 0x54, | ||
| 0x45, 0x00, 0x00, 0x00, 0xA7, 0x7A, 0x3D, 0xDA, | ||
| 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4E, 0x53, | ||
| 0x00, 0x40, 0xE6, 0xD8, 0x66, 0x00, 0x00, 0x00, | ||
| 0x0A, 0x49, 0x44, 0x41, 0x54, 0x08, 0x1D, 0x62, | ||
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, | ||
| 0x00, 0x01, 0x0A, 0x2D, 0xCB, 0x59, 0x00, 0x00, | ||
| 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, | ||
| 0x60, 0x82 | ||
| ]); | ||
|
|
||
| fs.writeFileSync('tray-icon.png', minimalPNG); | ||
| console.log('Created placeholder tray icon.'); | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.