Skip to content

Agent tour #598

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 35 commits into from
May 23, 2025
Merged

Agent tour #598

merged 35 commits into from
May 23, 2025

Conversation

swoopertr
Copy link
Contributor

@swoopertr swoopertr commented Apr 29, 2025

Describe your changes

1 - Fixed tooltip just showing last tooltip if 2 or more tips in the data.
2 - Fixed every guides borders.
3 - In Tour guide last and previous steps button name is fixed, changing accordingly.
4 - nginx configuration added in front end application.
Implementing tour agent and some other tasks.
issue number 541

@erenfn erenfn changed the base branch from master to develop April 29, 2025 22:56
Copy link
Contributor

coderabbitai bot commented May 6, 2025

Walkthrough

The updates introduce a fully functional guided tour UI module, adjust route authentication to allow unauthenticated access to tour details, and update several UI components' visual styles. Docker and deployment workflows are refactored to use npm scripts and clarify environment defaults. A new Nginx configuration and project-level package.json are added.

Changes

File(s) Change Summary
backend/src/routes/tour.routes.js Moved the GET /get_tour/:id route above JWT middleware, making it publicly accessible.
jsAgent/main.js Added BW_TOUR_DETAIL_JS_URL constant and a new async method bw.data.getTourById(tourId) for fetching tour details. Minor formatting change in initialization.
jsAgent/tour.js Expanded from placeholder to a full guided tour module under bw.tour, including state management, data fetching, UI dialog generation, navigation, dynamic positioning, element highlighting, completion tracking, and event handling.
jsAgent/banner.js Enhanced banner container styling with box-shadow and border via inline CSS.
jsAgent/hint.js Simplified the box-shadow style applied on hint button mouseenter events.
jsAgent/links.js Reduced z-index of the links widget container from 9999999 to 9990.
jsAgent/popup.js Updated modal content container styles: lighter border colour and new box-shadow value.
frontend/default.conf Added an Nginx server configuration file for serving static files, error handling, and commented PHP proxy templates.
backend/src/test/e2e/tour.test.mjs Removed test that checked for 401 Unauthorized when accessing tour details without a token.
.env Removed the NODE_ENV variable and its accompanying comment; other database variables remain.
.github/workflows/deploy.yml Replaced direct Docker Compose commands with npm script invocations for container management during deployment.
.github/workflows/node.js.yml Changed Docker container startup in CI from a direct Docker Compose command to sequential npm script invocations.
docker-compose.dev.yml Set NODE_ENV to default to "development" for backend/frontend. Simplified backend command to always run npm run dev. Changed frontend build to use context/dockerfile object, default NODE_ENV, and removed command.
docker-compose.prod.yml Set NODE_ENV to default to "production" for backend/frontend. Refined backend command to always attempt migration and run production server. Changed frontend build to use context/dockerfile object, expose port 80, default NODE_ENV, and removed command.
frontend/Dockerfile.development Removed duplicate bash install command. Set default command to run the development server (npm run dev).
package.json Added new project-level package.json with metadata and npm scripts for Docker Compose operations in development and production.
extention/app.js Consolidated menu button styling into a single cssText assignment. Cleaned up copy button event listeners and improved clipboard error handling.
frontend/Dockerfile.production Modified to copy a custom Nginx config (default.conf) into the container. Ensured correct command and file formatting.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant bw.tour (jsAgent/tour.js)
    participant bw.data (jsAgent/main.js)
    participant Backend API

    User->>bw.tour: Page loads
    bw.tour->>bw.data: getTourById(tourId)
    bw.data->>Backend API: GET /api/tour/get_tour/:id
    Backend API-->>bw.data: Tour data (public, no auth)
    bw.data-->>bw.tour: Tour data
    bw.tour->>User: Display guided tour dialog (step 1)
    User->>bw.tour: Click "Next"/"Previous"/pagination
    bw.tour->>User: Update dialog, highlight elements
    User->>bw.tour: Complete last step
    bw.tour->>bw.data: Send completion data (with user ID)
    bw.data->>Backend API: POST completion info
    Backend API-->>bw.data: Acknowledge
    bw.tour->>User: Remove tour dialog
Loading

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1f9708 and de6d779.

📒 Files selected for processing (1)
  • extention/app.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • extention/app.js
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @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.

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.

Copy link
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: 7

🧹 Nitpick comments (8)
backend/src/routes/tour.routes.js (1)

18-18: Unnecessary blank line

This blank line doesn't serve any purpose and could be removed to maintain consistent spacing in the file.

router.get('/tours', tourController.getToursByUserId);
-
jsAgent/main.js (1)

204-204: Unnecessary blank line

This blank line affects readability and is inconsistent with the spacing in the rest of the file.

console.log("data loaded:", onBoardConfig);
-          
window.bwonboarddata = onBoardConfig;
jsAgent/a.html (3)

59-72: SVG styling issues and duplicate properties

There are some issues with the SVG styling:

  1. display: block and display: inline-block are both specified
  2. !important is used excessively which makes styles hard to override
  3. Some properties like float: right alongside position: absolute are redundant

Consider cleaning up these styles for better maintainability.

closeButton.style.cssText = `
-   fill: rgb(152, 162, 179) !important; 
-   font-size: 20px !important; 
-   display: block !important; 
-   position: absolute !important; 
-   float: right !important; 
-   right: 23px !important; 
-   cursor: pointer !important; 
-   width: 20px !important; 
-   height: 20px !important; 
-   display: inline-block !important; 
-   margin: auto !important;
+   fill: rgb(152, 162, 179); 
+   font-size: 20px; 
+   position: absolute; 
+   right: 23px; 
+   cursor: pointer; 
+   width: 20px; 
+   height: 20px; 
+   display: inline-block; 
+   margin: auto;
`;

175-178: Improve the setActiveIndicator function

The current function resets all indicators and then sets the active one. This could be more efficient by directly targeting the previously active indicator.

Additionally, consider using CSS classes for active state rather than inline styles for better separation of concerns.

function setActiveIndicator(index) {
-   indicators.forEach(indicator => indicator.style.backgroundColor = '#ddd');
-   indicators[index].style.backgroundColor = '#673ab7';
+   // Find current active indicator and deactivate it
+   const activeIndicator = document.querySelector('.indicator.active');
+   if (activeIndicator) {
+     activeIndicator.classList.remove('active');
+     activeIndicator.style.backgroundColor = '#ddd';
+   }
+   // Activate the new indicator
+   indicators[index].classList.add('active');
+   indicators[index].style.backgroundColor = '#673ab7';
}

203-205: Improve the closeContainer function

The current function only hides the container but doesn't clean up event listeners, which could lead to memory leaks if the container is shown and hidden multiple times.

Consider fully removing the container or implementing a complete cleanup function.

function closeContainer() {
-   container.style.display = 'none'; // Or container.remove();
+   // Remove the container completely to clean up memory
+   container.remove();
+   // Alternatively, if you need to show it again later:
+   // container.style.display = 'none';
+   // Then implement a way to clear event listeners when appropriate
}
jsAgent/tour.js (3)

74-81: Unused parameter in createCloseButton

container is passed in but never referenced, which is confusing for readers and may hint at incomplete logic.

-createCloseButton: function (container) {
+createCloseButton: function () {

If you later need the container inside the SVG handler, you can capture it via closure when wiring the click listener rather than passing it here.


135-146: dialogItem parameter is accepted but ignored

generateDialog relies entirely on the global bw.tour.currentStep and bw.tour.tourData, rendering its dialogItem argument superfluous. Either use the parameter for clarity or remove it to keep the API tidy.


301-306: Optional chaining can simplify defensive code

Biome flags recommend options?.tour?.[0] to avoid a hard crash when bwonboarddata is missing. Worth adopting once the callback signature is corrected.

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b54bb1 and 86e30d3.

📒 Files selected for processing (5)
  • backend/.env (1 hunks)
  • backend/src/routes/tour.routes.js (1 hunks)
  • jsAgent/a.html (1 hunks)
  • jsAgent/main.js (3 hunks)
  • jsAgent/tour.js (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
jsAgent/tour.js

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)
🔇 Additional comments (2)
jsAgent/main.js (1)

5-5: Good addition of constant for API endpoint

Adding a constant for the tour detail endpoint URL is a good practice. This makes the code more maintainable and follows the pattern used for other endpoints.

jsAgent/tour.js (1)

117-118: Next button disabling logic could block tour completion

nextButton.disabled is computed once at creation (currentStep === lastStep). When the user eventually reaches the last step via navigation, the button is still enabled, but if the tour ever starts at the last step (edge-case or resumed session) it will be disabled and stay that way, preventing completion. Consider recomputing disabled inside setActiveIndicator.

@@ -10,12 +10,12 @@ const router = express.Router();
const teamPermissions = settings.team.permissions.tours;

router.get('/get_tour_by_url', bodyUrlValidator, handleValidationErrors, tourController.getTourByUrl);

router.get('/get_tour/:id', tourController.getTourById);
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Security consideration: Exposing tour data publicly

Moving the getTourById endpoint above the JWT authentication middleware makes this endpoint publicly accessible. Ensure that this endpoint doesn't expose sensitive data and implement appropriate rate limiting to prevent abuse.

Consider adding request validation to prevent potential injection attacks through the ID parameter.


🏁 Script executed:

#!/bin/bash
# Check how the tour controller handles the ID parameter
echo "Examining tour controller implementation for getTourById:"
find backend/src -name "tour.controller.js" -exec cat {} \; | grep -A 15 "getTourById"

Length of output: 737


Secure and Validate getTourById Endpoint

  • The route at backend/src/routes/tour.routes.js:13 is currently public (no JWT auth). Confirm that it’s acceptable to expose tour data without authentication and that no sensitive fields (internal notes, admin-only flags, etc.) are returned.

  • Implement rate limiting (e.g., with express-rate-limit) on this endpoint to guard against enumeration or DoS attacks.

  • Validate the :id parameter (e.g., using express-validator or Joi) to ensure it’s a well-formed identifier (UUID or MongoDB ObjectId) and to prevent injection attacks.

  • If this endpoint should require authentication, move it below your JWT middleware:

    - router.get('/get_tour/:id', tourController.getTourById);
    + router.get(
    +   '/get_tour/:id',
    +   rateLimiter,
    +   param('id').isMongoId(),      // or .isUUID()
    +   handleValidationErrors,
    +   jwtMiddleware,
    +   tourController.getTourById
    + );

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

Copy link
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: 3

♻️ Duplicate comments (5)
jsAgent/tour.js (5)

83-87: Un-sanitised HTML opens the door to XSS

p.innerHTML = content; assumes the backend always delivers safe markup. If a malicious script sneaks into tourData.description, it runs in your users' browsers with full privileges. Prefer textContent, or run the HTML through a trusted sanitiser (DOMPurify, etc.).

-        p.innerHTML = content;
+        // If rich HTML is required, run `content` through a sanitizer first.
+        p.textContent = content;

Better safe than sorry when mom's spaghetti is on the keyboard.


255-261: updatePosition crashes when the target selector is missing

document.querySelector(...) can return null; calling getBoundingClientRect() on it will throw. Guard against missing or transient elements and provide a graceful fallback.

        function updatePosition() {
-            const targetElement = document.querySelector(bw.tour.tourData.steps[bw.tour.currentStep].targetElement);
-            //update container position according to target element with smooth animation transition
-            const rect = targetElement.getBoundingClientRect();
+            const targetElement = document.querySelector(
+                bw.tour.tourData.steps[bw.tour.currentStep].targetElement
+            );
+            if (!targetElement) {
+                console.warn("Target element not found for step", bw.tour.currentStep);
+                return;
+            }
+            // Update container position according to target element with smooth animation transition
+            const rect = targetElement.getBoundingClientRect();

This avoids a runtime exception that would abruptly end the tour.


296-316: Mismatch between declared docs, call-site and implementation silently drops the error-callback

loadFloatingUILibraries is documented (295-299) – and invoked in init (15-22) – with two callbacks, yet the function signature only accepts one.
As a result, the failure path you intend to handle is swallowed, and init proceeds to dereference result.id, which will blow up if the scripts failed to load.

-    loadFloatingUILibraries: function (cb) {
+    // Accept both success & error callbacks
+    loadFloatingUILibraries: function (cb, errCb) {
...
-                cb && cb(options);
+                cb?.call(null, options);            // success
...
-                console.error("Failed to load @floating-ui/dom:", err);
-                cb && cb(false);
+                console.error("Failed to load @floating-ui/dom:", err);
+                errCb ? errCb(err) : cb?.call(null, false);
...
-                console.error("Failed to load @floating-ui/core:", err);
-                cb && cb(false);
+                console.error("Failed to load @floating-ui/core:", err);
+                errCb ? errCb(err) : cb?.call(null, false);

Without this fix, a network hiccup will crash the tour and leave the user staring at a blank page—knees weak, arms heavy.

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


250-253: ⚠️ Potential issue

Another un-sanitised HTML vulnerability

Similar to the earlier issue, the updateData function uses innerHTML to update the description, creating another potential XSS vulnerability.

    function updateData() {
        document.getElementById('bw-tour-header').textContent = bw.tour.tourData.steps[bw.tour.currentStep].header;
-       document.getElementById('bw-tour-description').innerHTML = bw.tour.tourData.steps[bw.tour.currentStep].description;
+       document.getElementById('bw-tour-description').textContent = bw.tour.tourData.steps[bw.tour.currentStep].description;
    }

There's vomit on his sweater already from another XSS vulnerability.


14-23: ⚠️ Potential issue

Fix the init function to handle potential null result

The init function assumes result is always valid and contains an id property. If script loading fails, result might be false, causing a runtime error when accessing result.id.

     init: function (cb) {
-        this.loadFloatingUILibraries(async (result) => {
+        this.loadFloatingUILibraries(async (result) => {
+            if (!result || !result.id) {
+                console.warn("Failed to initialize tour: invalid result");
+                cb && cb(false);
+                return;
+            }
             const tourId = result.id;
             const tourData = await bw.data.getTourById(tourId);
             bw.tour.tourData = tourData;
-            cb && cb(tourData);
+            cb?.call(null, tourData);
         }, () => {
-            cb && cb(false);
+            cb?.call(null, false);
         });
     },

Gotta make sure we handle that null result—knees weak, code's heavy.

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🧹 Nitpick comments (7)
jsAgent/hint.js (4)

50-51: Clean up that comment about deleting code

There's a comment indicating that the positionTooltip function can be deleted later, but it's still being used on line 333. Either remove the function if it's truly not needed or remove the comment if the function should stay.

If the function is no longer needed:

-    //this can be delete later
-    positionTooltip: function(tooltip, tooltipOwner, tooltipArrow) {
-       /* function body */
-    },

Also make sure to remove the reference on line 333:

-                    bw.hint.positionTooltip(tooltip,  e.target, tooltipArrow);

Or if the function should stay, just remove the misleading comment:

-    //this can be delete later
     positionTooltip: function(tooltip, tooltipOwner, tooltipArrow) {

33-33: Clean up that commented code, mom's spaghetti

There's commented-out code that calls positionTooltip. Either restore the functionality or remove the commented line entirely to keep the code clean.

-            //bw.hint.positionTooltip(tooltip, contentContainer, tooltipArrow);

38-38: Clean up more commented code

Another instance of commented-out code that should be removed for cleanliness.

-                //bw.hint.positionTooltip(tooltip, contentContainer, tooltipArrow);

248-249: Empty lines added, knees weak

These empty lines don't affect functionality but seem unnecessary. Consider removing them to keep the code tighter.

-
-        
jsAgent/tour.js (3)

319-329: Allow for delayed or conditional tour initialization

The current implementation immediately initializes and displays the tour on script load, which can be jarring for users. Consider providing configuration options to delay or conditionally start the tour.

 (function () {
-    bw.tour.init((tourData) => {
-        if (tourData) {
-            console.log("Tour initialized successfully!");
-            console.log(tourData);
-            bw.tour.showTour(tourData);
-        } else {
-            console.warn("Tour initialization failed.");
-        }
-    });
+    // Expose a method to explicitly start the tour
+    bw.tour.start = function(options = {}) {
+        const { autoShow = true, onSuccess, onFailure } = options;
+        
+        bw.tour.init((tourData) => {
+            if (tourData) {
+                console.log("Tour initialized successfully!");
+                if (autoShow) {
+                    bw.tour.showTour(tourData);
+                }
+                onSuccess && onSuccess(tourData);
+            } else {
+                console.warn("Tour initialization failed.");
+                onFailure && onFailure();
+            }
+        });
+    };
+    
+    // Check if auto-start is disabled
+    if (window.bwDisableAutoTour !== true) {
+        bw.tour.start();
+    }
 })();

Mom's spaghetti—let users opt-in rather than forcing the tour on them immediately.


38-50: Extract styling to CSS classes for better maintainability

Inline styles make the code harder to maintain and override. Consider moving styles to external CSS classes.

    createContainer: function () {
        const container = document.createElement('div');
        container.className = 'bw-tour-container';
-        container.style.cssText = `
-            border-radius: 8px;
-            box-shadow: 2px 2px 10px 0px #0000000D;
-            border: 1px solid #F0F0F0 !important;
-            position: relative;
-            max-width: 400px;
-            width: 90%;
-          `;     
+        // Apply predefined CSS class with styles
        return container;
    },

Cleanup on this spaghetti code would reduce maintenance burden—add a stylesheet with the appropriate classes for all tour UI elements.


25-36: Update function documentation to match implementation

The JSDoc for showTour doesn't match the actual implementation. It describes generating a dialog item but the function is actually showing a tour.

    /**
-     * Generates a dialog item.  Currently, this function is empty.
-     * @param {object} dialogItem - The dialog item to generate.
+     * Displays the tour dialog for the current step.
+     * @param {object} tourData - The tour data containing steps and styling information.
     * @returns {void}
     */
    showTour: function (tourData) {

Documentation weak, implementation heavy—fix the JSDoc to properly describe what the function does.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 86e30d3 and 0cfcaf7.

📒 Files selected for processing (5)
  • jsAgent/banner.js (1 hunks)
  • jsAgent/hint.js (1 hunks)
  • jsAgent/links.js (1 hunks)
  • jsAgent/popup.js (1 hunks)
  • jsAgent/tour.js (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • jsAgent/links.js
  • jsAgent/banner.js
  • jsAgent/popup.js
🧰 Additional context used
🪛 Biome (1.9.4)
jsAgent/tour.js

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)

Copy link
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: 3

♻️ Duplicate comments (5)
jsAgent/tour.js (5)

89-89: Un-sanitised HTML opens the door to XSS

p.innerHTML = content; assumes the backend always delivers safe markup. If a malicious script sneaks into tourData.description, it runs in your users' browsers with full privileges. Prefer textContent, or run the HTML through a trusted sanitiser (DOMPurify, etc.).

-        p.innerHTML = content;
+        // If rich HTML is required, run `content` through a sanitizer first.
+        p.textContent = content;

Better safe than sorry when mom's spaghetti is on the keyboard.


258-269: updatePosition crashes when the target selector is missing

document.querySelector(...) can return null; calling getBoundingClientRect() on it will throw. Guard against missing or transient elements and provide a graceful fallback.

-        function updatePosition() {
-            const targetElement = document.querySelector(bw.tour.tourData.steps[bw.tour.currentStep].targetElement);
-            //update container position according to target element with smooth animation transition
-            const rect = targetElement.getBoundingClientRect();
+        function updatePosition() {
+            const targetElement = document.querySelector(
+                bw.tour.tourData.steps[bw.tour.currentStep].targetElement
+            );
+            if (!targetElement) {
+                console.warn("Target element not found for step", bw.tour.currentStep);
+                return;
+            }
+            // Update container position according to target element with smooth animation transition
+            const rect = targetElement.getBoundingClientRect();
             container.style.left = `${rect.left + window.scrollX}px`;
             container.style.top = `${rect.top + window.scrollY}px`;
             container.style.transform = `translate(-50%, 0%)`;

This avoids a runtime exception that would abruptly end the tour.


283-289: Add error handling for data submission

The handleNext function calls bw.data.sendData but doesn't handle any errors that might occur during submission.

        function handleNext() {
            if (bw.tour.currentStep === indicators.length - 1) {
-                bw.data.sendData(bw.GuideType.TOUR, bw.user.getUserID(), true, bw.tour.tourData.id);
-                console.log("Tour completed");
-                container.remove();
-                return;
+                try {
+                    const userId = bw.user.getUserID();
+                    if (!userId) {
+                        console.warn("Cannot send tour completion: user ID not available");
+                    } else {
+                        bw.data.sendData(bw.GuideType.TOUR, userId, true, bw.tour.tourData.id)
+                            .catch(err => console.error("Failed to send tour completion data:", err));
+                    }
+                    console.log("Tour completed");
+                    container.remove();
+                    return;
+                } catch (err) {
+                    console.error("Error during tour completion:", err);
+                    container.remove();
+                    return;
+                }

Palms are sweaty thinking about those unhandled exceptions.


299-319: Mismatch between declared docs, call-site and implementation silently drops the error-callback

loadFloatingUILibraries is documented (299-302) – and implemented with error callbacks (311-318) – but its signature (304) doesn't include the second callback parameter.

-    loadFloatingUILibraries: function (cb) {
+    // Accept both success & error callbacks
+    loadFloatingUILibraries: function (cb, errCb) {
         bw.util.loadScriptAsync(FLOATING_UI_CORE_URL, () => {
             console.log("@floating-ui/core loaded successfully");
             bw.util.loadScriptAsync(FLOATING_UI_DOM_URL, () => {
                 console.log("@floating-ui/dom loaded successfully");
+                if (!window.bwonboarddata?.tour?.length) {
+                    console.error("Tour data not found in window.bwonboarddata.tour");
+                    errCb ? errCb(new Error("Tour data missing")) : cb?.(false);
+                    return;
+                }
                 const options = window.bwonboarddata.tour[0];
-                cb && cb(options);
+                cb?.(options);
             }, (err) => {
                 console.error("Failed to load @floating-ui/dom:", err);
-                cb && cb(false);
+                errCb ? errCb(err) : cb?.(false);
             });
         }, (err) => {
             console.error("Failed to load @floating-ui/core:", err);
-            cb && cb(false);
+            errCb ? errCb(err) : cb?.(false);
         });
     }

Knees weak, arms heavy thinking about all these callback inconsistencies.

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


255-255: ⚠️ Potential issue

Un-sanitised HTML creates XSS vulnerability in dynamic updates

Similar to the initial content setting, innerHTML is used during updates without sanitization, creating an XSS vulnerability.

-            document.getElementById('bw-tour-description').innerHTML = bw.tour.tourData.steps[bw.tour.currentStep].description;
+            // If rich HTML is required, use a sanitizer library like DOMPurify
+            document.getElementById('bw-tour-description').textContent = bw.tour.tourData.steps[bw.tour.currentStep].description;

Palms sweaty just thinking about those script injections via tour step descriptions. Stay safe!

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a4bfeaf and 72aeef3.

📒 Files selected for processing (1)
  • jsAgent/tour.js (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
jsAgent/tour.js

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)

@swoopertr swoopertr assigned swoopertr and unassigned swoopertr May 20, 2025
@swoopertr swoopertr requested a review from erenfn May 20, 2025 06:44
Copy link
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: 3

♻️ Duplicate comments (6)
jsAgent/tour.js (6)

15-17: ⚠️ Potential issue

Missing checks for window.bwonboarddata could crash the tour initialization

The code directly accesses window.bwonboarddata.tour[0] without checking if these objects exist first. If they're undefined, your users will be staring at a blank page with console errors.

-    init : async function (cb) {
-        const result = window.bwonboarddata.tour[0];
-        const tourId = result.id;
+    init : async function (cb) {
+        if (!window.bwonboarddata?.tour?.length) {
+            console.error('Tour data not available in window.bwonboarddata.tour');
+            cb?.(false);
+            return;
+        }
+        const result = window.bwonboarddata.tour[0];
+        const tourId = result.id;

Mom's spaghetti all over the keyboard when this crashes in production!


32-39: ⚠️ Potential issue

showTour ignores the passed tourData parameter

The showTour function accepts a tourData parameter but then ignores it, relying on the global bw.tour.tourData instead. This can lead to inconsistent behavior.

-    showTour: function (tourData) {
+    showTour: function (tourData) {
         if (!tourData) {
             console.error('No tour data provided');
             return;
         }
-       
+        // Set the module's tourData if it was passed as a parameter
+        if (tourData !== bw.tour.tourData) {
+            bw.tour.tourData = tourData;
+        }
+        
         this.showDialog(bw.tour.currentStep);
     },

There's vomit on his sweater already when parameters are ignored like this.


86-99: ⚠️ Potential issue

Un-sanitised HTML opens the door to XSS

Using innerHTML without sanitization can allow malicious script injection. If a malicious script gets into content, it will run with full privileges in your users' browsers.

-        p.innerHTML = content;
+        // If rich HTML is required, run `content` through a sanitizer first.
+        p.textContent = content;

Palms are sweaty thinking about those XSS vulnerabilities!


258-269: ⚠️ Potential issue

updatePosition crashes when the target selector is missing

document.querySelector(...) can return null; calling getBoundingClientRect() on it will throw an exception. Need to guard against missing elements.

-        function updatePosition() {
-            const targetElement = document.querySelector(bw.tour.tourData.steps[bw.tour.currentStep].targetElement);
-            //update container position according to target element with smooth animation transition
-            const rect = targetElement.getBoundingClientRect();
+        function updatePosition() {
+            const targetElement = document.querySelector(
+                bw.tour.tourData.steps[bw.tour.currentStep].targetElement
+            );
+            if (!targetElement) {
+                console.warn("Target element not found for step", bw.tour.currentStep);
+                return;
+            }
+            // Update container position according to target element with smooth animation transition
+            const rect = targetElement.getBoundingClientRect();

There's vomit on his sweater already, mom's spaghetti, when this crashes mid-tour.


314-324: 🛠️ Refactor suggestion

Missing error callback in init call creates incomplete error handling

The initialization code doesn't provide an error callback to handle failures in loading the necessary libraries, and directly uses the success callback path.

 (function () {
-    bw.tour.init((tourData) => {
+    bw.tour.init((tourData) => {
         if (tourData) {
             console.log("Tour initialized successfully!");
             console.log(tourData);
             bw.tour.showTour(tourData);
         } else {
             console.warn("Tour initialization failed.");
         }
+    }, (error) => {
+        console.error("Tour initialization failed with error:", error);
     });
 })();

Palms are sweaty thinking about all those silent errors in the console.


254-256: ⚠️ Potential issue

Duplicate XSS vulnerability in updateData

Another instance of using innerHTML without sanitization. This creates the same XSS vulnerability.

-            document.getElementById('bw-tour-description').innerHTML = bw.tour.tourData.steps[bw.tour.currentStep].description;
+            document.getElementById('bw-tour-description').textContent = bw.tour.tourData.steps[bw.tour.currentStep].description;

Arms are heavy just thinking about all these XSS vulnerabilities.

🧹 Nitpick comments (6)
frontend/Dockerfile (3)

1-6: Great use of multi-stage build for a slimmer image
Leveraging node:22-alpine3.21, copying only package*.json before npm ci, and isolating the build step all help cache efficiency and reproducibility.
Suggest adding a .dockerignore (if not already present) to exclude node_modules, dist, etc., and keep the context lean.

Example .dockerignore:

node_modules
dist

8-9: Second stage: pin Nginx, add healthcheck and drop root
Switching to nginx:alpine is sound for serving static assets, but consider:

  • Pinning a specific minor version (e.g. nginx:1.25-alpine) for stability.
  • Adding a HEALTHCHECK to let orchestrators detect broken containers.
  • Dropping privileges by switching to a non-root user (e.g. USER nginx).
 FROM nginx:alpine
+HEALTHCHECK --interval=30s --timeout=5s \
+  CMD curl -f http://localhost/ || exit 1
 COPY --from=builder /app/dist /usr/share/nginx/html
 EXPOSE 80
+USER nginx
 CMD ["nginx", "-g", "daemon off;"]

Also applies to: 11-12


10-10: Clean up or enable your custom Nginx config
The commented-out COPY nginx.conf line could either be removed to reduce noise or enabled if you need custom routing or headers.

jsAgent/tour.js (3)

18-25: Use optional chaining for callback invocations

The callbacks might be undefined, leading to runtime errors. Optional chaining would make this code more robust.

-            cb && cb(tourData);
+            cb?.(tourData);
-            cb && cb(false);
+            cb?.(false);

Knees weak thinking about those potential undefined callbacks.

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


141-150: Remove commented-out code that's not useful for documentation

These commented lines appear to be development notes with sample values rather than meaningful documentation. They clutter the code without adding value.

-        /**
-        buttonBackgroundColor: "#d22828"
-        buttonTextColor: "#FFFFFF"
-        finalButtonText: "Complete tour"
-        ==headerColor: "#1f5fe0"
-        size: "small"
-        textColor: "#59ff00"
-        * 
-        */

Knees weak, arms are heavy looking at this leftover development cruft in production code.


79-82: Avoid hardcoding SVG strings in JavaScript

The SVG for the close button is hardcoded as a string, making it difficult to maintain. Consider creating a utility function or using a proper icon library.

-        const closeButton = `<svg id='bw-modal-close' focusable="false" viewBox="0 0 24 24" data-testid="CloseOutlinedIcon" 
-            style="fill: rgb(152, 162, 179) !important; font-size: 20px !important; display: block !important; position: absolute !important; float: right !important; right: 23px !important; cursor: pointer !important; width: 20px !important; height: 20px !important; display: inline-block !important; margin: auto !important;">
-            <path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
-        </svg>`
+        const closeButton = bw.util.createCloseIcon('bw-modal-close', {
+            fill: 'rgb(152, 162, 179)',
+            size: '20px',
+            position: 'absolute',
+            right: '23px',
+            cursor: 'pointer'
+        });

Mom's spaghetti all over my code when I have to update that SVG string later.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 72aeef3 and 5e21cb5.

📒 Files selected for processing (5)
  • frontend/Dockerfile (1 hunks)
  • frontend/Dockerfile_backup (1 hunks)
  • frontend/Dockerfile_nginx_html (0 hunks)
  • jsAgent/main.js (3 hunks)
  • jsAgent/tour.js (1 hunks)
💤 Files with no reviewable changes (1)
  • frontend/Dockerfile_nginx_html
✅ Files skipped from review due to trivial changes (1)
  • frontend/Dockerfile_backup
🚧 Files skipped from review as they are similar to previous changes (1)
  • jsAgent/main.js
🧰 Additional context used
🪛 Biome (1.9.4)
jsAgent/tour.js

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)

Copy link
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 (6)
jsAgent/tour.js (6)

328-338: Missing error callback in init call

The initialization code doesn't provide an error callback to handle failures in loading the necessary libraries.

 (function () {
-    bw.tour.init((tourData) => {
+    bw.tour.init((tourData) => {
         if (tourData) {
             console.log("Tour initialized successfully!");
             console.log(tourData);
             bw.tour.showTour(tourData);
         } else {
             console.warn("Tour initialization failed.");
         }
+    }, (error) => {
+        console.error("Tour initialization failed with error:", error);
     });
 })();

There's vomit on his sweater already thinking about all the uncaught promise rejections in the console!


3-4: 🛠️ Refactor suggestion

Use versioned imports with integrity hashes for external scripts

Loading external scripts without integrity hashes creates a security risk. If the CDN is compromised, malicious code could be injected.

-const FLOATING_UI_CORE_URL = "https://cdn.jsdelivr.net/npm/@floating-ui/[email protected]";
-const FLOATING_UI_DOM_URL = "https://cdn.jsdelivr.net/npm/@floating-ui/[email protected]";
+const FLOATING_UI_CORE_URL = "https://cdn.jsdelivr.net/npm/@floating-ui/[email protected]/dist/floating-ui.core.umd.min.js";
+const FLOATING_UI_CORE_INTEGRITY = "sha384-[actual hash value here]";
+const FLOATING_UI_DOM_URL = "https://cdn.jsdelivr.net/npm/@floating-ui/[email protected]/dist/floating-ui.dom.umd.min.js";
+const FLOATING_UI_DOM_INTEGRITY = "sha384-[actual hash value here]";

Palms are sweaty thinking about CDN compromise attacks!


15-25: ⚠️ Potential issue

Eliminate redundant API call and fix potential race condition

The code accesses window.bwonboarddata.tour[0] without checking if it exists first, which could cause errors if the tour data isn't available.

-    init : async function (cb) {
-        const result = window.bwonboarddata.tour[0];
-        const tourId = result.id;
-        
-        bw.data.getTourById(tourId).then((tourData) => {
-            console.log(tourData);
-            bw.tour.tourData = tourData;
-            cb && cb(tourData);
-        }).catch((error) => {
-            console.error('Error fetching tour data:', error);
-            cb && cb(false);
-        });
+    init : async function (cb) {
+        if (!window.bwonboarddata?.tour?.length) {
+            console.error('Tour data not available in window.bwonboarddata.tour');
+            cb?.(false);
+            return;
+        }
+        const result = window.bwonboarddata.tour[0];
+        const tourId = result.id;
+        bw.data.getTourById(tourId).then((tourData) => {
+            console.log(tourData);
+            bw.tour.tourData = tourData;
+            cb?.(tourData);
+        }).catch((error) => {
+            console.error('Error fetching tour data:', error);
+            cb?.(false);
+        });

Mom's spaghetti would fall right out of her arms seeing this potential error source!

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


32-39: ⚠️ Potential issue

Verify tourData parameter is consistent with module data

The showTour function accepts a tourData parameter but then ignores it and uses bw.tour.tourData instead. This can lead to inconsistent behavior.

-    showTour: function (tourData) {
-        if (!tourData) {
-            console.error('No tour data provided');
-            return;
-        }
-       
-        this.showDialog(bw.tour.currentStep);
+    showTour: function (tourData) {
+        if (!tourData) {
+            console.error('No tour data provided');
+            return;
+        }
+        
+        // Set the module's tourData if it was passed as a parameter
+        if (tourData !== bw.tour.tourData) {
+            bw.tour.tourData = tourData;
+        }
+        
+        this.showDialog(bw.tour.currentStep);

Mom's spaghetti all over the place when parameters are ignored like this!


89-89: ⚠️ Potential issue

Un-sanitised HTML opens the door to XSS

p.innerHTML = content; assumes the backend always delivers safe markup. If a malicious script sneaks into tourData.description, it runs in your users' browsers with full privileges.

-        p.innerHTML = content;
+        // If rich HTML is required, run `content` through a sanitizer first.
+        p.textContent = content;

Better safe than sorry when mom's spaghetti is on the keyboard!


258-264: ⚠️ Potential issue

updatePosition crashes when the target selector is missing

document.querySelector(...) can return null; calling getBoundingClientRect() on it will throw. Guard against missing or transient elements.

-        function updatePosition() {
-            const targetElement = document.querySelector(bw.tour.tourData.steps[bw.tour.currentStep].targetElement);
-            //update container position according to target element with smooth animation transition
-            const rect = targetElement.getBoundingClientRect();
-            container.style.left = `${rect.left + window.scrollX}px`;
-            container.style.top = `${rect.top + window.scrollY}px`;
-            container.style.transform = `translate(-50%, 0%)`;
+        function updatePosition() {
+            const targetElement = document.querySelector(
+                bw.tour.tourData.steps[bw.tour.currentStep].targetElement
+            );
+            if (!targetElement) {
+                console.warn("Target element not found for step", bw.tour.currentStep);
+                return;
+            }
+            // Update container position according to target element with smooth animation transition
+            const rect = targetElement.getBoundingClientRect();
+            container.style.left = `${rect.left + window.scrollX}px`;
+            container.style.top = `${rect.top + window.scrollY}px`;
+            container.style.transform = `translate(-50%, 0%)`;

This avoids a runtime exception that would abruptly end the tour and have vomit on your sweater already!

🧹 Nitpick comments (3)
docker-compose_dev.yml (1)

53-53: Remove trailing whitespace

There's trailing whitespace on this line that should be removed.

-    
+

Mom's spaghetti all over the keyboard with these trailing spaces!

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 53-53: trailing spaces

(trailing-spaces)

docker-compose_production.yml (1)

43-43: Remove trailing whitespace in multiple lines

There's trailing whitespace on lines 43 and 53 that should be removed.

-    build: 
+    build:
-    
+

Palms are sweaty seeing these trailing spaces in a production configuration!

Also applies to: 53-53

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 43-43: trailing spaces

(trailing-spaces)

jsAgent/tour.js (1)

120-121: Add keyboard accessibility attributes to buttons

To improve accessibility, add appropriate attributes like aria-label to provide context for screen reader users.

        const nextButton = document.createElement('button');
        nextButton.className = 'next-button';
        nextButton.textContent = 'Next';
        nextButton.disabled = bw.tour.currentStep === bw.tour.tourData.steps.length - 1;
+       nextButton.setAttribute('aria-label', 'Go to next step');

Knees weak thinking about keyboard users trying to navigate without proper accessibility attributes!

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 5e21cb5 and 0651a18.

📒 Files selected for processing (6)
  • .env (1 hunks)
  • docker-compose_dev.yml (1 hunks)
  • docker-compose_production.yml (1 hunks)
  • frontend/default.conf (1 hunks)
  • frontend/dockerfile.production (1 hunks)
  • jsAgent/tour.js (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • .env
  • frontend/dockerfile.production
  • frontend/default.conf
🧰 Additional context used
🪛 YAMLlint (1.37.1)
docker-compose_dev.yml

[error] 43-43: trailing spaces

(trailing-spaces)


[error] 53-53: trailing spaces

(trailing-spaces)

docker-compose_production.yml

[error] 43-43: trailing spaces

(trailing-spaces)


[error] 53-53: trailing spaces

(trailing-spaces)

🪛 Biome (1.9.4)
jsAgent/tour.js

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)
🔇 Additional comments (7)
docker-compose_dev.yml (2)

43-45: Nice job configuring dynamic Docker build selection based on environment!

The new build configuration with context and dynamic dockerfile selection is a solid approach. This allows you to maintain separate Dockerfiles for different environments while keeping the compose file structure consistent.

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 43-43: trailing spaces

(trailing-spaces)


50-50: Port change to standard HTTP port improves accessibility

Changing from port 4173 to port 80 makes the frontend service accessible through standard HTTP port, which aligns with the new Nginx configuration mentioned in the PR objectives.

docker-compose_production.yml (1)

1-62: Great production setup with all necessary services

The production Docker Compose configuration is well-structured with all required services for a complete deployment environment. The configuration is consistent with the development setup while making appropriate adjustments for production use.

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 43-43: trailing spaces

(trailing-spaces)


[error] 53-53: trailing spaces

(trailing-spaces)

jsAgent/tour.js (4)

309-320: Great job adding resize and scroll event listeners for repositioning!

I like how you've added event listeners to reposition the tour dialog when the window is resized or scrolled, and you're properly cleaning up the listeners when the container is removed. This is excellent for maintaining proper UI alignment.


286-301: Good error handling for data submission

Great job implementing proper error handling for the data submission when completing the tour. The try-catch block and the additional checks for user ID availability are excellent defensive programming practices.


241-242: Good button text update for the final step

Nice job changing the "Next" button text to use the finalButtonText property from the tour data on the last step. This provides a clearer indication to users that they're completing the tour.


45-48: Improved container border style

The border styling with !important ensures the border will be visible regardless of any inherited styles. This aligns with the PR objective to fix guide borders.

Copy link
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: 2

♻️ Duplicate comments (5)
jsAgent/tour.js (5)

3-4: Use versioned imports with integrity hashes for external scripts

Loading external scripts without integrity hashes is a security risk. If the CDN is compromised, malicious code could be injected.

Palms are sweaty thinking about CDN compromise attacks! This issue was previously flagged but hasn't been addressed yet.


15-16: Guard against missing tour data to prevent runtime errors

Accessing window.bwonboarddata.tour[0] without null checks will cause the tour to crash if the data structure is missing or empty.

There's vomit on his sweater already thinking about those undefined property access errors when the tour data is missing! This was flagged before but still needs addressing.


126-126: XSS vulnerability in content rendering

Using innerHTML to render potentially untrusted content creates an XSS vulnerability. If malicious script content reaches the tour description, it will execute in users' browsers.

Better safe than sorry when mom's spaghetti contains malicious scripts! This critical security issue was flagged before but still exists.


286-286: Same XSS vulnerability in updateData function

The innerHTML usage here has the same security vulnerability as the generateContent function.

Knees weak thinking about this XSS vulnerability that's been flagged before but remains unfixed!


290-292: Target element null check missing

document.querySelector() can return null, and calling getBoundingClientRect() on null will throw a runtime exception.

There's vomit on his sweater already when updatePosition crashes because the target selector is missing! This was previously identified but hasn't been fixed.

🧹 Nitpick comments (1)
jsAgent/tour.js (1)

45-45: Use optional chaining for cleaner null-safe callback invocation

The static analysis tool correctly suggests using optional chaining for callback invocation to improve code readability.

-            cb && cb(tourData);
+            cb?.(tourData);
-            cb && cb(false);
+            cb?.(false);

Knees weak thinking about all those manual null checks when optional chaining exists!

Also applies to: 48-48

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0651a18 and 289036c.

📒 Files selected for processing (2)
  • jsAgent/links.js (1 hunks)
  • jsAgent/tour.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • jsAgent/links.js
🧰 Additional context used
🪛 Biome (1.9.4)
jsAgent/tour.js

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)
🔇 Additional comments (2)
jsAgent/tour.js (2)

335-350: Excellent error handling implementation

The error handling in the handleNext function properly addresses previous concerns about unhandled exceptions during tour completion. The try-catch block and user ID validation prevent crashes.

This is much better than mom's spaghetti - proper error handling that won't leave users staring at a crashed tour!


358-369: Well-implemented event listener cleanup

The resize and scroll event listener management properly cleans up when the container is removed from the DOM, preventing memory leaks.

No more sweaty palms about memory leaks - this cleanup logic is solid as mom's best spaghetti recipe!

Copy link
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: 0

🧹 Nitpick comments (5)
docker-compose.dev.yml (2)

15-18: Use exec form for the dev command
The shell-style command with a trailing semicolon can swallow errors. Prefer the exec array form for clarity and proper error propagation:

command:
  - npm
  - run
  - dev

30-33: Remove trailing spaces to satisfy YAML lint
Lines with trailing whitespace can trigger lint errors. For example:

- build: 
+ build:

Also trim any spaces at the end of blank lines (e.g., line 40).

Also applies to: 40-40

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 30-30: trailing spaces

(trailing-spaces)

docker-compose.prod.yml (3)

1-27: Harden production startup script
Your bash -c block handles migrations and creates the DB if needed, then runs npm run prod. To fail fast on unexpected errors, consider adding set -euo pipefail at the top:

command: >
  bash -c "set -euo pipefail
    if ! npx sequelize-cli db:migrate; then

This guards against silent failures in CI/CD.


38-48: Clarify or remove commented frontend service
The commented-out frontend config adds noise. If you don’t plan to activate it soon, consider removing or documenting why it’s disabled.

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 39-39: trailing spaces

(trailing-spaces)


39-39: Strip trailing whitespace in commented lines
Trailing spaces at lines 39 and 49 trigger lint errors. E.g.:

-  #   environment:
+  #   environment:

Ensure no extra spaces on blank/comment lines.

Also applies to: 49-49

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 39-39: trailing spaces

(trailing-spaces)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b72ef6 and 186a913.

📒 Files selected for processing (7)
  • .env (0 hunks)
  • .github/workflows/deploy.yml (1 hunks)
  • .github/workflows/node.js.yml (1 hunks)
  • docker-compose.dev.yml (2 hunks)
  • docker-compose.prod.yml (1 hunks)
  • frontend/Dockerfile.development (1 hunks)
  • package.json (1 hunks)
💤 Files with no reviewable changes (1)
  • .env
✅ Files skipped from review due to trivial changes (2)
  • frontend/Dockerfile.development
  • package.json
🧰 Additional context used
🪛 YAMLlint (1.37.1)
docker-compose.dev.yml

[error] 30-30: trailing spaces

(trailing-spaces)


[error] 40-40: trailing spaces

(trailing-spaces)

docker-compose.prod.yml

[error] 39-39: trailing spaces

(trailing-spaces)


[error] 49-49: trailing spaces

(trailing-spaces)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)
🔇 Additional comments (2)
.github/workflows/node.js.yml (1)

99-103:

✅ Verification successful

Align CI with centralized Docker scripts
Switching to npm run docker-build:prod and npm run docker-up:prod-d is a solid move for maintainability. Please verify these scripts exist and correctly reference your production compose file (docker-compose.prod.yml).

You can confirm by running locally in the repo root:


🏁 Script executed:

rg '"docker-build:prod"' -n package.json
rg '"docker-up:prod-d"' -n package.json

Length of output: 240


CI aligned with centralized Docker scripts — verification complete

  • docker-build:prod (package.json line 10) and docker-up:prod-d (package.json line 8) are both defined
  • Each script correctly references docker-compose.prod.yml

No further changes needed.

.github/workflows/deploy.yml (1)

52-55:

❓ Verification inconclusive

Ensure npm scripts are present on the server
The deployment relies on docker-down:dev, docker-build:prod, and docker-up:prod-d in the remote package.json. Confirm the staging branch includes these scripts before invoking them.

Run on your CI runner or via SSH:


🏁 Script executed:

ssh staging-server 'grep -E "\"docker-(down:dev|build:prod|up:prod-d)\"" ~/bluewave-onboarding/package.json'

Length of output: 204


Manual verification required: Confirm npm scripts on the staging server

I’m unable to SSH into staging-server from here (ssh: command not found). Please run the following on your CI runner or your local shell to ensure those scripts exist in ~/bluewave-onboarding/package.json on staging:

ssh staging-server 'grep -E "\"docker-(down:dev|build:prod|up:prod-d)\"" ~/bluewave-onboarding/package.json'

Copy link
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

🧹 Nitpick comments (2)
docker-compose.prod.yml (2)

39-39: 🐾 Remove trailing whitespace
Lines with trailing spaces can trigger YAMLlint errors and make configs “sweaty.” Let’s clean them up.

Apply this diff:

-    build: 
+    build:
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 39-39: trailing spaces

(trailing-spaces)


49-49: 🐾 Remove trailing whitespace
That blank line is also sweating extra spaces. Let’s trim it to satisfy YAMLlint.

Apply this diff:

-    environment:
-      - NODE_ENV=${NODE_ENV:-production}
-    
+    environment:
+      - NODE_ENV=${NODE_ENV:-production}
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 49-49: trailing spaces

(trailing-spaces)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 186a913 and 0eb0218.

📒 Files selected for processing (1)
  • docker-compose.prod.yml (2 hunks)
🧰 Additional context used
🪛 YAMLlint (1.37.1)
docker-compose.prod.yml

[error] 39-39: trailing spaces

(trailing-spaces)


[error] 49-49: trailing spaces

(trailing-spaces)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)
🔇 Additional comments (1)
docker-compose.prod.yml (1)

15-15: ✔ Ensure a solid default for NODE_ENV
Providing a fallback of production avoids unintended development settings in CI/CD or cloud deployments.

Copy link
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: 0

🔭 Outside diff range comments (2)
extention/app.js (2)

202-202: ⚠️ Potential issue

Syntax slip - there's a rogue comma hanging out where a semicolon should be!

Knees weak moment here - you've got a trailing comma instead of a semicolon after the color property.

-  hintContainer.style.color = '#333',
+  hintContainer.style.color = '#333';

478-478: ⚠️ Potential issue

Another syntax stumble - missing semicolon after the color assignment!

Arms are heavy with these syntax errors - need that semicolon to close out the statement properly.

-  input.style.color='#344054';
+  input.style.color = '#344054';
🧹 Nitpick comments (1)
extention/app.js (1)

187-187: Consider extracting these hardcoded colours into constants

There's vomit on your sweater already with all these magic colour values scattered throughout! Consider creating a colour palette object at the top of the file for better maintainability.

+const COLORS = {
+  PRIMARY_PURPLE: '#7F56D9',
+  TEXT_PRIMARY: '#333',
+  TEXT_SECONDARY: '#344054',
+  BORDER_LIGHT: '#D0D5DD',
+  // ... other colours
+};

Then use COLORS.TEXT_PRIMARY instead of '#333' throughout the code.

Also applies to: 839-839, 915-915

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0eb0218 and 9f063e0.

⛔ Files ignored due to path filters (1)
  • extention/icon_128_128.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • extention/app.js (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)
🔇 Additional comments (2)
extention/app.js (2)

216-225: Yo, this cssText consolidation is actually fire! 🔥

Mom's spaghetti moment avoided here - you've cleaned up what could've been a messy pile of individual style assignments into one slick cssText block. This is more performant (fewer DOM manipulations) and way more readable. The styling properties are all preserved correctly.


512-523: Copy button's got that proper error handling now - no more sweaty palms! 💪

This async/await implementation with try-catch is solid. The user feedback ("Copied!" vs "Failed!") is a nice touch, and the 2-second timeout to revert the button text keeps things clean. Much better than the previous implementation that could leave users hanging if the clipboard API failed.

Copy link
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: 0

♻️ Duplicate comments (7)
jsAgent/tour.js (7)

3-4: ⚠️ Potential issue

Use versioned imports with integrity hashes for external scripts

Palms are sweaty thinking about CDN compromise attacks! Loading external scripts without integrity hashes is a security risk. If the CDN is compromised, malicious code could be injected.

-const FLOATING_UI_CORE_URL = "https://cdn.jsdelivr.net/npm/@floating-ui/[email protected]";
-const FLOATING_UI_DOM_URL = "https://cdn.jsdelivr.net/npm/@floating-ui/[email protected]";
+const FLOATING_UI_CORE_URL = "https://cdn.jsdelivr.net/npm/@floating-ui/[email protected]/dist/floating-ui.core.umd.min.js";
+const FLOATING_UI_CORE_INTEGRITY = "sha384-...[actual hash value here]";
+const FLOATING_UI_DOM_URL = "https://cdn.jsdelivr.net/npm/@floating-ui/[email protected]/dist/floating-ui.dom.umd.min.js";
+const FLOATING_UI_DOM_INTEGRITY = "sha384-...[actual hash value here]";

55-62: 🛠️ Refactor suggestion

Parameter inconsistency in showTour function

Mom's spaghetti all over the place when parameters are ignored like this! The function accepts tourData but doesn't use it, instead relying on bw.tour.currentStep.

-    showTour: function (tourData) {
+    showTour: function (tourData) {
         if (!tourData) {
             console.error('No tour data provided');
             return;
         }
-       
+        // Set the module's tourData if it was passed as a parameter
+        if (tourData !== bw.tour.tourData) {
+            bw.tour.tourData = tourData;
+        }
+        
         this.showDialog(bw.tour.currentStep);
     },

126-126: ⚠️ Potential issue

XSS vulnerability in generateContent function

Knees weak thinking about this XSS vulnerability! p.innerHTML = content; assumes the backend always delivers safe markup. If malicious script sneaks into tourData.description, it runs in users' browsers with full privileges.

-        p.innerHTML = content;
+        // If rich HTML is required, run `content` through a sanitizer first.
+        p.textContent = content;

298-298: ⚠️ Potential issue

Same XSS vulnerability in updateData function

The innerHTML usage in updateData has the same XSS vulnerability as in the generateContent function!

-            document.getElementById('bw-tour-description').innerHTML = bw.tour.tourData.steps[bw.tour.currentStep].description;
+            // If rich HTML is required, use a sanitizer before setting innerHTML
+            document.getElementById('bw-tour-description').textContent = bw.tour.tourData.steps[bw.tour.currentStep].description;

302-304: ⚠️ Potential issue

Missing null check in updatePosition function

updatePosition crashes when the target selector is missing! document.querySelector(...) can return null; calling getBoundingClientRect() on it will throw.

-            const targetElement = document.querySelector(bw.tour.tourData.steps[bw.tour.currentStep].targetElement);
-            //update container position according to target element with smooth animation transition
-            const rect = targetElement.getBoundingClientRect();
+            const targetElement = document.querySelector(
+                bw.tour.tourData.steps[bw.tour.currentStep].targetElement
+            );
+            if (!targetElement) {
+                console.warn("Target element not found for step", bw.tour.currentStep);
+                return;
+            }
+            // Update container position according to target element with smooth animation transition
+            const rect = targetElement.getBoundingClientRect();

329-331: ⚠️ Potential issue

Add null check for target element highlighting

Arms are heavy with the weight of all these potential null reference errors! The highlightTatgetElement function should verify the target element exists before attempting to modify its classes.

 function highlightTatgetElement(targetElement){
+    if (!targetElement) {
+        console.warn("Cannot highlight: target element is null");
+        return;
+    }
     // highlight target element
     targetElement.classList.add('bw-glowing-box');
 }

15-16: ⚠️ Potential issue

Add null checks for window.bwonboarddata access

There's vomit on his sweater already thinking about those null reference exceptions! The code accesses window.bwonboarddata.tour[0] without verifying the object exists.

-        const result = window.bwonboarddata.tour[0];
-        const tourId = result.id;
+        if (!window.bwonboarddata?.tour?.length) {
+            console.error('Tour data not available in window.bwonboarddata.tour');
+            cb?.(false);
+            return;
+        }
+        const result = window.bwonboarddata.tour[0];
+        const tourId = result.id;
🧹 Nitpick comments (2)
jsAgent/tour.js (2)

45-48: Use optional chaining for callback invocations

Arms are heavy with all these repetitive null checks! The static analysis tool is right - you can simplify the callback pattern.

-            cb && cb(tourData);
+            cb?.(tourData);
-            cb && cb(false);
+            cb?.(false);
🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


329-329: Fix typo in function name

Mom's spaghetti is falling out thinking about this typo! highlightTatgetElement should be highlightTargetElement.

-        function highlightTatgetElement(targetElement){
+        function highlightTargetElement(targetElement){

Don't forget to update the function call on line 314:

-            highlightTatgetElement(targetElement);
+            highlightTargetElement(targetElement);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 666cad6 and 6b27642.

📒 Files selected for processing (1)
  • jsAgent/tour.js (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
jsAgent/tour.js

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build (22.x)
🔇 Additional comments (2)
jsAgent/tour.js (2)

349-366: Good error handling implementation

There's relief in my sweaty palms seeing this proper error handling! The try-catch blocks and user ID validation show much better defensive programming compared to earlier versions.


374-385: Excellent event listener management

Knees feeling strong seeing this proper cleanup! The resize and scroll event listeners with proper cleanup prevent memory leaks and ensure the tour dialog repositions correctly.

@erenfn erenfn merged commit 3502bfd into develop May 23, 2025
2 checks passed
@erenfn erenfn deleted the agent-tour branch June 4, 2025 13:31
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