Skip to content

Feat/agent auth setting#8874

Merged
evereq merged 11 commits intodevelopfrom
feat/agent-auth-setting
Mar 30, 2025
Merged

Feat/agent auth setting#8874
evereq merged 11 commits intodevelopfrom
feat/agent-auth-setting

Conversation

@syns2191
Copy link
Copy Markdown
Collaborator

@syns2191 syns2191 commented Mar 16, 2025

PR

Please note: we will close your PR without comment if you do not check the boxes above and provide ALL requested information.


@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 16, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a dedicated authentication flow with a pop-up login window and user prompts.
    • Added a custom title bar and enhanced tray menu with additional settings options.
    • Integrated a sidebar for improved in-app navigation.
  • Enhancements

    • Improved window management for increased stability and responsiveness.
    • Refined communication channels for update notifications, settings, and database status.
    • Updated login interface layout and styling, including clearer user messages for login requirements.

Walkthrough

The changes span multiple modules and packages, introducing new authentication logic, refactoring window and tray management to use singleton patterns, and unifying IPC message formats across the application. In the Angular agent app, Nebular’s sidebar components are integrated. Several files in both the Electron and UI libraries have been updated to consolidate IPC handlers and adjust component lifecycles with new methods and properties. Additionally, new localization keys and improved security options for window settings have been added.

Changes

File(s) Change Summary
apps/agent/src/app/app.module.ts Added NbSidebarModule (with forRoot()) and NbSidebarService to the Angular module.
apps/agent/src/index.ts Removed the window-all-closed event listener to prevent auto-quitting on non-macOS platforms.
apps/agent/src/main/auth.ts Introduced a new authentication file with checkUserAuthentication and handleCloseAuthWindow for managing user login and dialog fallback.
apps/agent/src/main/init/app.ts Refactored AppWindow and TrayMenu to use singleton patterns; added setVariableGlobal, a macOS window-all-closed handler, and integrated authentication checks before server start.
apps/agent/src/main/init/ipcMain.ts Updated getGlobalVariable signature and added multiple IPC handlers (e.g., app_setting, AUTH_SUCCESS, update_app_setting).
apps/agent/src/main/preload.ts, .../preload/contextBridge.ts Added an import for the custom title bar and exposed a new require method (returning EventEmitter) in development mode.
apps/agent/src/main/preload/custom-title-bar.ts Introduced a custom title bar implementation using custom-electron-titlebar with IPC events for refreshing and hiding the menu.
apps/agent/src/main/tray.ts Implemented a singleton pattern for TrayMenu, updated the instantiation of appWindow, and added a new settings menu item.
apps/agent/src/main/util.ts Reformatted code and updated parameter types in utility functions.
apps/agent/src/main/window-manager.ts Enhanced AppWindow with new properties for authWindow and settingWindow plus added initAuthWindow and initSettingWindow methods.
Desktop & Server IPC Updates
apps/desktop-timer/src/index.ts, apps/desktop/src/index.ts,
apps/server-api/src/index.ts, apps/server/src/index.ts,
packages/desktop-lib/**/*
Unified IPC message format to use the structured setting_page_ipc payload; added new app_setting handlers and restructured update, database, and navigation messages.
packages/desktop-core/src/lib/window-manager/interfaces/iwindow.manager.ts Added new enum entry AUTH for window management.
Desktop UI Library – Auth & Login
packages/desktop-ui-lib/src/lib/auth/services/auth.service.ts,
login.component.{html,scss,ts}
Updated AuthService to inject GAUZY_ENV and added an isAgent getter; modified login UI behavior and styling.
Desktop UI Library – Settings/Setup/Updater
packages/desktop-ui-lib/src/lib/settings/*,
setup/*,
updater/updater.component.ts
Refactored components to consolidate IPC handling into single methods, implemented OnDestroy for cleanup, and added isAgent getters for conditional UI rendering.
Desktop Window
packages/desktop-window/src/index.ts,
desktop-window-auth.ts,
desktop-window-setting.ts
Added a new AuthWindow class, exported all entities from desktop-window-auth, and updated settings window functions to accept a new contextIsolation parameter.
packages/ui-core/i18n/assets/i18n/en.json Added a new key "EXIT_AGENT_CONFIRM" and adjusted punctuation for "SELECT_FILE".

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant LS as LocalStorage
    participant AuthW as AuthWindow
    participant DD as DesktopDialog
    participant User as User

    App->>LS: getAuthConfig() to check token
    alt Token Present
        App->>App: Proceed with normal initialization
    else Token Absent
        App->>AuthW: Create and display authentication window
        AuthW-->>App: User triggers close event
        App->>App: Invoke handleCloseAuthWindow()
        App->>LS: Re-check token existence
        alt Token Still Missing
            App->>DD: Open DesktopDialog prompting login/exit
            DD->>User: Display login prompt
            User-->>DD: Return decision (Login/Exit)
            DD-->>App: Send back user choice
        end
    end
Loading

Poem

I'm a bouncy rabbit in fields of code so vast,
Hopping through new windows built to forever last.
I found fresh IPC carrots, neatly wrapped with care,
And singleton treats that sparkle everywhere.
With each refactored line, my heart skips a beat,
Celebrating every change with a joyful, hopping tweet!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6595b7d and 1bdd3d7.

📒 Files selected for processing (1)
  • apps/agent/src/main/auth.ts (1 hunks)
🧰 Additional context used
🪛 GitHub Check: Cspell
apps/agent/src/main/auth.ts

[warning] 51-51:
Unknown word (choosed)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: test
  • GitHub Check: build
🔇 Additional comments (2)
apps/agent/src/main/auth.ts (2)

9-16: Revisit secure token storage
This code still stores user credentials in LocalStore. As previously noted, this can pose a security risk if an attacker gains local file system access. Consider storing tokens in a more secure location (e.g., Electron’s safeStorage API or OS-level credential storage).


24-27:

Details

❓ Verification inconclusive

Verify that removing all 'close' event listeners is intentional
Calling removeAllListeners('close') here discards any other handlers attached to the 'close' event. If additional closers or cleanup logic is needed elsewhere, this could introduce bugs. Confirm whether no other code relies on the 'close' event.

You can run a script to search for other 'close' event listeners in the codebase:


🏁 Script executed:

#!/bin/bash
# Searches for all instances of 'close' event usage in the codebase.
rg --context 2 "browserWindow\.on\('close'|\.once\('close'"

Length of output: 2404


ACTION: Confirm Intentional Override of 'close' Event Handlers

In apps/agent/src/main/auth.ts, the use of removeAllListeners('close') before attaching a new handler means that any previously registered 'close' logic—such as the one in apps/agent/src/main/window-manager.ts that destroys the auth window—will be discarded. Please verify that this deliberate override won’t remove needed cleanup actions. If the intent is to replace the default behavior with the async handler (handleCloseAuthWindow), consider clearly documenting this decision to avoid future confusion or unintended side effects.

  • Location: apps/agent/src/main/auth.ts (Lines 24–27)
  • Related Context: A 'close' listener is added for auth windows in apps/agent/src/main/window-manager.ts. Verify that its removal is acceptable.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Mar 16, 2025

View your CI Pipeline Execution ↗ for commit 1bdd3d7.

Command Status Duration Result
nx build desktop --base-href ./ ✅ Succeeded 1m 41s View ↗
nx build desktop-api --output-path=dist/apps/de... ✅ Succeeded 27s View ↗
nx run api:desktop-api ✅ Succeeded 1m 18s View ↗
nx build api -c=production --prod ✅ Succeeded 1m 21s View ↗
nx build gauzy -c=production --prod --verbose ✅ Succeeded 4m 3s View ↗
nx run gauzy:desktop-ui --base-href ./ ✅ Succeeded 4m 11s View ↗
nx build desktop-ui-lib --configuration=develop... ✅ Succeeded 32s View ↗
nx build plugin-integration-wakatime ✅ Succeeded <1s View ↗
Additional runs (57) ✅ Succeeded ... View ↗

☁️ Nx Cloud last updated this comment at 2025-03-28 23:21:41 UTC

@gitguardian
Copy link
Copy Markdown

gitguardian bot commented Mar 23, 2025

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
11719210 Triggered Nx Cloud Token a7fc1cb nx.json View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@syns2191 syns2191 marked this pull request as ready for review March 23, 2025 16:35
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (23)
packages/desktop-lib/src/lib/desktop-ipc.ts (1)

479-484: IPC message structure refactored to use a consistent pattern.

The code now uses a unified 'setting_page_ipc' channel with a structured payload object containing 'type' and 'data' fields, instead of using separate channels for different message types. This approach improves maintainability and consistency across the application.

packages/desktop-ui-lib/src/lib/login/login.component.ts (1)

116-118: Consider making the isAgent property more dynamic.

The isAgent getter unconditionally returns true, which means all users are treated as agents. If this is used for conditional UI rendering, it will always show agent-specific UI elements.

 get isAgent(): boolean {
-	return true;
+	return this.someConditionToCheckIfUserIsAgent();
 }
apps/agent/src/main/preload/contextBridge.ts (1)

27-29: Development-only EventEmitter exposure.

Exposing the EventEmitter class only in development mode is a secure approach. However, consider documenting why this is needed specifically in development to help future maintainers understand the purpose.

 if (process.env.NODE_ENV === 'development') {
+	// Expose EventEmitter for development-only authentication event handling
 	contextBridge.exposeInMainWorld('require', () => EventEmitter);
 }
packages/desktop-window/src/lib/desktop-window-auth.ts (2)

23-26: Remove debug console logs.

The console.log statements should be removed before merging to production.

-		console.log('preloadPath', preloadPath);
-		console.log('path ', path);

27-35: Auth window configuration with appropriate dimensions.

The window is configured with reasonable size (1000x768) and appropriate settings for an authentication window. Consider making the dimensions configurable or responsive to screen size.

apps/agent/src/main/auth.ts (2)

32-47: Authentication window close handling could be improved

The current implementation prevents users from closing the authentication window without logging in or explicitly exiting, which might lead to a frustrating user experience.

Consider:

  1. Adding a timeout for authentication attempts
  2. Providing a way to retry authentication
  3. Handling authentication failure scenarios beyond window closing
async function handleCloseAuthWindow() {
	const authConfig = getAuthConfig();
	if (!authConfig?.token) {
		const dialog = new DialogErrorHandler('Please login first to use the app');
		dialog.options.buttons.splice(1, 1);
+		// Add more descriptive buttons
+		dialog.options.buttons = ['Retry Login', 'Exit Application'];
		const button = await dialog.show();
		switch (button.response) {
+			case 0:
+				// Reopen the auth window
+				const appWindow = AppWindow.getInstance();
+				await appWindow.initAuthWindow();
+				await appWindow.authWindow.loadURL();
+				appWindow.authWindow.show();
+				break;
			case 1:
				app.exit(0);
				break;
			default:
-				// 👀
+				// Default fallback - keep application open
				break;
		}
	}
}

43-44: Clarify default case comment

The emoji comment // 👀 in the default case doesn't provide clear information about what happens in this scenario.

Replace with a more descriptive comment:

default:
-	// 👀
+	// Keep application open without taking any action
	break;
apps/agent/src/main/preload/custom-title-bar.ts (1)

10-20: Handle IPC failures gracefully.
You call ipcRenderer.invoke('get-app-path') without a fallback. If the main process fails to respond, the promise may reject. Consider adding a try/catch or fallback to handle IPC invocation failures.

packages/desktop-window/src/lib/desktop-window-setting.ts (1)

74-75: Name clarity.
The function windowSetting now takes contextIsolation as a second parameter. If more flags are added in the future, consider consolidating them into a config object for readability.

apps/agent/src/main/tray.ts (1)

61-72: Settings window logic could benefit from error handling.
Opening and showing the settings window is async. Consider adding error handling if the window fails to load or if appWindow.settingWindow is not yet defined.

packages/desktop-lib/src/lib/desktop-updater.ts (1)

73-76: Consider using constants for message types

All IPC message types are currently defined as string literals throughout the code. To improve maintainability and reduce the risk of typos, consider extracting these types into named constants.

+ // At the top of the file or in a separate constants file
+ const IPC_TYPES = {
+   UPDATE_FILES_DIRECTORY: 'update_files_directory',
+   ERROR_UPDATE: 'error_update',
+   UPDATE_DOWNLOADED: 'update_downloaded',
+   LOGOUT_QUIT_INSTALL: '_logout_quit_install_',
+   UPDATE_AVAILABLE: 'update_available',
+   UPDATE_NOT_AVAILABLE: 'update_not_available',
+   DOWNLOAD_ON_PROGRESS: 'download_on_progress'
+ };

// Then in the code
  this._settingWindow.webContents.send('setting_page_ipc', {
-   type: 'update_files_directory',
+   type: IPC_TYPES.UPDATE_FILES_DIRECTORY,
    data: {
      uri: files
    }
  });

Also applies to: 92-95, 105-108, 149-151, 165-167, 173-175, 184-186, 193-196, 201-204, 233-236

packages/desktop-ui-lib/src/lib/setup/setup.component.ts (1)

507-525: Implement comprehensive IPC event handling

The current implementation only handles the 'database_status' event type, but it's registered to listen for all 'setting_page_ipc' events. Consider extending the handler to include all expected event types or implement logging for unhandled types.

handleIpcEvent(_: any, arg: { type: string, data: any }) {
  if (arg.type === 'database_status') {
    if (arg.data.status) {
      this._notifier.success(arg.data.message);
    } else {
      this._notifier.warn(arg.data.message)
    }

    if (arg.data.status && this.runApp) {
      this.saveAndRun();
    } else {
      const elBtn: HTMLElement = this.btnDialogOpen.nativeElement;
      elBtn.click();
    }
    this.isSaving = false;
    this.isCheckConnection = false;
    this._cdr.detectChanges();
+ } else {
+   // Log unhandled event types for debugging
+   console.log(`Unhandled IPC event type: ${arg.type}`, arg);
  }
}
apps/agent/src/main/window-manager.ts (2)

99-115: Remove commented-out development code

There's a commented-out line for toggling dev tools (// this.authWindow.browserWindow.webContents.toggleDevTools();). Consider removing this comment if it's not needed for production, or implement it as a configurable debug option if it might be needed later.

 this.authWindow.browserWindow.on('close', () => {
   this.authWindow.browserWindow.destroy();
 });
- // this.authWindow.browserWindow.webContents.toggleDevTools();

117-138: Robust settings window initialization

The implementation for initSettingWindow is thorough with proper error handling and window configuration. However, like the auth window, there's a commented-out development line that should be addressed.

 this.settingWindow = await createSettingsWindow(
   null,
   this.getUiPath('settings'),
   this.getPreloadPath(),
   true
 );
- // this.settingWindow.webContents.toggleDevTools();
 this.settingWindow.removeAllListeners('close'); // remove the close default handle
packages/desktop-ui-lib/src/lib/updater/updater.component.ts (1)

23-25: Consider using arrow functions instead of manual binding.
Binding handleIpcEvent in the constructor works, but defining it as an arrow function (e.g., handleIpcEvent = (event, arg) => { ... }) often simplifies code and prevents forgetting to remove the binding later.

 constructor(
   private electronService: ElectronService,
   private _ngZone: NgZone
 ) {
-  this.handleIpcEvent = this.handleIpcEvent.bind(this);
 }
packages/desktop-ui-lib/src/lib/settings/settings.component.ts (3)

489-489: Alternative arrow function approach.
As before, to avoid manual binding, you can define your handler as an arrow function.


523-587: getAppSetting method is comprehensive.
The logic to merge settings, handle environment flags, and check connectivity in one place is cohesive. Consider graceful error handling if IPC invocation fails.

🧰 Tools
🪛 Biome (1.9.4)

[error] 576-576: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


590-741: Switch-based IPC handling is well structured.
You handle many IPC events in a single location. Consider extracting separate methods for each case if the logic grows further. Also, fix the comment spelling "copressed" → "compressed".

- // // copressed ipc setting to single event with multiple type
+ // // compressed ipc setting to single event with multiple types
apps/agent/src/main/init/app.ts (2)

15-15: Ensure checkUserAuthentication is tested
Importing checkUserAuthentication is fine, but make sure it’s covered by tests to catch any future regression.


167-179: Centralizing global variable logic
setVariableGlobal neatly encapsulates the assignment of global variables. However, storing global state can be tricky if concurrency or multi-process usage grows. Consider scoping these configs more locally or storing them in a central managed store to simplify app-wide data tracking.

apps/agent/src/main/init/ipcMain.ts (3)

23-36: Global var retrieval logic
getGlobalVariable consolidates environment options (server URL, port, etc.) into a single object. This is useful for consistency, but be mindful of potential overlaps with global.variableGlobal if these references get out of sync.


102-117: AUTH_SUCCESS handler
Saving user data and updating the store in response to the AUTH_SUCCESS event is appropriate. By invoking closeLoginWindow(), the flow fosters smooth user transitions. Consider additional logging for user details in case debugging is needed.


119-122: Dynamic application setting updates
The update_app_setting event logs the update time and uses LocalStore for persistence. This is well-structured, though an acknowledgement or result back to the sender might provide helpful user feedback.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b8a443 and 67cfac0.

📒 Files selected for processing (34)
  • apps/agent/src/app/app.component.ts (1 hunks)
  • apps/agent/src/app/app.module.ts (3 hunks)
  • apps/agent/src/index.ts (0 hunks)
  • apps/agent/src/main/auth.ts (1 hunks)
  • apps/agent/src/main/init/app.ts (9 hunks)
  • apps/agent/src/main/init/ipcMain.ts (3 hunks)
  • apps/agent/src/main/preload.ts (1 hunks)
  • apps/agent/src/main/preload/contextBridge.ts (2 hunks)
  • apps/agent/src/main/preload/custom-title-bar.ts (1 hunks)
  • apps/agent/src/main/tray.ts (5 hunks)
  • apps/agent/src/main/util.ts (1 hunks)
  • apps/agent/src/main/window-manager.ts (3 hunks)
  • apps/desktop-timer/src/index.ts (2 hunks)
  • apps/desktop/src/index.ts (2 hunks)
  • apps/server-api/src/index.ts (4 hunks)
  • apps/server/src/index.ts (4 hunks)
  • packages/desktop-core/src/lib/window-manager/interfaces/iwindow.manager.ts (1 hunks)
  • packages/desktop-lib/src/lib/contexts/automatic-update.ts (1 hunks)
  • packages/desktop-lib/src/lib/desktop-ipc.ts (4 hunks)
  • packages/desktop-lib/src/lib/desktop-menu.ts (2 hunks)
  • packages/desktop-lib/src/lib/desktop-tray.ts (6 hunks)
  • packages/desktop-lib/src/lib/desktop-updater.ts (7 hunks)
  • packages/desktop-ui-lib/src/lib/auth/services/auth.service.ts (3 hunks)
  • packages/desktop-ui-lib/src/lib/login/login.component.html (2 hunks)
  • packages/desktop-ui-lib/src/lib/login/login.component.scss (4 hunks)
  • packages/desktop-ui-lib/src/lib/login/login.component.ts (1 hunks)
  • packages/desktop-ui-lib/src/lib/settings/settings.component.html (1 hunks)
  • packages/desktop-ui-lib/src/lib/settings/settings.component.ts (9 hunks)
  • packages/desktop-ui-lib/src/lib/setup/setup.component.html (2 hunks)
  • packages/desktop-ui-lib/src/lib/setup/setup.component.ts (4 hunks)
  • packages/desktop-ui-lib/src/lib/updater/updater.component.ts (2 hunks)
  • packages/desktop-window/src/index.ts (1 hunks)
  • packages/desktop-window/src/lib/desktop-window-auth.ts (1 hunks)
  • packages/desktop-window/src/lib/desktop-window-setting.ts (3 hunks)
💤 Files with no reviewable changes (1)
  • apps/agent/src/index.ts
🧰 Additional context used
🧬 Code Definitions (3)
apps/desktop-timer/src/index.ts (1)
packages/desktop-lib/src/lib/desktop-store.ts (1)
  • LocalStore (15-176)
apps/agent/src/main/window-manager.ts (2)
packages/desktop-window/src/lib/desktop-window-auth.ts (1)
  • AuthWindow (15-54)
packages/desktop-window/src/lib/desktop-window-setting.ts (1)
  • createSettingsWindow (20-60)
packages/desktop-lib/src/lib/desktop-ipc.ts (1)
packages/desktop-lib/src/lib/desktop-updater.ts (1)
  • settingWindow (210-212)
🪛 GitHub Check: Cspell
apps/server/src/index.ts

[warning] 579-579:
Unknown word (seting)

packages/desktop-ui-lib/src/lib/settings/settings.component.ts

[warning] 753-753:
Unknown word (copressed)

🪛 GitHub Actions: Check Spelling and Typos with cspell
apps/server/src/index.ts

[warning] 579-579: Unknown word (seting)

packages/desktop-ui-lib/src/lib/settings/settings.component.ts

[warning] 753-753: Unknown word (copressed)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: test
  • GitHub Check: build
🔇 Additional comments (78)
packages/desktop-lib/src/lib/contexts/automatic-update.ts (1)

41-44: Refactored message format improves consistency.

The change to use a structured setting_page_ipc message format with type and data fields is a good improvement. This standardized approach makes IPC communication more maintainable and consistent across the application.

packages/desktop-lib/src/lib/desktop-menu.ts (2)

61-63: Good refactoring for consistent IPC messaging.

Converting direct event messages to a structured format with type/data properties aligns with the application-wide standardization of IPC communication.


150-152: Refactored to consistent IPC message pattern.

The conditional messaging now uses the same structured setting_page_ipc format, making the IPC communication more consistent and maintainable throughout the application.

apps/desktop/src/index.ts (3)

748-754: Standardized IPC message pattern for database status.

The refactoring to use a structured setting_page_ipc format for database status responses improves consistency with other parts of the application.


757-763: Consistent error handling with structured IPC messaging.

Error case now also uses the standardized setting_page_ipc format, maintaining consistency throughout the codebase.


884-884: Added new IPC handler for application settings.

This new handler provides a centralized way to retrieve application configuration, which is a good practice for maintaining separation of concerns.

packages/desktop-lib/src/lib/desktop-tray.ts (3)

39-41: Standardized IPC messaging for settings navigation.

The refactored approach using setting_page_ipc with a type property improves the consistency of inter-process communication.


51-53: Consistent message format for update navigation.

Changed to use the standardized IPC message format, aligning with other changes throughout the application.


88-90: Systematically updated IPC messaging across multiple menu handlers.

All instances of direct messaging have been properly refactored to use the standardized setting_page_ipc format with appropriate type properties. This systematic approach ensures consistency throughout the codebase.

Also applies to: 100-102, 179-181, 193-195

packages/desktop-lib/src/lib/desktop-ipc.ts (3)

735-740: Consistent IPC message structure applied for timer stop updates.

This change follows the same pattern of using the 'setting_page_ipc' channel with structured payload, maintaining consistency with other IPC communications in the codebase.


874-876: Updated navigation message to use the new IPC structure.

The 'goto_top_menu' message has been refactored to use the unified 'setting_page_ipc' channel with a type field, consistent with the application's new IPC pattern.


904-906: Logout success notification updated to use structured IPC.

The 'logout_success' message now follows the standardized 'setting_page_ipc' message format, completing the consistent implementation of the IPC messaging pattern throughout the file.

apps/server-api/src/index.ts (5)

370-372: Check for update IPC message refactored to use new pattern.

The code now uses the standardized 'setting_page_ipc' channel with a 'type' field, maintaining consistent IPC communication with the settings window.


535-543: Database status notification updated to use unified IPC structure.

The database connection status message has been refactored to use the 'setting_page_ipc' channel with a structured payload containing 'type' and 'data' fields, keeping the codebase consistent.


546-552: Database error handling refactored to use consistent IPC pattern.

Error handling for database connection now follows the same structured messaging pattern, properly sending the error message and status through the unified 'setting_page_ipc' channel.


564-567: Server status messaging updated to use standardized IPC.

The running state notification now uses the 'setting_page_ipc' channel with a structured payload, maintaining consistency across IPC communications.


811-811: Added new IPC handler for retrieving application settings.

A new handler has been added to provide a centralized way to access application configuration through IPC, complementing the new IPC message structure implementation.

packages/desktop-window/src/index.ts (1)

13-13: New authentication window module exported.

Added export for the desktop-window-auth module, making authentication functionality available to other parts of the application. This is part of the new authentication handling system introduced in this PR.

apps/agent/src/main/preload.ts (1)

3-3: Added custom title bar to preload script.

Imported the custom title bar module in the preload script, enabling enhanced UI functionality with a custom window title bar. This complements the authentication window implementation by providing a consistent UI experience.

packages/desktop-ui-lib/src/lib/settings/settings.component.html (1)

1163-1163: Broadened footer visibility condition to include agent users.

The condition has been updated to show the footer when either the user is a desktop timer user or an agent. This change is aligned with the new isAgent property added to the login component.

packages/desktop-core/src/lib/window-manager/interfaces/iwindow.manager.ts (1)

15-15: Successfully added AUTH to the RegisteredWindow enum.

The addition of AUTH = 'auth' to the RegisteredWindow enum enables the application to register and manage an authentication window, aligning with the new authentication functionality being implemented.

apps/agent/src/main/preload/contextBridge.ts (2)

4-4: Added EventEmitter import for development mode functionality.

The import is used in the conditional block that exposes EventEmitter through the require API.


24-25: Added trailing comma - minor syntax change.

This is a small syntax improvement that makes it easier to add more properties later.

apps/agent/src/app/app.module.ts (3)

14-16: Added Nebular sidebar components to imports.

The NbSidebarModule and NbSidebarService are being added to enable sidebar functionality in the application.


93-93: Added NbSidebarModule to the NgModule imports.

This allows the application to utilize Nebular's sidebar component functionality.


117-117: Added NbSidebarService to providers array.

This ensures the sidebar service is available for dependency injection throughout the application.

packages/desktop-window/src/lib/desktop-window-auth.ts (4)

1-14: New authentication window implementation.

This file introduces a new AuthWindow class that extends BaseWindow for handling authentication flow. The imports properly include all necessary components from @gauzy/desktop-core.


15-22: Implements AuthWindow class with proper inheritance.

The class correctly extends BaseWindow and implements IBaseWindow, following the existing architectural patterns of the application.


38-42: Configurable security settings with context isolation.

Good implementation of conditional context isolation. When enabled, it properly sets up secure web preferences by disabling nodeIntegration and configuring the preload script.


51-53: Proper window registration with WindowManager.

The AuthWindow is correctly registered with the WindowManager singleton using the RegisteredWindow.AUTH identifier.

apps/desktop-timer/src/index.ts (3)

554-560: Updated IPC message format for database connection status.

The IPC messaging has been standardized to use a structured format with 'setting_page_ipc' as the channel and an object containing 'type' and 'data' fields. This is more maintainable and follows a consistent pattern.


562-568: Consistent error handling for database connection failures.

The error case follows the same structured format as the success case, maintaining consistency in the IPC message structure.


797-797: Added application settings retrieval via IPC.

This new handler provides access to the application configuration from renderer processes. It leverages the existing LocalStore.getApplicationConfig() method to fetch all settings, auth, and project data.

packages/desktop-ui-lib/src/lib/login/login.component.scss (3)

4-4: UI adjustment: Login container width reduced

The login container width has been reduced from 765px to 560px, creating a more compact login interface. This change aligns with modern UI practices that favor narrower authentication forms.


15-15: Improved responsiveness: Login wrapper now uses 100% width

Changing from fixed width (476px) to 100% makes the login wrapper fully responsive, allowing it to adapt to its container size. This improves the component's usability across different screen sizes.


125-125: Consistent alignment: Submit inner wrapper justification changed

The justification has been updated from space-between to flex-end for both desktop and mobile layouts, ensuring elements are consistently aligned to the right. This change complements the HTML modifications where the forgot password link structure has been updated.

Also applies to: 357-357

apps/agent/src/main/util.ts (2)

14-17: Improved type safety in getApiBaseUrl function

The function signature has been enhanced with proper TypeScript typing instead of using any. This provides better type checking and self-documentation.

export function getApiBaseUrl(configs: {
  serverUrl?: string,
  port?: number
} | { [key: string]: string })

4-12: Code formatting improvements

The indentation and code structure has been improved while maintaining the same functionality. This enhances code readability and maintainability.

Also applies to: 21-22

packages/desktop-ui-lib/src/lib/login/login.component.html (1)

114-116:

Details

✅ Verification successful

Changed forgot password behavior

The "forgot password" link now uses a click event handler (click)="forgot()" instead of a router link. This change shifts the navigation from a declarative route-based approach to an imperative function call, which allows for custom handling before navigation.

Please ensure the forgot() method is properly implemented in the component class and handles the forgot password flow appropriately.


🏁 Script executed:

#!/bin/bash
# Check if the forgot() method exists in the login component
grep -A 10 "forgot()" packages/desktop-ui-lib/src/lib/login/login.component.ts

Length of output: 403


Verification: Forgot Password Behavior Correctly Updated

The forgot() method is present and properly implemented in the login component (see packages/desktop-ui-lib/src/lib/login/login.component.ts). It correctly calls this.electronService.shell.openExternal(this.forgotPasswordUrl), ensuring the forgot password flow is managed imperatively via the click event handler.

  • The code now uses (click)="forgot()" to trigger a custom navigation flow instead of the previous router link.
  • The implementation of forgot() confirms the intended behavior, utilizing the forgotPasswordUrl getter.
apps/agent/src/main/auth.ts (1)

17-30: New authentication flow implementation

The checkUserAuthentication function properly verifies if a user is authenticated and initiates the authentication flow when needed. This implementation ensures that users are authenticated before accessing the application.

However, consider adding explicit handling for when authentication is successful to properly close the auth window.

packages/desktop-ui-lib/src/lib/setup/setup.component.html (2)

51-52: Confirm behavior for agent environments.
Adding !isAgent to the condition hides this step when running in agent mode. Verify that this is intentional so that server or agent modes do not display these UI steps.


212-212: Keep conditions aligned for agent mode.
This additional check for !isAgent matches the earlier condition. Ensure that the UI logic for agent mode remains consistent across the application.

apps/agent/src/main/preload/custom-title-bar.ts (2)

29-37: Confirm icon path availability.
The code creates the title bar icon from a path in appPath + 'assets/icons/tray/icon.png'. Ensure this path always exists in production builds.


55-115: Validate CSS for cross-platform consistency.
The appended stylesheet sets a custom blur, shadow, and menu container position. Confirm that these visual effects behave as expected on all platforms (Windows, macOS, Linux).

packages/desktop-window/src/lib/desktop-window-setting.ts (2)

23-24: Ensure consistent usage of contextIsolation.
You've added an optional contextIsolation parameter to the function signature. Verify that all callers now appropriately pass or omit it when desired to avoid unexpected behavior.

Also applies to: 27-27


107-110: Improve security with context isolation.
Enabling contextIsolation is a plus for security, but remember to confirm that any renderer scripts don't rely on nodeIntegration. Thoroughly test to avoid unexpected breaks.

apps/agent/src/main/tray.ts (3)

16-16: Confirm correct usage of singleton instance.
AppWindow.getInstance(...) ensures only one AppWindow is created. Verify that this approach covers all cases where the main window is needed.


31-43: Singleton pattern initialization.
The class sets and returns TrayMenu.instance. Double-check that no code attempts to instantiate TrayMenu directly elsewhere, bypassing getInstance.


119-119: Clearer behavior for updating menu.
Calling this.setMenuList([]) effectively resets the menu. Ensure no items need to be preserved.

packages/desktop-lib/src/lib/desktop-updater.ts (1)

64-69: Consistent message structure implementation

The code now uses a more structured approach for IPC messaging with a unified format that includes type and data fields, which enhances maintainability and consistency across the application.

packages/desktop-ui-lib/src/lib/setup/setup.component.ts (2)

527-531: Proper IPC event binding in ngOnInit

The code correctly binds the handleIpcEvent method before registering it as an event listener, ensuring this context is preserved. This is good practice for event handler registration.


550-552: Good addition of isAgent getter

Adding the isAgent getter method provides a clean way to access the environment variable and improves code readability.

apps/agent/src/main/window-manager.ts (1)

17-18: Improved singleton pattern implementation

The updated singleton pattern prevents multiple instances creation and ensures proper initialization. This is a good improvement for the window manager.

Also applies to: 21-33

packages/desktop-ui-lib/src/lib/auth/services/auth.service.ts (3)

23-28: Environment injection for improved flexibility

Adding the GAUZY_ENV injection allows the service to adapt its behavior based on environment configuration, which is a good enhancement.


158-160: Encapsulated environment check with getter

Using a private getter for the isAgent check encapsulates the implementation details and improves code maintainability.


135-152:

Details

❓ Verification inconclusive

Different IPC methods for agent vs non-agent environments

The code uses invoke for agent environments and send for non-agent environments. These methods have different behaviors: invoke returns a Promise for a result while send is one-way messaging with no response.

Ensure this difference is intentional and that the agent environment properly handles the Promise returned by invoke.


🏁 Script executed:

#!/bin/bash
# Check if there are handlers for 'AUTH_SUCCESS' in main process

echo "Searching for 'AUTH_SUCCESS' handlers in main process files..."
rg -p "ipcMain\.(on|handle)\(['\"]AUTH_SUCCESS['\"]" | grep -v "test"

echo "Searching for usage of returned Promise from invoke..."
rg -p "'AUTH_SUCCESS'.*then" | grep -v "test"

Length of output: 477


Review IPC Behavior for Agent Environment

Our investigation confirms that the agent environment correctly registers a handler for 'AUTH_SUCCESS' in the main process (see, for example, apps/agent/src/main/init/ipcMain.ts, line 102). However, note that the Promise returned from invoke is not explicitly consumed (e.g., via .then/.catch or await). Please verify that the deliberate choice to forego handling the Promise is acceptable and that any potential errors are either handled elsewhere or intentionally ignored.

packages/desktop-ui-lib/src/lib/updater/updater.component.ts (1)

34-79: Centralized event handling looks good.
This switch-based handler cleanly conditions on different IPC message types. If desired, you could log or handle unexpected event types in the default case to aid debugging.

apps/server/src/index.ts (4)

385-387: Structured IPC message is consistent.
Sending messages under 'setting_page_ipc' unifies your event format and keeps it aligned with other files.


550-556: Good refactor for successful DB connection response.
Encapsulating connection status in a data object under 'setting_page_ipc' is consistent and clear.


561-567: Good refactor for failed DB connection response.
Using 'setting_page_ipc' for errors ensures consistent handling and messaging.


825-826: New IPC handler is consistent with your structured approach.
Returning application config via 'app_setting' streamlines retrieving app settings in the client UI.

packages/desktop-ui-lib/src/lib/settings/settings.component.ts (5)

1-1: OnDestroy inclusion is a good step.
Implementing OnDestroy helps ensure IPC listeners or subscriptions get properly cleaned up.

Also applies to: 32-32


57-57: Use of this.isAgent is clear for environment-based conditions.
This gating logic ensures you differentiate the agent build from other editions.


405-406: Dynamic server and driver options appear correct.
Restricting certain drivers and server modes for the agent variant helps tailor the UI to the intended environment.

Also applies to: 409-409


519-521: Properly removing the IPC listener in ngOnDestroy.
This cleanup avoids memory leaks and aligns with Angular’s lifecycle.


1239-1241: isAgent getter is consistent with the environment checks.
This aligns well with the newly introduced agent-based conditions used throughout the component.

apps/agent/src/main/init/app.ts (5)

1-1: No issue with importing ipcMain here
It seems you've simply adjusted this import statement. No functional or logical issues spotted.


25-27: Good shift to a singleton pattern
Using AppWindow.getInstance(appRootPath) aligns with the newly introduced singleton approach and avoids multiple instantiations. Declaring trayMenu as a let is understandable since it is initialized later.


94-98: Tray singleton initialization
Obtaining the tray menu via TrayMenu.getInstance() consistently follows the singleton strategy. No issues here.


127-134: Retaining the app on macOS
Preventing the default behavior of closing the app on macOS and hiding the dock is a common pattern for maintaining a background tray application. This approach is suitable for a persistent Electron app.


150-150: Setting global variables at runtime
Calling setVariableGlobal(configs); just before proceeding ensures environment details are set early. No concerns here.

apps/agent/src/main/init/ipcMain.ts (7)

4-5: Added Electron imports
Incorporating shell and app from Electron is straightforward. No issues here.


12-15: New imports for error & user management
The addition of AppError, User, and UserService indicates deeper integration for authentication and error handling. Looks consistent with the rest of the changes.


16-16: Imports for utility, window manager, and user service instantiation
Bringing in getApiBaseUrl, delaySync, AppWindow, moment, and then initializing a userService reflect enhanced setup for user-related operations. This is a coherent step to align IPC with authentication flows.

Also applies to: 18-19, 21-21


38-42: Graceful login window closure
The closeLoginWindow function introduces a 2-second delay, ensuring a smooth user experience before destroying the auth window. This approach is acceptable for letting any final actions or redirects take place.


73-73: Assigning global variable
Storing the output of getGlobalVariable(arg) in global.variableGlobal helps unify configuration handling. Keep an eye on synchronization if further dynamic updates occur.

Would you like to verify all other references to global.variableGlobal to ensure they align with the updated structure? I can generate a shell script to do so if needed.


98-98: Providing app path to renderer
ipcMain.on('get-app-path', () => app.getAppPath()); is a straightforward listener for retrieving the app path. No issues identified.


100-100: Fetching application config
ipcMain.handle('app_setting', () => LocalStore.getApplicationConfig()); nicely abstracts retrieving stored app settings. Ensures a single source of truth for configuration.

Comment thread apps/agent/src/app/app.component.ts Outdated
Comment thread packages/desktop-ui-lib/src/lib/login/login.component.html
Comment thread apps/agent/src/main/preload/custom-title-bar.ts
Comment thread packages/desktop-ui-lib/src/lib/updater/updater.component.ts
Comment thread apps/server/src/index.ts Outdated
Comment thread apps/agent/src/main/init/app.ts Outdated
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This PR adds authentication and settings functionality to the agent application. Here's a summary of the key changes:

  • Added new AuthWindow class and authentication flow management for handling agent login/logout
  • Standardized IPC communication patterns by consolidating settings-related messages under 'setting_page_ipc' channel
  • Added sidebar support via NbSidebarModule for improved navigation
  • Modified window management to use singleton pattern and proper cleanup

Key points to note:

  • The AuthWindow class documentation incorrectly refers to splash screen instead of auth window and contains debug logs
  • The isAgent getter in login component is hardcoded to true, which could cause issues in non-agent contexts
  • Window cleanup and error handling could be improved, particularly around auth window management
  • Security considerations needed for contextIsolation settings in window preferences
  • Singleton pattern implementation in window manager needs proper thread safety guarantees

The changes improve the architecture but require some refinements around security, error handling and documentation clarity.

💡 (2/5) Greptile learns from your feedback when you react with 👍/👎!

33 file(s) reviewed, 29 comment(s)
Edit PR Review Bot Settings | Greptile

Comment thread apps/agent/src/app/app.module.ts Outdated
Comment thread apps/agent/src/main/auth.ts
Comment thread apps/agent/src/main/auth.ts Outdated
Comment thread apps/agent/src/main/auth.ts
Comment thread apps/agent/src/app/app.component.ts Outdated
Comment thread packages/desktop-window/src/lib/desktop-window-auth.ts Outdated
Comment thread packages/desktop-ui-lib/src/lib/updater/updater.component.ts Outdated
Comment thread packages/desktop-ui-lib/src/lib/updater/updater.component.ts
Comment thread packages/desktop-ui-lib/src/lib/updater/updater.component.ts
Comment thread packages/desktop-ui-lib/src/lib/updater/updater.component.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🔭 Outside diff range comments (2)
packages/desktop-ui-lib/src/lib/setup/setup.component.ts (1)

508-526: 🧹 Nitpick (assertive)

Ensure typed IPC event
While this logic is correct, consider strongly typing the event parameter to Electron.IpcRendererEvent or a custom type for better type safety.

- handleIpcEvent(_: any, arg: { type: string, data: any }) {
+ handleIpcEvent(_: Electron.IpcRendererEvent, arg: { type: string; data: any }) {
packages/desktop-ui-lib/src/lib/settings/settings.component.ts (1)

523-587: 🧹 Nitpick (assertive)

Wrap the new getAppSetting() logic in try/catch.
This async method could benefit from additional error handling in case the IPC call fails. You can catch errors gracefully and notify the user.

+try {
    const appSetting = await this.electronService.ipcRenderer.invoke('app_setting');
    // ...
+} catch (error) {
+    console.error('Failed to retrieve app setting:', error);
+    this._notifier.error('Unable to load application settings');
+}
🧰 Tools
🪛 Biome (1.9.4)

[error] 576-576: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67cfac0 and 652ad4e.

📒 Files selected for processing (13)
  • apps/agent/src/app/app.module.ts (2 hunks)
  • apps/agent/src/main/auth.ts (1 hunks)
  • apps/agent/src/main/init/app.ts (8 hunks)
  • apps/agent/src/main/init/ipcMain.ts (3 hunks)
  • apps/agent/src/main/preload.ts (1 hunks)
  • apps/agent/src/main/window-manager.ts (3 hunks)
  • apps/server/src/index.ts (4 hunks)
  • packages/desktop-ui-lib/src/lib/login/login.component.ts (1 hunks)
  • packages/desktop-ui-lib/src/lib/settings/settings.component.ts (9 hunks)
  • packages/desktop-ui-lib/src/lib/setup/setup.component.ts (6 hunks)
  • packages/desktop-ui-lib/src/lib/updater/updater.component.ts (2 hunks)
  • packages/desktop-window/src/index.ts (1 hunks)
  • packages/desktop-window/src/lib/desktop-window-auth.ts (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
packages/desktop-ui-lib/src/lib/updater/updater.component.ts (1)
packages/desktop-ui-lib/src/lib/setup/setup.component.ts (1)
  • Component (23-568)
apps/agent/src/main/window-manager.ts (2)
packages/desktop-window/src/lib/desktop-window-auth.ts (1)
  • AuthWindow (15-52)
packages/desktop-window/src/lib/desktop-window-setting.ts (1)
  • createSettingsWindow (20-60)
🪛 GitHub Check: Cspell
apps/agent/src/main/auth.ts

[warning] 37-37:
Unknown word (Wirst)


[warning] 51-51:
Unknown word (choosed)

packages/desktop-ui-lib/src/lib/settings/settings.component.ts

[warning] 752-752:
Unknown word (copressed)

🪛 GitHub Actions: Check Spelling and Typos with cspell
apps/agent/src/main/auth.ts

[warning] 37-37: Unknown word (Wirst)


[warning] 51-51: Unknown word (choosed)

packages/desktop-ui-lib/src/lib/settings/settings.component.ts

[warning] 752-752: Unknown word (copressed)

🪛 Biome (1.9.4)
apps/agent/src/main/init/ipcMain.ts

[error] 20-20: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: test
  • GitHub Check: build
🔇 Additional comments (48)
packages/desktop-window/src/index.ts (1)

11-11: LGTM! New auth window export added correctly.

The new export for the authentication window follows the existing pattern and is placed appropriately with other desktop window exports.

apps/agent/src/main/preload.ts (1)

2-2: LGTM! Import order is correct.

The custom title bar import is properly placed before the console log statement, following best practices for import ordering.

packages/desktop-ui-lib/src/lib/login/login.component.ts (1)

116-118: LGTM! Clean implementation of the agent status getter.

The isAgent getter provides a clean way to access the environment configuration, which will allow for conditional rendering in the template based on agent status.

apps/agent/src/app/app.module.ts (3)

14-16: LGTM! Proper import of Nebular sidebar components.

The imports for NbSidebarModule and NbSidebarService are correctly added to the imports list.


93-93: LGTM! Correct initialization of the sidebar module.

The NbSidebarModule is properly initialized with .forRoot() as recommended in the previous review.


117-117: LGTM! Service properly registered.

NbSidebarService is correctly added to the providers array for dependency injection.

packages/desktop-window/src/lib/desktop-window-auth.ts (2)

36-40: Validate contextIsolation usage when preloadPath is missing.

You apply the secure defaults only if contextIsolation and preloadPath are both truthy. If a developer sets contextIsolation to true but omits preloadPath by mistake, the window remains with nodeIntegration enabled. A past reviewer flagged the same concern.

Would you like to throw an error or provide a fallback when contextIsolation is requested without a valid preload script?


46-52: Looks good!

Registering this window under RegisteredWindow.AUTH is consistent with the code’s approach to unified window management.

apps/server/src/index.ts (3)

385-387: Unified IPC message for handling updates looks consistent.

Using 'setting_page_ipc' with a descriptive type key helps maintain a structured approach to IPC and clearly indicates the purpose of each message.


550-557: Confirm handling of error messages in IPC responses.

Returning raw database error messages to the renderer could leak sensitive details (e.g., connection secrets). Ensure that no sensitive data is exposed or sanitize the message before sending back.

Would you like to mask credentials or display a custom error message to avoid potential leakage?

Also applies to: 561-567


579-582: Good use of structured IPC event for server status.

Sending server status under 'setting_page_ipc' with a type property centralizes communication and makes the frontend logic easier to manage.

apps/agent/src/main/window-manager.ts (4)

4-6: Add imports for new window logic looks good.
These imports appear to be used properly in the subsequent code.


21-25: Singleton constructor logic
The conditional assignment to AppWindow.instance ensures a single instance. Looks good.


27-32: getInstance method
Implements the singleton pattern effectively. No issues here.


98-116: initAuthWindow
Initializing a dedicated authentication window with appropriate event handling is solid. The error handling and cleanup logic look correct.

packages/desktop-ui-lib/src/lib/setup/setup.component.ts (6)

8-9: Added OnDestroy
Implementing the OnDestroy interface is a good step for cleanup. The use of ViewChild for references also looks consistent.


29-29: Class implements OnDestroy
Ensures the component can handle resource cleanup properly.


105-105: Bound handleIpcEvent
Binding the function is a neat pattern that ensures the correct this context in IPC callbacks.


528-531: Registering 'setting_page_ipc' listener
This is consistent with your new IPC structure. Looks good.


535-537: Remove IPC listener on destroy
Helps prevent memory leaks. Good practice.


555-557: Added get isAgent
Exposes agent info for the UI; straightforward addition.

packages/desktop-ui-lib/src/lib/updater/updater.component.ts (7)

8-8: Introduce OnDestroy
Adding OnDestroy ensures the component can handle cleanup on destruction.


11-11: Importing Event from 'electron'
Allows for strongly typing the event parameter in handleIpcEvent. Good approach.


19-19: Implements OnInit, OnDestroy
Ensures consistent lifecycle management for updates. Looks good.


25-27: Binding handleIpcEvent in constructor
This approach eliminates the need for arrow functions or manual binding in usage sites. Nicely done.


36-81: handleIpcEvent - consolidated update events
The switch statement effectively handles various update statuses. The usage of _ngZone.run() ensures UI updates are triggered in Angular’s zone.


83-86: ngOnInit - registering 'setting_page_ipc'
Consistent with the new centralized IPC messaging approach.


88-90: ngOnDestroy - removing IPC listener
Prevents memory leaks by properly cleaning up. Good practice.

packages/desktop-ui-lib/src/lib/settings/settings.component.ts (7)

1-1: Good use of the OnDestroy lifecycle hook.
Adding OnDestroy to the class and properly removing listeners is a best practice to prevent memory leaks and improve maintainability.

Also applies to: 32-32


57-57: Conditional icon path reflects the new isAgent state effectively.
This ensures a consistent icon experience across different modes (desktop timer, server, agent).


405-407: Appropriate customization of serverOptions for the agent.
Excluding 'integrated' when isAgent is true appears logical given the new agent workflow.


409-409: Extending driverOptions for mysql under isAgent condition seems correct.
This aligns the agent environment with additional database driver support.


489-489: Binding handleIpcEvent to the component scope.
This pattern ensures that when the handler is triggered, it retains the correct this context.


519-521: Well-handled unsubscription in ngOnDestroy.
Removing the IPC listener when the component is destroyed helps avoid leaks and unexpected behavior.


1238-1240: New isAgent getter is consistent with existing environment checks.
This is well-aligned with the other environment-based getters.

apps/agent/src/main/init/app.ts (6)

15-15: Ensuring authentication checks through checkUserAuthentication.
Importing checkUserAuthentication sets up the agent for robust login flow.


25-27: Refactored to use appRootPath and lazy initialization.
Storing appRootPath and retrieving the singleton instance of AppWindow ensures consistent path usage and a single source of truth for the main window.


105-106: Authentication invoked before finalizing startup.
Calling checkUserAuthentication(appRootPath) ensures that user credentials are handled prior to completing server initialization.


127-134: Preventing app exit on macOS until explicitly quit.
Overriding the default window-all-closed behavior aligns with typical macOS app standards. Hiding the dock is also a user-friendly approach.


150-151: Properly calling setVariableGlobal before splash screen.
This ensures any global config is in place before rendering or additional steps occur.


168-179: New setVariableGlobal function clarifies global state setup.
By extracting this logic, you promote a cleaner, more modular approach to updating global variables.

apps/agent/src/main/init/ipcMain.ts (7)

4-5: Use of ECMAScript import is appropriate.
The import from 'electron' plus the shell is valid. Consider the node: protocol only if it’s aligned with your project style.


13-14: Newly imported classes AppError, User, UserService highlight improved error handling and user management.
Ensure these classes are thoroughly tested to maintain reliability.

Also applies to: 16-16


18-20: Additional imports (AppWindow, moment, path) are consistent with new functionalities.
This broadens the capabilities for window management and date/time formatting.

🧰 Tools
🪛 Biome (1.9.4)

[error] 20-20: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


22-23: UserService instantiation introduced.
Centralizing user logic in a dedicated service fosters separation of concerns.


24-37: Extended getGlobalVariable with optional config.
This enhances flexibility when retrieving base URLs or local server flags, particularly useful for conditional server setups.


39-44: Graceful closeLoginWindow with delay.
Adding a small delay helps to ensure the UI is no longer in use, minimizing potential race conditions upon window destruction.


94-95: New IPC handlers improve config and authentication flow.

  • get-app-path retrieves the Electron app path.
  • app_setting centralizes application config retrieval.
  • AUTH_SUCCESS orchestrates user creation and stable login flow.
  • update_app_setting logs the update event and persists settings.
    These additions help unify the interplay between front-end and back-end states.

Also applies to: 100-101, 102-102, 104-119, 121-124

Comment thread packages/desktop-window/src/lib/desktop-window-auth.ts
Comment thread apps/agent/src/main/auth.ts
Comment thread apps/agent/src/main/auth.ts Outdated
Comment thread apps/server/src/index.ts
Comment thread apps/agent/src/main/window-manager.ts
Comment thread apps/agent/src/main/window-manager.ts Outdated
Comment thread packages/desktop-ui-lib/src/lib/settings/settings.component.ts
Comment thread packages/desktop-ui-lib/src/lib/settings/settings.component.ts Outdated
Comment thread packages/desktop-ui-lib/src/lib/settings/settings.component.ts Outdated
Comment thread packages/desktop-ui-lib/src/lib/settings/settings.component.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🔭 Outside diff range comments (1)
packages/desktop-ui-lib/src/lib/settings/settings.component.ts (1)

523-587: 🧹 Nitpick (assertive)

Consider adding error handling in getAppSetting.
While invoking IPC is straightforward, wrapping the async call in a try/catch block could improve resiliency and let you log errors gracefully.

🧰 Tools
🪛 Biome (1.9.4)

[error] 576-576: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

♻️ Duplicate comments (2)
packages/desktop-window/src/lib/desktop-window-auth.ts (1)

12-13: 🧹 Nitpick (assertive)

Unify references to authentication window rather than splash screen.

Line 13 still references "splash screen" despite the class name and usage focusing on authentication. Updating the doc comment can avoid confusion.

- * This class is responsible for creating and managing the splash screen.
+ * This class is responsible for creating and managing the authentication window.
apps/agent/src/main/auth.ts (1)

51-51: 🧹 Nitpick (assertive)

Correct the “choosed” spelling.

Minor grammatical fix for improved clarity and user-facing text correctness.

- // Do nothing when other than exit button choosed
+ // Do nothing when the user chooses any option other than exit
🧰 Tools
🪛 GitHub Check: Cspell

[warning] 51-51:
Unknown word (choosed)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 652ad4e and eab16e2.

📒 Files selected for processing (7)
  • apps/agent/src/main/auth.ts (1 hunks)
  • apps/agent/src/main/init/app.ts (8 hunks)
  • apps/agent/src/main/init/ipcMain.ts (3 hunks)
  • apps/agent/src/main/window-manager.ts (3 hunks)
  • packages/desktop-ui-lib/src/lib/settings/settings.component.ts (9 hunks)
  • packages/desktop-window/src/lib/desktop-window-auth.ts (1 hunks)
  • packages/ui-core/i18n/assets/i18n/en.json (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/desktop-ui-lib/src/lib/settings/settings.component.ts (1)
Learnt from: syns2191
PR: ever-co/ever-gauzy#8874
File: packages/desktop-ui-lib/src/lib/settings/settings.component.ts:493-493
Timestamp: 2025-03-28T14:31:13.570Z
Learning: In the Ever Gauzy codebase, some code is commented out rather than deleted when it's still required in other applications but not in the current context. For example, the `request_permission` IPC call in the SettingsComponent is needed in other apps but not in the agent app.
🧬 Code Definitions (1)
apps/agent/src/main/window-manager.ts (2)
packages/desktop-window/src/lib/desktop-window-auth.ts (1)
  • AuthWindow (15-52)
packages/desktop-window/src/lib/desktop-window-setting.ts (1)
  • createSettingsWindow (20-60)
🪛 GitHub Check: Cspell
apps/agent/src/main/auth.ts

[warning] 51-51:
Unknown word (choosed)

🪛 Biome (1.9.4)
apps/agent/src/main/init/ipcMain.ts

[error] 21-21: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: test
  • GitHub Check: build
🔇 Additional comments (24)
packages/desktop-ui-lib/src/lib/settings/settings.component.ts (10)

1-1: Well-done adding OnDestroy to the imports.
Including OnDestroy ensures that lifecycle management is clear for tasks like unsubscribing from streams or removing listeners.


32-32: Correct use of OnDestroy in the class signature.
Implementing OnDestroy here complements the new cleanup logic in ngOnDestroy.


57-57: Conditional usage of this.isAgent.
Extending this condition for the agent scenario appears logically consistent. Please verify all references to ensure consistent behavior.


405-405: Valid refinement in serverOptions for the agent scenario.
Restricting options when isAgent is true aligns with the streamlined needs of the agent application.


409-409: Conditional driver selection looks good.
Including 'mysql' only when isDesktopTimer or isAgent is sensible for targeted database support.


489-489: Binding this.handleIpcEvent is consistent.
Assigning this.handleIpcEvent = this.handleIpcEvent.bind(this) ensures the correct this context and avoids callback issues.


493-493: Commented-out code remains from previous instance.
This code was retained for potential reuse in other applications. This exact topic was discussed in a prior review.


519-522: Good practice cleaning up the event listener in ngOnDestroy.
Removing IPC listeners prevents memory leaks and ensures the component lifecycle is handled correctly.


565-566: Fetching user details for agent desktops.
Conditionally calling getUserDetails is consistent with the agent context. The logic looks accurate.


589-741: Refactor suggestion for large handleIpcEvent method.
This method uses a large switch statement with many case blocks. Splitting it into smaller handlers could improve maintainability. Identical to prior feedback on refactoring event handlers.

apps/agent/src/main/window-manager.ts (2)

21-25: Singleton initialization looks good.

The conditional assignment ensures AppWindow.instance is not overwritten if it already exists, following a standard singleton pattern.


127-127: Duplicate: Restrict DevTools in production.

Automatically toggling devTools can expose internal app details in production. Consider wrapping this call in a development check or removing it for production builds.

apps/agent/src/main/init/app.ts (4)

15-15: New authentication import looks good.
This addition cleanly integrates the checkUserAuthentication function into the current flow.


25-27: No issues with the appRootPath and appWindow singleton usage.
Encapsulating your AppWindow instantiation via getInstance is a neat way to enforce a single source of truth.


105-110: Authentication error handling is appropriately wrapped in try/catch.
Re-throwing as AppError ensures this process is logged and handled correctly.


154-154: Global variable assignment is straightforward.
Calling setVariableGlobal(configs) here is clear and does not pose immediate concerns.

apps/agent/src/main/init/ipcMain.ts (8)

4-5: New imports from Electron look good.
They align with the usage for opening external links and accessing the application object.


12-15: Additional imports from the desktop library are coherent with the new features.
Imports like AppError, User, UserService, and pluginListeners integrate well with the new authentication flow.


23-23: Instantiating UserService at module level is fine.
Just be mindful of potential overhead if this is a heavy service.


76-76: Global variable assignment matches your getGlobalVariable return.
This is consistent with the initialization flow.


101-101: Retrieving the app path on demand is a clean approach.
No issues noted.


103-103: IPC handler for app_setting is straightforward.
No concerns with returning LocalStore.getApplicationConfig().


127-127: Initializer call to pluginListeners is seamless.
No issues with the plugin initialization pattern.


105-120:

Details

❓ Verification inconclusive

Verify storage of sensitive user data.
This handler stores user details (including remoteId and organizationId). If personal data is involved, ensure compliance with any privacy requirements or sensitive data encryption policies.


🏁 Script executed:

#!/bin/bash
# Check how user data is stored and whether any encryption or secure handling is used
rg -A 5 "userService.save"

Length of output: 824


Action Required: Sensitive User Data Handling Verification

The IPC handler in apps/agent/src/main/init/ipcMain.ts stores user details (including remoteId and organizationId) via a call to userService.save(user.toObject());. A similar pattern is observed in packages/desktop-lib/src/lib/desktop-tray.ts, with no evidence of additional encryption or secure processing applied to these sensitive fields. Please verify that this plain storage method complies with your privacy and data protection requirements. If additional measures (such as encrypting sensitive fields or adding secure storage mechanisms) are expected, update the code accordingly or provide documentation justifying the current approach.

Comment on lines +4195 to 4197
"SELECT_FILE": "Select file",
"EXIT_AGENT_CONFIRM": "Oops! You need to log in before you can use the app."
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

New Agent Auth Localization Added

A new key has been introduced in the DIALOG section:

  • "SELECT_FILE": "Select file"
  • "EXIT_AGENT_CONFIRM": "Oops! You need to log in before you can use the app."

The addition of "EXIT_AGENT_CONFIRM" provides a clear, friendly prompt to inform users that they must log in before accessing certain functionality. Please verify that the tone and terminology are consistent with other similar user-facing messages in the application—as well as across all localization files—to ensure a seamless user experience. Also, double-check that the "SELECT_FILE" string is harmonized with file selection prompts used elsewhere in the platform.

Comment thread packages/desktop-window/src/lib/desktop-window-auth.ts
Comment thread apps/agent/src/main/window-manager.ts
Comment thread apps/agent/src/main/init/app.ts
Comment thread apps/agent/src/main/init/app.ts
Comment thread apps/agent/src/main/init/app.ts
Comment thread apps/agent/src/main/init/ipcMain.ts
Comment thread apps/agent/src/main/init/ipcMain.ts
Comment thread apps/agent/src/main/init/ipcMain.ts
Comment thread apps/agent/src/main/init/ipcMain.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eab16e2 and ac630ef.

📒 Files selected for processing (1)
  • apps/agent/src/main/window-manager.ts (3 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
apps/agent/src/main/window-manager.ts (2)
packages/desktop-window/src/lib/desktop-window-auth.ts (1)
  • AuthWindow (15-52)
packages/desktop-window/src/lib/desktop-window-setting.ts (1)
  • createSettingsWindow (20-60)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: build
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: test
🔇 Additional comments (5)
apps/agent/src/main/window-manager.ts (5)

4-6: Imports look good.
These new imports are properly used later in the code and help modularize window creation.


17-18: Consistent property initialization.
Declaring authWindow and settingWindow as nullable follows the same pattern as aboutWindow, ensuring clarity when windows are not yet created.


21-25: Singleton pattern looks correct.
Only setting AppWindow.instance once in the constructor is a valid approach to enforce the singleton contract.


27-29: No issues in getInstance logic.
The static method follows a suitable lazy singleton pattern.

Also applies to: 32-32


117-138: Duplicate note: Avoid toggling devTools by default.
For the settings window, always calling toggleDevTools() can expose advanced UI options to end users and potentially create security concerns in production. This was previously flagged as well.

Comment on lines +99 to +115
async initAuthWindow(): Promise<void> {
try {
if (!this.authWindow) {
this.authWindow = new AuthWindow(this.getUiPath('auth/login'), this.getPreloadPath(), true);
this.authWindow.config.options.titleBarStyle = 'hidden';
this.authWindow.config.options.titleBarOverlay = true;
this.authWindow.browserWindow.on('close', () => {
this.authWindow.browserWindow.destroy();
this.authWindow = null;
});
// this.authWindow.browserWindow.webContents.toggleDevTools();
}
} catch (error) {
console.error('Failed to initialize auth window', error);
throw new Error(`Auth Window initialization failed ${error.message}`);
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Consider removing commented code or gating devTools.
You have sensibly commented out toggleDevTools() for the auth window. If you only need it in development, consider wrapping it with an environment check or remove it entirely for cleaner production code.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/agent/src/main/window-manager.ts (1)

99-115: 🧹 Nitpick (assertive)

Optional: Remove or conditionally enable devTools.
You’ve commented out the toggleDevTools() call. If you only need it in development, consider wrapping it behind an environment check or removing it if not needed:

- // this.authWindow.browserWindow.webContents.toggleDevTools();
+ if (process.env.NODE_ENV === 'development') {
+   this.authWindow.browserWindow.webContents.toggleDevTools();
+ }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac630ef and 6595b7d.

📒 Files selected for processing (1)
  • apps/agent/src/main/window-manager.ts (3 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
apps/agent/src/main/window-manager.ts (2)
packages/desktop-window/src/lib/desktop-window-auth.ts (1)
  • AuthWindow (15-52)
packages/desktop-window/src/lib/desktop-window-setting.ts (1)
  • createSettingsWindow (20-60)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: test
  • GitHub Check: build
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
apps/agent/src/main/window-manager.ts (3)

4-6: Imports look correct and aligned with usage.
Everything appears consistent with the subsequent references to createSetupWindow, AuthWindow, and createSettingsWindow.


17-18: Properties for additional windows are clearly declared.
Storing them as null-initialized references follows a clean pattern for conditional instantiation.


117-138: [Duplicate] Using null as the first argument and devTools handling

  1. Passing null as the first argument to createSettingsWindow was previously flagged; it's functionally correct if the utility handles both null and undefined the same way, but you might document why or prefer undefined.
  2. Similarly to the auth window, consider conditionally toggling devTools or removing it completely if not used in production.

[duplicate_comment, suggest_nitpick]

- // this.settingWindow.webContents.toggleDevTools();
+ if (process.env.NODE_ENV === 'development') {
+   this.settingWindow.webContents.toggleDevTools();
+ }

Comment on lines +21 to 33
if (!AppWindow.instance) {
AppWindow.instance = this;
this.rootPath = rootPath;
}
}

static getInstance(rootPath: string): AppWindow {
if (!AppWindow.instance) {
AppWindow.instance = new AppWindow(rootPath);
return AppWindow.instance;
}
AppWindow.instance= this;
this.rootPath = rootPath;
return AppWindow.instance;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Consider making the constructor private to fully enforce the Singleton pattern.
Right now, the constructor can still be called from elsewhere. A private constructor ensures the instance must be obtained via getInstance().

-class AppWindow {
+class AppWindow private constructor(rootPath: string) {

Committable suggestion skipped: line range outside the PR's diff.

event.sender.send('database_status', {
status: true,
message: TranslateService.instant('TIMER_TRACKER.DIALOG.CONNECTION_DRIVER', { driver })
event.sender.send('setting_page_ipc', {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adkif please note those changes, not sure how they affect everything, but want to make sure you see this and if it's not good let us know!

@evereq evereq merged commit f22efec into develop Mar 30, 2025
18 of 19 checks passed
@evereq evereq deleted the feat/agent-auth-setting branch March 30, 2025 18:16
reinier-millo pushed a commit to DSpotDevelopers/DSpot-ERP that referenced this pull request May 1, 2025
* feat: added agent auth login page and setting page

* feat: enhance setting page agent and other app

* fix: auth and setting page enchancement

* fix: handle event ipc missing this

* feat: agent auth and setting page enhancement

* fix: styling and handle some error

* fix: styling and handle some error

* fix: styling and handle some error

* fix: styling and handle some error

* fix: styling and handle some error
@coderabbitai coderabbitai bot mentioned this pull request Jul 13, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants