Skip to content

Conversation

@Tim020
Copy link
Contributor

@Tim020 Tim020 commented Jan 19, 2026

No description provided.

Tim020 and others added 25 commits January 13, 2026 19:16
- Detailed architecture documentation
- Implementation phases with timeline
- File inventory and directory structure
- Development workflows and build process
- Testing strategy and success criteria

Issue #839
Add platform abstraction layer to support both browser and Electron environments:
- Create platform detection module (platform/index.js) with runtime detection
- Add browser implementation (platform/browser.js) using window.location
- Add Electron implementation (platform/electron.js) with IPC placeholders
- Update utils.js, main.js, and store.js to use platform layer
- Configure ESLint to support top-level await (ES2022)

This foundation enables seamless operation in both web and Electron contexts
with 95% code sharing and minimal modifications to the existing Vue app.

Refs #839

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add Electron main process, preload script, and connection management:
- Create electron/main.js with BrowserWindow and IPC handlers
- Create electron/preload.js exposing window.electronAPI via contextBridge
- Create ConnectionManager service using electron-store for persistence
- Add package.json with Electron 32.x and dependencies
- Configure dev mode (Vite dev server) and production mode (built files)

The Electron app now launches successfully and loads the Vue frontend.
IPC communication is established for connection management and storage.

Refs #839

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add server validation and discovery capabilities:
- Create VersionChecker service to validate server compatibility
  - Fetches /api/v1/settings endpoint
  - Requires exact version match between client and server
  - Handles connection errors with detailed error messages
- Create MDNSDiscovery service for local network server discovery
  - Uses bonjour-service to find _digiscript._tcp services
  - Optional version checking for discovered servers
  - 5 second discovery timeout
- Add IPC handlers in main.js:
  - version:check - Validate server compatibility
  - mdns:discover - Find servers on local network
  - mdns:discoverWithVersionCheck - Discovery with version validation
- Update preload.js to expose new methods to renderer

Server-side mDNS advertising will be implemented in future backend work.
The client-side discovery is ready to use when servers advertise.

Refs #839

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add complete connection management interface for Electron app:
- Create ServerSelector.vue component with:
  - Saved connections list with Connect/Test/Delete actions
  - mDNS discovery with version compatibility checking
  - Manual server entry form with validation
  - Test connection functionality
  - Real-time version compatibility feedback
- Update router/index.js:
  - Add /electron/server-selector route (Electron-only)
  - Add navigation guard to redirect to selector if no active connection
  - Prevent non-Electron access to Electron-only routes
- Fix VersionChecker.js to use dynamic import for node-fetch (ES module)

The Electron app now has a complete connection workflow:
1. App launches → checks for active connection
2. No connection → redirects to ServerSelector
3. User selects/adds/discovers server
4. Version compatibility verified
5. Connection saved and activated
6. Redirects to home page

Refs #839

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Move Electron connection check after store initialization and skip all
settings fetching and auth checks when navigating to server selector.

This fixes the blank page issue where the app would try to fetch settings
from a non-existent server connection, causing the navigation to fail.

Refs #839
Make WebSocket initialization conditional:
- Check if running in Electron and if there's an active connection
- Skip WebSocket initialization if no server is configured
- Use window.location.href to reload page after connecting to server

This fixes the blank page issue where main.js would try to initialize
WebSocket before any server connection was configured, causing the app
to crash before the ServerSelector could load.

Connection flow:
1. App loads → checks for connection → skips WebSocket if none
2. Router redirects to ServerSelector
3. User adds/selects server
4. Page reloads with active connection
5. WebSocket initializes with correct server URL

Refs #839
Add check in App.vue created hook to skip settings fetch and WebSocket
initialization when running in Electron without an active connection.

This fixes the error where App.vue would try to fetch settings before the
router guard could redirect to the ServerSelector, causing the app to show
the navbar but get stuck with a spinner.

Now App.vue checks for active connection first and skips all initialization
if none exists, allowing the router to properly redirect to ServerSelector.

Refs #839
Fix infinite spinner by setting loaded=true before returning early when
there's no active connection in Electron. Also add null check for SETTINGS
in template to prevent errors when SETTINGS hasn't been fetched.

The App.vue template shows a spinner when !loaded and only renders
router-view when loaded=true. Previously, when skipping initialization,
we never set loaded=true, causing the spinner to show forever.

Refs #839
Add dynamic version reading from package metadata to settings.as_json():
- Use importlib.metadata.version() to read from pyproject.toml
- Fallback to '0.0.0' if package metadata unavailable
- Required for Electron client version compatibility checking

The /api/v1/settings endpoint now includes a 'version' field that the
Electron client uses to validate server compatibility before connecting.

Refs #839
Add v-if condition to hide navbar when on /electron/server-selector route.
The navbar (with About, Help, Login buttons) is now hidden on the server
selection screen, providing a cleaner first-run experience.

Refs #839
Replace importlib.metadata.version() with direct reading from pyproject.toml
using tomllib (Python 3.11+ built-in). This avoids dependency on package
installation and ensures version is always available.

- Add _get_version() helper function
- Read from pyproject.toml using tomllib
- Fallback to '0.0.0' if file not found or parse error
- Log warning if version read fails

Fixes issue where version was returning '0.0.0' because server wasn't
installed as a package.

Refs #839
Add CORS (Cross-Origin Resource Sharing) headers to BaseController:
- set_default_headers() adds CORS headers to all responses
- options() method handles CORS preflight requests
- Allow all origins (*) for Electron compatibility (file:// protocol)
- Allow standard HTTP methods and headers

This fixes CORS errors when the Electron app (running from file:// or
Vite dev server) makes requests to the backend API.

Refs #839
After connecting to a server via ServerSelector and reloading the page,
the router guard wasn't detecting that RBAC roles needed to be fetched.
The check only looked at whether the store was undefined, not whether
the store data was empty.

Now also checks if RBAC_ROLES getter is empty to trigger settings fetch,
ensuring all required state is loaded before navigation proceeds.

Fixes Vue warnings about IS_SHOW_EDITOR and other RBAC getters being
undefined during render.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
The ConfigShow component was referencing IS_SHOW_EDITOR in its template
(line 6: v-if="IS_SHOW_EDITOR") but not importing it in mapGetters.

This caused Vue development mode to display a warning:
"Property or method IS_SHOW_EDITOR is not defined on the instance"

In production builds, this was silently failing - the undefined value
evaluated to falsy, so the "Edit Show" button simply didn't render
instead of showing an error.

Added IS_SHOW_EDITOR to the mapGetters array to properly import the
getter and fix both the dev warning and ensure the button displays
correctly for users with edit permissions.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Changes:
- Set base: './' in Vite config for relative paths (works with both
  web server and Electron file:// protocol)
- Updated Electron to load from ../server/static in development,
  process.resourcesPath/static when packaged
- Added server connection dropdown in navbar (Electron only)
- Added switchServer() method and clearActiveConnection IPC
- Configured Electron Forge to include server/static as extraResource
- Added build script: builds frontend then packages Electron app

Build workflow:
1. cd client && npm run build (outputs to ../server/static)
2. cd electron && npm run build (packages app with frontend included)

Both web and Electron use same built files - no duplication!

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
When loading from file:// protocol (Electron production build),
Vue Router's history mode fails because it tries to navigate to
file paths that don't exist (e.g., file:///show-config).

Solution: Detect file:// protocol and use hash mode (#/show-config)
for Electron, while keeping history mode for web server.

This allows navigation to work correctly in packaged Electron apps
while maintaining clean URLs in the web version.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
The issue: After connecting to a server, using window.location.href = '/'
navigates to file:/// (filesystem root) instead of reloading the app.

Solution: Use window.location.reload() to reload the current page,
which works correctly with both file:// protocol and web servers.

Changes:
- ServerSelector.vue: Replace window.location.href = '/' with
  window.location.reload() after successful connection
- App.vue: Use router.push() + reload() for switchServer action

This ensures navigation works correctly in packaged Electron apps.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Issue 1: After connecting, window.location.reload() was reloading the
ServerSelector page instead of navigating to home. This caused a
redirect loop.

Issue 2: WebSocket connection stayed active when switching servers,
causing connection leaks.

Solutions:
1. Navigate to home using hash-based URL (baseUrl + '#/') instead of
   reload, which properly navigates in hash mode
2. Close WebSocket connection with this.$socket.close() before clearing
   active connection and navigating to ServerSelector

Now users can connect to a server and navigate properly, and switching
servers cleanly closes the old connection before reconnecting.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
The issue: After connecting to a server, changing window.location.href
to a hash URL (e.g., baseUrl + '#/') only triggers client-side
navigation, not a full page reload. This means main.js never re-runs,
so the WebSocket is never reinitialized.

Solution: Set window.location.hash first (to specify target route),
then call window.location.reload() to force a full page reload.
This ensures main.js runs again and reinitializes the WebSocket.

Changes:
- ServerSelector: Set hash to '/' then reload after connecting
- App.vue switchServer: Set hash to '/electron/server-selector' then reload

Now the WebSocket properly reinitializes after switching/reconnecting.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Issue: Using base: './' for both web and Electron caused SPA routing
issues. On refresh of nested routes like /show-config/cast, relative
asset paths resolved incorrectly (e.g., ./assets/index.js became
/show-config/cast/assets/index.js), causing MIME type errors.

Solution: Separate build outputs with different base paths:
- Web build: base: '/' → ../server/static/ (absolute paths)
- Electron build: base: './' → ./dist-electron/ (relative paths)

Changes:
- vite.config.js: Conditional base and outDir based on BUILD_TARGET env
- Electron build script: Sets BUILD_TARGET=electron
- Electron main.js: Loads from ../client/dist-electron/
- Electron Forge: Packages dist-electron/ as extraResource
- .gitignore: Ignore dist-electron/

Build commands:
- Web: cd client && npm run build
- Electron: cd electron && npm run build (builds frontend + packages)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add mDNS/DNS-SD service advertising on the server and discovery on the
Electron client, allowing automatic server detection on the local network.

Server changes:
- Create MDNSAdvertiser class using AsyncZeroconf for async event loop
  compatibility
- Integrate mDNS into DigiScriptServer with toggleable setting
- Add mdns_advertising setting (enabled by default) with callback
- Support graceful start/stop when setting changes
- Deduplicate IP addresses from getaddrinfo()

Client changes:
- Fix bonjour-service import (use named export with constructor)
- MDNSDiscovery service already implemented, just needed import fix

Technical details:
- Use AsyncZeroconf instead of sync Zeroconf to avoid blocking Tornado's
  event loop
- Service type: _digiscript._tcp.local.
- Advertise on all non-loopback IPv4 addresses
- Async settings access pattern for proper lock handling

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Configure linting and formatting for the Electron project to match the
client project's code quality standards.

Changes:
- Add ESLint 9 with flat config (eslint.config.mjs)
- Add Prettier for code formatting (.prettierrc.json)
- Add lint and format npm scripts matching client project
- Install required dev dependencies:
  - eslint, @eslint/js
  - prettier, eslint-config-prettier, eslint-plugin-prettier
  - globals for environment definitions

Scripts added:
- npm run lint: Format and lint with auto-fix
- npm run ci-lint: Check formatting and linting (CI mode)
- npm run format: Auto-format all JavaScript and JSON files
- npm run format:check: Check formatting without changes

Configuration:
- ESLint: Node.js globals, ES2021 features, Prettier integration
- Prettier: Single quotes, 100 char width, ES5 trailing commas
- Automatically formatted existing code to match standards

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@github-actions github-actions bot added client Pull requests changing front end code server Pull requests changing back end code xlarge-diff git labels Jan 19, 2026
@github-actions
Copy link

github-actions bot commented Jan 19, 2026

Client Test Results

83 tests   83 ✅  0s ⏱️
 3 suites   0 💤
 1 files     0 ❌

Results for commit 30f8c3a.

♻️ This comment has been updated with latest results.

@github-actions
Copy link

github-actions bot commented Jan 19, 2026

Python Test Results

  1 files    1 suites   37s ⏱️
313 tests 313 ✅ 0 💤 0 ❌
318 runs  318 ✅ 0 💤 0 ❌

Results for commit 30f8c3a.

♻️ This comment has been updated with latest results.

@github-actions github-actions bot added the github GitHub actions related issue or pull request label Jan 19, 2026
Tim020 and others added 3 commits January 19, 2026 02:39
…tain permissions

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@github-actions github-actions bot added the idea label Jan 20, 2026
@Tim020 Tim020 force-pushed the feature/electron-standalone-frontend branch 2 times, most recently from cb3c582 to d075af9 Compare January 20, 2026 00:07
Create dedicated /api/v1/health endpoint for version checking that
exposes only minimal, non-sensitive information (version and status).
Previously, the Electron client used /api/v1/settings which exposed
sensitive system data (database paths, log paths, debug mode, etc.)
to unauthenticated clients.

Backend changes:
- Add GET /api/v1/health endpoint (public, no auth required)
- Restore @api_authenticated decorator to GET /api/v1/settings
- Keep @allow_when_password_required for password reset workflow
- Export get_version() function from settings module
- Fix test infrastructure: add missing port parameter to DigiScriptTestCase

Frontend changes:
- Update Electron VersionChecker to use /api/v1/health endpoint
- Update ServerSelector UI enhancements (text alignment, time formatting)

Tests:
- Add comprehensive test suite for health endpoint (4 tests)
- Add authentication tests for settings endpoint (2 tests)
- All 315 backend tests passing
- All 83 frontend tests passing

Security impact:
- Before: 10+ sensitive fields exposed publicly via /api/v1/settings
- After: Only 2 non-sensitive fields exposed via /api/v1/health
- Settings endpoint now requires authentication (401 without token)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@Tim020 Tim020 force-pushed the feature/electron-standalone-frontend branch from d075af9 to cd149ef Compare January 20, 2026 00:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client Pull requests changing front end code git github GitHub actions related issue or pull request idea server Pull requests changing back end code xlarge-diff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants