-
Notifications
You must be signed in to change notification settings - Fork 542
Show Theme Picker during On Boarding #186
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
0c6447a
Implement settings service and routes for file-based settings management
webdevcody 1a78304
Refactor SetupView component for improved readability
webdevcody ace736c
Update README and enhance Electron app initialization
webdevcody c76ba69
Enhance unit tests for settings service and error handling
webdevcody File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| /** | ||
| * Common utilities for settings routes | ||
| */ | ||
|
|
||
| import { createLogger } from "../../lib/logger.js"; | ||
| import { | ||
| getErrorMessage as getErrorMessageShared, | ||
| createLogError, | ||
| } from "../common.js"; | ||
|
|
||
| export const logger = createLogger("Settings"); | ||
|
|
||
| // Re-export shared utilities | ||
| export { getErrorMessageShared as getErrorMessage }; | ||
| export const logError = createLogError(logger); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /** | ||
| * Settings routes - HTTP API for persistent file-based settings | ||
| */ | ||
|
|
||
| import { Router } from "express"; | ||
| import type { SettingsService } from "../../services/settings-service.js"; | ||
| import { createGetGlobalHandler } from "./routes/get-global.js"; | ||
| import { createUpdateGlobalHandler } from "./routes/update-global.js"; | ||
| import { createGetCredentialsHandler } from "./routes/get-credentials.js"; | ||
| import { createUpdateCredentialsHandler } from "./routes/update-credentials.js"; | ||
| import { createGetProjectHandler } from "./routes/get-project.js"; | ||
| import { createUpdateProjectHandler } from "./routes/update-project.js"; | ||
| import { createMigrateHandler } from "./routes/migrate.js"; | ||
| import { createStatusHandler } from "./routes/status.js"; | ||
|
|
||
| export function createSettingsRoutes(settingsService: SettingsService): Router { | ||
| const router = Router(); | ||
|
|
||
| // Status endpoint (check if migration needed) | ||
| router.get("/status", createStatusHandler(settingsService)); | ||
|
|
||
| // Global settings | ||
| router.get("/global", createGetGlobalHandler(settingsService)); | ||
| router.put("/global", createUpdateGlobalHandler(settingsService)); | ||
|
|
||
| // Credentials (separate for security) | ||
| router.get("/credentials", createGetCredentialsHandler(settingsService)); | ||
| router.put("/credentials", createUpdateCredentialsHandler(settingsService)); | ||
|
|
||
| // Project settings | ||
| router.post("/project", createGetProjectHandler(settingsService)); | ||
| router.put("/project", createUpdateProjectHandler(settingsService)); | ||
|
|
||
| // Migration from localStorage | ||
| router.post("/migrate", createMigrateHandler(settingsService)); | ||
|
|
||
| return router; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /** | ||
| * GET /api/settings/credentials - Get credentials (masked for security) | ||
| */ | ||
|
|
||
| import type { Request, Response } from "express"; | ||
| import type { SettingsService } from "../../../services/settings-service.js"; | ||
| import { getErrorMessage, logError } from "../common.js"; | ||
|
|
||
| export function createGetCredentialsHandler(settingsService: SettingsService) { | ||
| return async (_req: Request, res: Response): Promise<void> => { | ||
| try { | ||
| const credentials = await settingsService.getMaskedCredentials(); | ||
|
|
||
| res.json({ | ||
| success: true, | ||
| credentials, | ||
| }); | ||
| } catch (error) { | ||
| logError(error, "Get credentials failed"); | ||
| res.status(500).json({ success: false, error: getErrorMessage(error) }); | ||
| } | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /** | ||
| * GET /api/settings/global - Get global settings | ||
| */ | ||
|
|
||
| import type { Request, Response } from "express"; | ||
| import type { SettingsService } from "../../../services/settings-service.js"; | ||
| import { getErrorMessage, logError } from "../common.js"; | ||
|
|
||
| export function createGetGlobalHandler(settingsService: SettingsService) { | ||
| return async (_req: Request, res: Response): Promise<void> => { | ||
| try { | ||
| const settings = await settingsService.getGlobalSettings(); | ||
|
|
||
| res.json({ | ||
| success: true, | ||
| settings, | ||
| }); | ||
| } catch (error) { | ||
| logError(error, "Get global settings failed"); | ||
| res.status(500).json({ success: false, error: getErrorMessage(error) }); | ||
| } | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| /** | ||
| * POST /api/settings/project - Get project settings | ||
| * Uses POST because projectPath may contain special characters | ||
| */ | ||
|
|
||
| import type { Request, Response } from "express"; | ||
| import type { SettingsService } from "../../../services/settings-service.js"; | ||
| import { getErrorMessage, logError } from "../common.js"; | ||
|
|
||
| export function createGetProjectHandler(settingsService: SettingsService) { | ||
| return async (req: Request, res: Response): Promise<void> => { | ||
| try { | ||
| const { projectPath } = req.body as { projectPath?: string }; | ||
|
|
||
| if (!projectPath || typeof projectPath !== "string") { | ||
| res.status(400).json({ | ||
| success: false, | ||
| error: "projectPath is required", | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| const settings = await settingsService.getProjectSettings(projectPath); | ||
|
|
||
| res.json({ | ||
| success: true, | ||
| settings, | ||
| }); | ||
| } catch (error) { | ||
| logError(error, "Get project settings failed"); | ||
| res.status(500).json({ success: false, error: getErrorMessage(error) }); | ||
| } | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /** | ||
| * POST /api/settings/migrate - Migrate settings from localStorage | ||
| */ | ||
|
|
||
| import type { Request, Response } from "express"; | ||
| import type { SettingsService } from "../../../services/settings-service.js"; | ||
| import { getErrorMessage, logError, logger } from "../common.js"; | ||
|
|
||
| export function createMigrateHandler(settingsService: SettingsService) { | ||
| return async (req: Request, res: Response): Promise<void> => { | ||
| try { | ||
| const { data } = req.body as { | ||
| data?: { | ||
| "automaker-storage"?: string; | ||
| "automaker-setup"?: string; | ||
| "worktree-panel-collapsed"?: string; | ||
| "file-browser-recent-folders"?: string; | ||
| "automaker:lastProjectDir"?: string; | ||
| }; | ||
| }; | ||
|
|
||
| if (!data || typeof data !== "object") { | ||
| res.status(400).json({ | ||
| success: false, | ||
| error: "data object is required containing localStorage data", | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| logger.info("Starting settings migration from localStorage"); | ||
|
|
||
| const result = await settingsService.migrateFromLocalStorage(data); | ||
|
|
||
| if (result.success) { | ||
| logger.info( | ||
| `Migration successful: ${result.migratedProjectCount} projects migrated` | ||
| ); | ||
| } else { | ||
| logger.warn(`Migration completed with errors: ${result.errors.join(", ")}`); | ||
| } | ||
|
|
||
| res.json({ | ||
| success: result.success, | ||
| migratedGlobalSettings: result.migratedGlobalSettings, | ||
| migratedCredentials: result.migratedCredentials, | ||
| migratedProjectCount: result.migratedProjectCount, | ||
| errors: result.errors, | ||
| }); | ||
| } catch (error) { | ||
| logError(error, "Migration failed"); | ||
| res.status(500).json({ success: false, error: getErrorMessage(error) }); | ||
| } | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /** | ||
| * GET /api/settings/status - Get settings migration status | ||
| * Returns whether settings files exist (to determine if migration is needed) | ||
| */ | ||
|
|
||
| import type { Request, Response } from "express"; | ||
| import type { SettingsService } from "../../../services/settings-service.js"; | ||
| import { getErrorMessage, logError } from "../common.js"; | ||
|
|
||
| export function createStatusHandler(settingsService: SettingsService) { | ||
| return async (_req: Request, res: Response): Promise<void> => { | ||
| try { | ||
| const hasGlobalSettings = await settingsService.hasGlobalSettings(); | ||
| const hasCredentials = await settingsService.hasCredentials(); | ||
|
|
||
| res.json({ | ||
| success: true, | ||
| hasGlobalSettings, | ||
| hasCredentials, | ||
| dataDir: settingsService.getDataDir(), | ||
| needsMigration: !hasGlobalSettings, | ||
| }); | ||
| } catch (error) { | ||
| logError(error, "Get settings status failed"); | ||
| res.status(500).json({ success: false, error: getErrorMessage(error) }); | ||
| } | ||
| }; | ||
| } |
39 changes: 39 additions & 0 deletions
39
apps/server/src/routes/settings/routes/update-credentials.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| /** | ||
| * PUT /api/settings/credentials - Update credentials | ||
| */ | ||
|
|
||
| import type { Request, Response } from "express"; | ||
| import type { SettingsService } from "../../../services/settings-service.js"; | ||
| import type { Credentials } from "../../../types/settings.js"; | ||
| import { getErrorMessage, logError } from "../common.js"; | ||
|
|
||
| export function createUpdateCredentialsHandler( | ||
| settingsService: SettingsService | ||
| ) { | ||
| return async (req: Request, res: Response): Promise<void> => { | ||
| try { | ||
| const updates = req.body as Partial<Credentials>; | ||
|
|
||
| if (!updates || typeof updates !== "object") { | ||
| res.status(400).json({ | ||
| success: false, | ||
| error: "Invalid request body - expected credentials object", | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| await settingsService.updateCredentials(updates); | ||
|
|
||
| // Return masked credentials for confirmation | ||
| const masked = await settingsService.getMaskedCredentials(); | ||
|
|
||
| res.json({ | ||
| success: true, | ||
| credentials: masked, | ||
| }); | ||
| } catch (error) { | ||
| logError(error, "Update credentials failed"); | ||
| res.status(500).json({ success: false, error: getErrorMessage(error) }); | ||
| } | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| /** | ||
| * PUT /api/settings/global - Update global settings | ||
| */ | ||
|
|
||
| import type { Request, Response } from "express"; | ||
| import type { SettingsService } from "../../../services/settings-service.js"; | ||
| import type { GlobalSettings } from "../../../types/settings.js"; | ||
| import { getErrorMessage, logError } from "../common.js"; | ||
|
|
||
| export function createUpdateGlobalHandler(settingsService: SettingsService) { | ||
| return async (req: Request, res: Response): Promise<void> => { | ||
| try { | ||
| const updates = req.body as Partial<GlobalSettings>; | ||
|
|
||
| if (!updates || typeof updates !== "object") { | ||
| res.status(400).json({ | ||
| success: false, | ||
| error: "Invalid request body - expected settings object", | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| const settings = await settingsService.updateGlobalSettings(updates); | ||
|
|
||
| res.json({ | ||
| success: true, | ||
| settings, | ||
| }); | ||
| } catch (error) { | ||
| logError(error, "Update global settings failed"); | ||
| res.status(500).json({ success: false, error: getErrorMessage(error) }); | ||
| } | ||
| }; | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use GET method for retrieving project settings.
Line 31 uses POST for retrieving project settings, which violates REST conventions. GET requests should be used for read operations.
Consider either:
router.get("/project")and acceptprojectPathas a query parameterrouter.get("/project/:projectPath")(requires URL encoding for paths)🔎 Recommended refactor
Option 1 - Query parameter approach:
Then update the handler in
apps/server/src/routes/settings/routes/get-project.tsto read from query params: