Compare commits

..

3 Commits

Author SHA1 Message Date
dayuan.jiang
34913ce477 fix: handle fork PRs in auto-format workflow
- Use head.sha instead of head_ref for checkout (works for forks)
- For fork PRs: fail with helpful message if formatting needed
- For same-repo PRs: auto-commit and push as before
2025-12-26 12:14:06 +09:00
Dayuan Jiang
d1d0de3dea chore: bump version to 0.4.7 (#416)
* chore: bump version to 0.4.7

* style: auto-format with Biome

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-12-25 22:30:48 +09:00
Dayuan Jiang
8c736cee0d fix: persist settings in Electron by using fixed port (#415)
- Use fixed port 61337 in production instead of random ports (10000-65535)
- localStorage is origin-specific, so random ports caused settings loss
- Add locale save/restore since language is URL-based
- Fixes #399
2025-12-25 22:20:59 +09:00
6 changed files with 59 additions and 42 deletions

View File

@@ -14,7 +14,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
ref: ${{ github.event.pull_request.head.sha }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
@@ -37,11 +37,21 @@ jobs:
echo "has_changes=true" >> $GITHUB_OUTPUT
fi
# For fork PRs, just fail if formatting is needed (can't push to forks)
- name: Fail if fork PR needs formatting
if: steps.changes.outputs.has_changes == 'true' && github.event.pull_request.head.repo.full_name != github.repository
run: |
echo "::error::This PR has formatting issues. Please run 'npx @biomejs/biome check --write .' locally and push the changes."
git diff --stat
exit 1
# For same-repo PRs, commit and push the changes
- name: Commit changes
if: steps.changes.outputs.has_changes == 'true'
if: steps.changes.outputs.has_changes == 'true' && github.event.pull_request.head.repo.full_name == github.repository
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
git add .
git commit -m "style: auto-format with Biome"
git push
git push origin HEAD:${{ github.head_ref }}

View File

@@ -1,4 +1,5 @@
"use client"
import { usePathname, useRouter } from "next/navigation"
import { useCallback, useEffect, useRef, useState } from "react"
import { DrawIoEmbed } from "react-drawio"
import type { ImperativePanelHandle } from "react-resizable-panels"
@@ -10,6 +11,7 @@ import {
ResizablePanelGroup,
} from "@/components/ui/resizable"
import { useDiagram } from "@/contexts/diagram-context"
import { i18n, type Locale } from "@/lib/i18n/config"
const drawioBaseUrl =
process.env.NEXT_PUBLIC_DRAWIO_BASE_URL || "https://embed.diagrams.net"
@@ -24,6 +26,8 @@ export default function Home() {
showSaveDialog,
setShowSaveDialog,
} = useDiagram()
const router = useRouter()
const pathname = usePathname()
const [isMobile, setIsMobile] = useState(false)
const [isChatVisible, setIsChatVisible] = useState(true)
const [drawioUi, setDrawioUi] = useState<"min" | "sketch">("min")
@@ -58,6 +62,18 @@ export default function Home() {
// Load preferences from localStorage after mount
useEffect(() => {
// Restore saved locale and redirect if needed
const savedLocale = localStorage.getItem("next-ai-draw-io-locale")
if (savedLocale && i18n.locales.includes(savedLocale as Locale)) {
const pathParts = pathname.split("/").filter(Boolean)
const currentLocale = pathParts[0]
if (currentLocale !== savedLocale) {
pathParts[0] = savedLocale
router.replace(`/${pathParts.join("/")}`)
return // Wait for redirect
}
}
const savedUi = localStorage.getItem("drawio-theme")
if (savedUi === "min" || savedUi === "sketch") {
setDrawioUi(savedUi)
@@ -84,7 +100,7 @@ export default function Home() {
}
setIsLoaded(true)
}, [])
}, [pathname, router])
const handleDarkModeChange = async () => {
await saveDiagramToStorage()

View File

@@ -151,6 +151,9 @@ function SettingsContent({
}, [open])
const changeLanguage = (lang: string) => {
// Save locale to localStorage for persistence across restarts
localStorage.setItem("next-ai-draw-io-locale", lang)
const parts = pathname.split("/")
if (parts.length > 1 && i18n.locales.includes(parts[1] as Locale)) {
parts[1] = lang

View File

@@ -3,16 +3,16 @@ import { app } from "electron"
/**
* Port configuration
* Using fixed ports to preserve localStorage across restarts
* (localStorage is origin-specific, so changing ports loses all saved data)
*/
const PORT_CONFIG = {
// Development mode uses fixed port for hot reload compatibility
development: 6002,
// Production mode port range (will find first available)
production: {
min: 10000,
max: 65535,
},
// Maximum attempts to find an available port
// Production mode uses fixed port (61337) to preserve localStorage
// Falls back to sequential ports if unavailable
production: 61337,
// Maximum attempts to find an available port (fallback)
maxAttempts: 100,
}
@@ -36,19 +36,11 @@ export function isPortAvailable(port: number): Promise<boolean> {
})
}
/**
* Generate a random port within the production range
*/
function getRandomPort(): number {
const { min, max } = PORT_CONFIG.production
return Math.floor(Math.random() * (max - min + 1)) + min
}
/**
* Find an available port
* - In development: uses fixed port (6002)
* - In production: finds a random available port
* - If a port was previously allocated, verifies it's still available
* - In production: uses fixed port (61337) to preserve localStorage
* - Falls back to sequential ports if preferred port is unavailable
*
* @param reuseExisting If true, try to reuse the previously allocated port
* @returns Promise<number> The available port
@@ -56,6 +48,9 @@ function getRandomPort(): number {
*/
export async function findAvailablePort(reuseExisting = true): Promise<number> {
const isDev = !app.isPackaged
const preferredPort = isDev
? PORT_CONFIG.development
: PORT_CONFIG.production
// Try to reuse cached port if requested and available
if (reuseExisting && allocatedPort !== null) {
@@ -69,29 +64,22 @@ export async function findAvailablePort(reuseExisting = true): Promise<number> {
allocatedPort = null
}
if (isDev) {
// Development mode: use fixed port
const port = PORT_CONFIG.development
const available = await isPortAvailable(port)
if (available) {
allocatedPort = port
return port
}
console.warn(
`Development port ${port} is in use, finding alternative...`,
)
// Try preferred port first
if (await isPortAvailable(preferredPort)) {
allocatedPort = preferredPort
return preferredPort
}
// Production mode or dev port unavailable: find random available port
for (let attempt = 0; attempt < PORT_CONFIG.maxAttempts; attempt++) {
const port = isDev
? PORT_CONFIG.development + attempt + 1
: getRandomPort()
console.warn(
`Preferred port ${preferredPort} is in use, finding alternative...`,
)
const available = await isPortAvailable(port)
if (available) {
// Fallback: try sequential ports starting from preferred + 1
for (let attempt = 1; attempt <= PORT_CONFIG.maxAttempts; attempt++) {
const port = preferredPort + attempt
if (await isPortAvailable(port)) {
allocatedPort = port
console.log(`Allocated port: ${port}`)
console.log(`Allocated fallback port: ${port}`)
return port
}
}

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "next-ai-draw-io",
"version": "0.4.6",
"version": "0.4.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "next-ai-draw-io",
"version": "0.4.6",
"version": "0.4.7",
"license": "Apache-2.0",
"dependencies": {
"@ai-sdk/amazon-bedrock": "^4.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "next-ai-draw-io",
"version": "0.4.6",
"version": "0.4.7",
"license": "Apache-2.0",
"private": true,
"main": "dist-electron/main/index.js",