Skip to content
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

Information overlays #194

Merged
merged 30 commits into from
Nov 22, 2024
Merged

Information overlays #194

merged 30 commits into from
Nov 22, 2024

Conversation

damongolding
Copy link
Owner

@damongolding damongolding commented Nov 20, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new overlay for displaying additional information when polling is paused.
    • Added styles for the new overlay and its components, enhancing the visual representation of polling status.
    • New navigation item for "more info" added to the main menu.
    • New CSS variables introduced to enhance theming across the application.
    • Enhanced image metadata display with QR code integration.
  • Bug Fixes

    • Improved error handling and logging for API calls and user interactions.
  • Documentation

    • Updated README with clearer installation and configuration instructions.
    • Enhanced the FAQ section with detailed explanations of features.
  • Chores

    • Updated CSS files to include new styles and improve overall layout consistency.
    • Refactored task management files for better organisation and efficiency.

@damongolding damongolding added the enhancement New feature or request label Nov 20, 2024
Copy link
Contributor

coderabbitai bot commented Nov 20, 2024

Walkthrough

The changes in this pull request introduce a new CSS file, more-info-overlay.css, which contains styles for the #more-info component and modifies the appearance of elements when the .polling-paused.more-info class is applied. Various CSS selectors are added across multiple files to enhance the styling of image metadata and layout adjustments during specific states. Additionally, several TypeScript functions are introduced or modified to manage the visibility of the image overlay and handle new event interactions.

Changes

File Path Change Summary
frontend/src/css/more-info-overlay.css New CSS file added with styles for #more-info and related elements.
frontend/src/css/image.css New selector for .polling-paused.more-info .image--metadata added, setting opacity to 0.2.
frontend/src/css/clock-weather-container.css New rule for #clock-weather-container under .polling-paused.more-info with opacity: 0.2.
frontend/src/css/kiosk.css Import statement for more-info-overlay.css added.
frontend/src/css/menu.css New class .navigation--more-info added; various adjustments to spacing and sizing.
frontend/src/ts/kiosk.ts New function handleInfoKeyPress added; modified event handling for key presses.
frontend/src/ts/menu.ts New functions for managing image overlay visibility added: showImageOverlay, hideImageOverlay, toggleImageOverlay.
frontend/src/ts/polling.ts Updated startPolling and resumePolling to include a parameter for hiding the image overlay.
views/views_image.templ New function renderMoreInfo added to display detailed image information.
views/views_menu.templ New navigation item for "more info" added; new <div> for #more-info.
go.mod New direct dependencies added for QR code generation and human-readable formats.
utils/utils.go New functions for QR code generation and time parsing added; new types defined.
main.go New POST route for webhooks added.
routes/routes_webhooks.go New webhook handler function Webhooks introduced.
webhooks/webhooks.go New constant UserWebhookTriggerInfoOverlay added for webhook events.
Various CSS files Multiple new selectors added to enhance styling for .polling-paused.more-info context.

Possibly related PRs

  • splitview-landscape layout fix #189: The changes in this PR involve modifications to the .layout-splitview-landscape class, which is relevant to the layout adjustments made in the main PR for the .polling-paused.more-info context, indicating a direct connection in styling for landscape layouts.

Suggested labels

fix

Poem

In the meadow where rabbits play,
New styles hop in, brightening the day.
With overlays and buttons, oh so fine,
Polling paused, yet all will shine.
A whisker of change, a dash of flair,
Hopping along, we style with care! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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 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.

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.

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: 17

🧹 Outside diff range and nitpick comments (18)
frontend/src/css/clock-weather-container.css (1)

1-5: Consider increasing the opacity value for better readability

The opacity value of 0.2 makes the content quite faint. Consider increasing it to around 0.4-0.5 to maintain visual hierarchy whilst ensuring content remains readable.

 .polling-paused.more-info {
     #clock-weather-container {
-        opacity: 0.2;
+        opacity: 0.4;
     }
 }
frontend/src/ts/menu.ts (2)

11-11: Fix spelling in variable name

The variable name contains a spelling error: "Visable" should be "Visible".

-let imageOverlayVisable = false;
+let imageOverlayVisible = false;

31-46: Consider implementing a proper state management solution

The current implementation mixes DOM manipulation with state management. Consider:

  1. Using a dedicated state management solution (e.g., Redux, MobX)
  2. Separating overlay management into its own module
  3. Adding event emitters for state changes instead of direct DOM manipulation

This would improve maintainability and make the code more testable.

frontend/src/css/image-more-info.css (4)

1-3: Consider using a class selector instead of an ID

Using ID selectors can make the styles less reusable and harder to maintain. Consider converting #more-info to a class selector (e.g., .more-info-overlay) for better modularity and reusability.

-#more-info {
+.more-info-overlay {
    display: none;
}

6-8: Consider performance impact of filters

The combination of grayscale, blur, and brightness filters might impact performance, especially on lower-end devices. Consider using opacity or a semi-transparent overlay instead.

    .frame--image img {
-        filter: grayscale(1) blur(4px) brightness(0.4);
+        opacity: 0.4;
    }

21-21: Avoid arbitrary z-index values

Using very high z-index values (99998) can lead to maintainability issues. Consider implementing a z-index scale system with lower, more manageable values.

-        z-index: 99998;
+        z-index: 100;

71-79: Consider using media queries for layout changes

Instead of relying on a class to handle landscape layouts, consider using media queries for a more maintainable and automated approach.

-.layout-splitview-landscape {
+@media (orientation: landscape) {
    #more-info {
        flex-direction: column;

        .more-info--image {
            flex-direction: row;
        }
    }
}
frontend/src/css/menu.css (1)

12-12: Consider using lower z-index values

Whilst the relative difference between z-indices is correct (navigation menu above interaction area), using extremely high values like 99997 isn't necessary and could cause conflicts with third-party components. Consider scaling down all z-index values whilst maintaining their relative ordering.

-    z-index: 99997;
+    z-index: 97;

Also update the related .navigation class:

.navigation {
    /* ... other properties ... */
    z-index: 99;
}
frontend/src/ts/polling.ts (1)

Line range hint 107-116: LGTM: Clean parameter addition

The optional parameter addition is backwards-compatible and well-implemented. The conditional overlay hiding is placed appropriately after state updates.

Consider extracting the common state update logic between startPolling and resumePolling to reduce code duplication:

+function updatePollingState(hideOverlay: boolean = false) {
+  progressBarElement?.classList.remove("progress--bar-paused");
+  menuElement?.classList.add("navigation-hidden");
+  document.body.classList.remove("polling-paused");
+  if (hideOverlay) hideImageOverlay();
+}
custom.example.css (1)

Line range hint 1-161: Consider modernising the CSS architecture

The current file structure imports multiple CSS files and combines them into a single file. Consider adopting a more maintainable approach:

  1. Use CSS Modules or a CSS-in-JS solution to better encapsulate styles and prevent naming conflicts
  2. Implement a CSS preprocessor (like SASS/SCSS) to:
    • Utilise variables for consistent theming
    • Create mixins for repeated style patterns
    • Nest selectors for better readability
  3. Consider implementing a utility-first approach (like Tailwind CSS) for rapid development

Would you like guidance on implementing any of these architectural improvements?

🧰 Tools
🪛 Biome

[error] 62-62: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 63-63: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 64-64: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 78-78: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 79-79: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

frontend/src/ts/kiosk.ts (1)

186-189: Maintain consistency with existing code patterns

The implementation should follow the established patterns in the codebase:

  1. Use htmx.find instead of querySelector
  2. Add error handling for missing elements

Apply this improvement:

-  document
-    .querySelector(".navigation--more-info")
-    ?.addEventListener("click", () => toggleImageOverlay());
+  const moreInfoButton = htmx.find(".navigation--more-info") as HTMLElement | null;
+  if (!moreInfoButton) {
+    console.error("More info button not found");
+    return;
+  }
+  moreInfoButton.addEventListener("click", () => toggleImageOverlay());
views/views_menu.templ (1)

23-23: Add ARIA attributes for better accessibility

The more-info overlay should include proper ARIA attributes to ensure screen readers can properly announce its presence and state.

Apply this diff to improve accessibility:

-<div id="more-info" class="hidden" hx-swap-oob="true"></div>
+<div id="more-info" class="hidden" hx-swap-oob="true" role="dialog" aria-modal="true" aria-hidden="true" aria-labelledby="more-info-title"></div>
views/views_image.templ (2)

28-43: Consider adding input validation.

Whilst the function handles URL parsing errors well, consider validating the input parameters to ensure they're not empty and the imageID follows the expected format.

 func imageUrl(baseUrl, imageID string) string {
+    if baseUrl == "" || imageID == "" {
+        return "#"
+    }
+
     u, err := url.Parse(baseUrl)
     if err != nil {
         return "#"
     }

50-59: Simplify nested div structure.

The current structure has unnecessary nesting. Consider simplifying it for better maintainability.

-<div>
-    <div>
-        <h3>
-            Image ID
-        </h3>
-    </div>
-    <div>
-        { img.ImmichImage.ID }
-    </div>
-</div>
+<div class="more-info--field">
+    <h3>Image ID</h3>
+    <div>{ img.ImmichImage.ID }</div>
+</div>
views/views_menu_templ.go (2)

32-32: Consider enhancing keyboard navigation and menu area

The navigation interaction area could benefit from the following improvements:

  1. Add keyboard navigation for the right arrow key to match the left arrow implementation
  2. Consider adding content to the empty menu area or remove it if not needed
-  keyup[key=='ArrowLeft'] from:body throttle:1s,
+  keyup[key=='ArrowLeft,ArrowRight'] from:body throttle:1s,

32-32: Enhance accessibility for the more info overlay

Consider adding ARIA attributes to improve accessibility:

- <div id="more-info" class="hidden" hx-swap-oob="true">
+ <div id="more-info" class="hidden" hx-swap-oob="true" 
+      role="dialog" 
+      aria-labelledby="more-info-title"
+      aria-hidden="true">
+   <h2 id="more-info-title" class="sr-only">Additional Information</h2>
frontend/public/assets/css/kiosk.css (1)

591-591: Consider standardising border-radius values.

The border-radius value of 0.74rem is inconsistent with other components that use 0.75rem.

Apply this diff for consistency:

-   border-radius: 0.74rem;
+   border-radius: 0.75rem;
views/views_image_templ.go (1)

70-85: Handle URL parsing errors more gracefully

Currently, if url.Parse(baseUrl) fails, the function returns "#". Returning a fragment identifier may not provide meaningful feedback to the user or assist in debugging. Consider logging the error and returning an empty string or propagating the error to the caller.

Modify the error handling as follows:

 func imageUrl(baseUrl, imageID string) string {
     u, err := url.Parse(baseUrl)
     if err != nil {
-        return "#"
+        // Log the error and return an empty string
+        fmt.Errorf("invalid base URL: %v", err)
+        return ""
     }
     // Rest of the code...
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c53d23d and 1df6799.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (16)
  • custom.example.css (4 hunks)
  • frontend/public/assets/css/kiosk.css (7 hunks)
  • frontend/src/css/clock-weather-container.css (1 hunks)
  • frontend/src/css/image-more-info.css (1 hunks)
  • frontend/src/css/image.css (1 hunks)
  • frontend/src/css/kiosk.css (1 hunks)
  • frontend/src/css/menu.css (4 hunks)
  • frontend/src/ts/kiosk.ts (2 hunks)
  • frontend/src/ts/menu.ts (3 hunks)
  • frontend/src/ts/polling.ts (4 hunks)
  • go.mod (1 hunks)
  • utils/utils.go (2 hunks)
  • views/views_image.templ (2 hunks)
  • views/views_image_templ.go (18 hunks)
  • views/views_menu.templ (2 hunks)
  • views/views_menu_templ.go (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/css/kiosk.css
🧰 Additional context used
🪛 Biome
custom.example.css

[error] 43-43: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 93-93: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 161-161: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

🔇 Additional comments (18)
frontend/src/css/clock-weather-container.css (1)

1-5: Verify integration with related CSS files

Let's ensure this styling integrates properly with the mentioned files in the summary (custom.example.css, image-more-info.css).

✅ Verification successful

CSS integration verified and consistent

The opacity styling for #clock-weather-container within the .polling-paused.more-info selector is properly integrated across the codebase. The implementation is consistent with other related elements that use the same class combination, where similar opacity values (0.2) are applied to create a unified dimming effect during the paused state.

  • The styling in clock-weather-container.css aligns with similar opacity treatments in:
    • kiosk.css for image metadata (0.2)
    • image.css for image metadata (0.2)
    • Other related elements using the .polling-paused.more-info selector
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for related CSS files and their integration
# Expected: Find references to polling-paused.more-info class and verify consistent styling

# Search for related CSS files
echo "Searching for related CSS files..."
fd -e css -x grep -l "polling-paused.more-info" {} \;

# Check for potential conflicting opacity rules
echo "\nChecking for potential conflicting opacity rules..."
rg "opacity:" $(fd -e css)

Length of output: 2729


Script:

#!/bin/bash
# Let's check the actual implementation of polling-paused.more-info class in the related files
echo "Checking polling-paused.more-info implementation in related files..."
rg -A 3 "polling-paused\.more-info" ./frontend/src/css/image.css ./frontend/src/css/image-more-info.css ./custom.example.css ./frontend/public/assets/css/kiosk.css

Length of output: 5019

frontend/src/ts/menu.ts (1)

65-67: LGTM: Export modifications are correct

The new overlay management functions are properly exported, maintaining consistency with the module's existing pattern.

go.mod (1)

43-43: Verify the QR code dependency's maintenance status and security

The go-qrcode library appears to be unmaintained (last commit from June 2020). Consider evaluating more actively maintained alternatives for QR code generation.

Let's check the repository status and potential alternatives:

Consider these maintained alternatives:

  • github.com/yeqown/go-qrcode
  • github.com/boombuler/barcode
frontend/src/css/menu.css (2)

31-31: LGTM: Refined spacing and sizing

The reduced gap and SVG dimensions create a more compact navigation whilst maintaining proportional relationships. These changes complement the new more-info feature by establishing a clear visual hierarchy.

Also applies to: 74-75


105-110: LGTM: Well-structured more-info styling

The new class follows BEM naming conventions and creates appropriate visual distinction through icon sizing. However, let's verify its integration with the polling states mentioned in the PR summary.

✅ Verification successful

Let me gather more information about the templates since the previous HTML search didn't work correctly.


The more-info styling appears to be correctly integrated

The CSS integration shows that the .navigation--more-info class is part of a broader styling system for the polling states and information overlays. The styling is consistently applied across multiple CSS files including image-more-info.css, clock-weather-container.css, and others, with proper BEM naming conventions maintained throughout. The smaller SVG size (1.5rem) in the menu navigation complements the existing more-info styling structure.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the integration between more-info styling and polling states
# Expected: Find related more-info and polling state classes in templates and CSS

# Check for related more-info classes in templates
echo "Checking templates for more-info usage:"
rg -t html "navigation--more-info|polling-paused.more-info"

# Check for related styling in other CSS files
echo "Checking related CSS files:"
rg -t css "polling-paused.more-info|\.more-info" --glob '!menu.css'

Length of output: 2868


Script:

#!/bin/bash
# Search for HTML/template files first
echo "Finding template files:"
fd -e html -e vue -e jsx -e tsx

# Then search for more-info usage in those files
echo -e "\nChecking templates for more-info usage:"
fd -e html -e vue -e jsx -e tsx -x rg -l "navigation--more-info|more-info"

# Check the specific menu component files
echo -e "\nChecking menu-related components:"
fd -g '*menu*' -e js -e jsx -e tsx -e vue -x rg -l "navigation--more-info"

Length of output: 420

frontend/src/ts/polling.ts (3)

2-2: LGTM: Clean import addition

The import statement is well-placed and follows proper module import conventions.


124-125: LGTM: Clean parameter forwarding

The togglePolling function cleanly forwards the hideOverlay parameter while maintaining its simple toggle logic.


69-69: Consider timing of overlay hide operation

The hideImageOverlay call occurs after state updates but before animation frame completion. Consider whether this could cause visual flickering if the animation frame updates occur rapidly.

✅ Verification successful

Let me gather more context about the animation frame handling and hideImageOverlay implementation.


Let me check the animation frame handling in the updateKiosk function to understand the timing context better.


No timing issues with overlay hide operation

The hideImageOverlay call is safely placed after animation frame cancellation in pause operations and after state updates in resume operations. The implementation ensures proper synchronisation with the animation frame lifecycle, preventing any potential visual flickering.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other timing-dependent calls to hideImageOverlay
ast-grep --pattern 'hideImageOverlay()' 

Length of output: 255


Script:

#!/bin/bash
# Check hideImageOverlay implementation and animation frame usage
ast-grep --pattern 'function hideImageOverlay() {
  $$$
}'

# Check for requestAnimationFrame usage
ast-grep --pattern 'requestAnimationFrame'

# Check the full polling function context
rg -B 5 -A 5 'hideImageOverlay\(\)' frontend/src/ts/polling.ts

Length of output: 89425


Script:

#!/bin/bash
# Check updateKiosk implementation
ast-grep --pattern 'function updateKiosk() {
  $$$
}'

# Check for any animation frame cancellation
rg -B 3 -A 3 'cancelAnimationFrame' frontend/src/ts/polling.ts

Length of output: 568

frontend/src/css/image.css (1)

2-6: Verify the cascade order with other opacity-related styles

The new class looks good, but we should ensure it doesn't conflict with other opacity-related styles when multiple states are active.

✅ Verification successful

Let me check the specific context around the opacity declarations in image.css to understand potential cascading conflicts.


No opacity cascade conflicts found in image.css

The two opacity declarations in image.css (.polling-paused.more-info .image--metadata at 0.2 and .image--metadata--exif--seperator at 0.3) target different elements and won't conflict with each other. The new style uses proper class nesting and specificity to ensure it only affects metadata when the polling-paused and more-info states are active.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential opacity conflicts in CSS files
# Look for other opacity declarations that might interact with .polling-paused.more-info

rg -g '*.css' 'opacity:' frontend/src/css/

Length of output: 760


Script:

#!/bin/bash
# Get full context of opacity-related styles in image.css
rg -g 'image.css' -B 3 -A 3 'opacity:' frontend/src/css/image.css

Length of output: 260

frontend/src/ts/kiosk.ts (1)

18-18: LGTM!

The import of toggleImageOverlay is properly added and aligns with the new image overlay functionality.

views/views_menu.templ (1)

Line range hint 23-54: Verify integration with supporting components

Please ensure that the following dependencies are properly implemented:

  1. The /image/info endpoint for fetching more information
  2. The image-more-info.css styles referenced in the AI summary
  3. Any JavaScript handlers for managing the overlay state
✅ Verification successful

Integration is properly implemented and functional

The verification confirms that all required components are present and correctly integrated:

  • CSS styles for the more-info overlay are implemented in frontend/src/css/image-more-info.css
  • TypeScript handlers in menu.ts provide toggleImageOverlay, showImageOverlay, and hideImageOverlay functions
  • The overlay state is managed via CSS classes and TypeScript event handlers
  • Keyboard shortcuts (pressing 'I') and click handlers are properly wired up in kiosk.ts
  • The overlay integrates with the polling system to pause image rotation when active
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of required supporting files and endpoints

# Check for the CSS file
echo "Checking for CSS file..."
fd -t f "image-more-info.css"

# Check for route handler
echo "Checking for route handler..."
rg -l "/image/info"

# Check for JS handlers
echo "Checking for JS handlers..."
rg -l "toggleImageOverlay|showMoreInfo|hideMoreInfo"

Length of output: 383


Script:

#!/bin/bash
# Let's examine the contents of the found files to verify the integration

# Check the CSS implementation
echo "=== CSS Implementation ==="
cat frontend/src/css/image-more-info.css

# Check the TypeScript handlers
echo -e "\n=== Menu TypeScript Implementation ==="
cat frontend/src/ts/menu.ts

echo -e "\n=== Kiosk TypeScript Implementation ==="
cat frontend/src/ts/kiosk.ts

Length of output: 10973

views/views_image.templ (2)

7-8: LGTM: Required imports added for URL handling.

The new imports are appropriate for URL manipulation functionality.


25-25: LGTM: Proper placement of the new more info section.

The renderMoreInfo template is appropriately placed after the main content and history section.

utils/utils.go (1)

38-39: LGTM: Import statement is properly structured

The addition of the go-qrcode package is appropriate for the QR code generation functionality.

frontend/public/assets/css/kiosk.css (3)

371-373: LGTM!

The opacity adjustment for image metadata when polling is paused is appropriate and consistent with the overlay design pattern.


734-736: LGTM!

The opacity adjustment for the clock-weather container when polling is paused is appropriate and consistent with the overlay design pattern.


1233-1233: LGTM!

The z-index and SVG size adjustments are appropriate for the navigation elements:

  • z-index ensures proper layering with the more-info overlay
  • SVG sizes are consistent with the design system

Also applies to: 1297-1298, 1319-1322

views/views_image_templ.go (1)

194-196: Avoid modifying generated code

The code in this section appears to be generated by templ and is marked as "DO NOT EDIT". Modifying generated code can lead to inconsistencies and may be overwritten. Ensure that any required changes are made in the source templates instead.

Comment on lines 38 to 42
function hideImageOverlay() {
console.log("off");
document.body.classList.remove("more-info");
imageOverlayVisable = false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove debug logging and fix variable spelling

Production code shouldn't include console.log statements.

 function hideImageOverlay() {
-  console.log("off");
   document.body.classList.remove("more-info");
-  imageOverlayVisable = false;
+  imageOverlayVisible = false;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function hideImageOverlay() {
console.log("off");
document.body.classList.remove("more-info");
imageOverlayVisable = false;
}
function hideImageOverlay() {
document.body.classList.remove("more-info");
imageOverlayVisible = false;
}

Comment on lines 44 to 46
function toggleImageOverlay() {
imageOverlayVisable ? hideImageOverlay() : showImageOverlay();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix variable spelling in toggle function

Update the variable name to use correct spelling.

 function toggleImageOverlay() {
-  imageOverlayVisable ? hideImageOverlay() : showImageOverlay();
+  imageOverlayVisible ? hideImageOverlay() : showImageOverlay();
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function toggleImageOverlay() {
imageOverlayVisable ? hideImageOverlay() : showImageOverlay();
}
function toggleImageOverlay() {
imageOverlayVisible ? hideImageOverlay() : showImageOverlay();
}

Comment on lines 31 to 36
function showImageOverlay() {
if (!document.body.classList.contains("polling-paused")) return;
console.log("on");
document.body.classList.add("more-info");
imageOverlayVisable = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add TypeScript type safety and remove console.log

The function could benefit from TypeScript type assertions and shouldn't include debug logging in production code.

 function showImageOverlay() {
   if (!document.body.classList.contains("polling-paused")) return;
-  console.log("on");
   document.body.classList.add("more-info");
-  imageOverlayVisable = true;
+  imageOverlayVisible = true;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function showImageOverlay() {
if (!document.body.classList.contains("polling-paused")) return;
console.log("on");
document.body.classList.add("more-info");
imageOverlayVisable = true;
}
function showImageOverlay() {
if (!document.body.classList.contains("polling-paused")) return;
document.body.classList.add("more-info");
imageOverlayVisible = true;
}

Comment on lines 28 to 38
display: flex;
flex-direction: column;
justify-content: space-between;

padding: 6rem 3rem 3rem 3rem;
color: #fff;
border-radius: 0.74rem;

display: flex;
flex-direction: column;
gap: 2rem;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove duplicate flex properties

The flex properties are declared twice. Remove the duplicate declarations to improve maintainability.

            display: flex;
            flex-direction: column;
            justify-content: space-between;

            padding: 6rem 3rem 3rem 3rem;
            color: #fff;
            border-radius: 0.74rem;

-            display: flex;
-            flex-direction: column;
            gap: 2rem;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 6rem 3rem 3rem 3rem;
color: #fff;
border-radius: 0.74rem;
display: flex;
flex-direction: column;
gap: 2rem;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 6rem 3rem 3rem 3rem;
color: #fff;
border-radius: 0.74rem;
gap: 2rem;

Comment on lines 52 to 56
a {
font-weight: 600;
text-decoration: underline;
color: #fff;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance accessibility and user experience

The link styles should include focus and hover states, and state changes should be smooth.

            a {
                font-weight: 600;
                text-decoration: underline;
                color: #fff;
+                transition: opacity 0.2s ease;
+                
+                &:hover,
+                &:focus {
+                    opacity: 0.8;
+                    outline: 2px solid #fff;
+                    outline-offset: 2px;
+                }
            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
a {
font-weight: 600;
text-decoration: underline;
color: #fff;
}
a {
font-weight: 600;
text-decoration: underline;
color: #fff;
transition: opacity 0.2s ease;
&:hover,
&:focus {
opacity: 0.8;
outline: 2px solid #fff;
outline-offset: 2px;
}
}

@@ -29,7 +29,7 @@ func menu() templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<nav id=\"navigation-interaction-area\"><div id=\"navigation-interaction-area--previous-image\" hx-post=\"/image/previous\" hx-target=\"#kiosk\" hx-include=\".kiosk-history--entry\" hx-trigger=\"\n\t\t\t click throttle:1s,\n\t\t\t click from:.navigation--prev-image throttle:1s,\n\t\t\t keyup[key==&#39;ArrowLeft&#39;] from:body throttle:1s,\n\t\t\t kiosk-prev-image throttle:1s\n\t\t\t\" hx-on::before-request=\"kiosk.checkHistoryExists(event)\" hx-on::after-request=\"kiosk.startPolling()\" hx-on::after-swap=\"kiosk.cleanupFrames(), kiosk.releaseRequestLock()\"></div><div id=\"navigation-interaction-area--menu\"></div><div id=\"navigation-interaction-area--next-image\"></div></nav><nav class=\"navigation navigation-hidden\"><div class=\"navigation--media-buttons rounded\"><div class=\"navigation--item navigation--prev-image\"><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.2 288 416 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-306.7 0L214.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z\"></path></svg></div><div class=\"navigation--item navigation--play-pause\"><svg class=\"navigation--play-pause--pause\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\" height=\"32px\" width=\"32px\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M48 64C21.5 64 0 85.5 0 112L0 400c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48L48 64zm192 0c-26.5 0-48 21.5-48 48l0 288c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48l-32 0z\"></path></svg> <svg class=\"navigation--play-pause--play\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\" height=\"32px\" width=\"32px\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80L0 432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z\"></path></svg></div><div class=\"navigation--item navigation--next-image\"><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z\"></path></svg></div></div><div class=\"navigation--item navigation--flush-cache rounded\" hx-get=\"/cache/flush\" hx-swap=\"none\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M2 5C2 4.19711 2.43749 3.55194 2.96527 3.08401C3.49422 2.61504 4.20256 2.2384 4.99202 1.94235C6.57833 1.34749 8.70269 1 11 1C13.2973 1 15.4217 1.34749 17.008 1.94235C17.7974 2.2384 18.5058 2.61504 19.0347 3.08401C19.5625 3.55194 20 4.19711 20 5V9.98763C20 10.0333 19.9996 10.0781 19.9989 10.1219C19.9959 10.2876 19.9945 10.3704 19.9431 10.4263C19.8917 10.4822 19.7934 10.4923 19.5967 10.5124C18.9826 10.5753 18.401 10.8669 17.985 11.3266C17.9032 11.4169 17.8623 11.4621 17.8187 11.4792C17.7751 11.4964 17.719 11.4916 17.6067 11.4819C17.4199 11.4659 17.231 11.4577 17.0404 11.4577C15.0435 11.4577 13.2497 12.3522 12.0481 13.7655C11.9557 13.8742 11.9095 13.9285 11.8524 13.956C11.7953 13.9836 11.7298 13.9858 11.599 13.9901C11.3982 13.9967 11.1984 14 11 14C8.6113 14 6.01354 13.5188 4.0508 12.5952C3.64779 12.4055 3.28325 12.2037 2.95806 11.9907C2.15337 11.4637 2 10.9324 2 9.98763V5ZM5.57313 6.13845C4.97883 5.9045 4.55524 5.65279 4.29209 5.41948C3.9354 5.10324 3.9354 4.89676 4.29209 4.58052C4.57279 4.33166 5.03602 4.06185 5.69427 3.81501C7.0034 3.32409 8.87903 3 11 3C13.121 3 14.9966 3.32409 16.3057 3.81501C16.964 4.06185 17.4272 4.33166 17.7079 4.58052C18.0646 4.89676 18.0646 5.10324 17.7079 5.41948C17.4272 5.66834 16.964 5.93815 16.3057 6.18499C14.9966 6.67591 13.121 7 11 7C10.1029 7 9.24969 6.94202 8.46467 6.83796C7.48782 6.70847 6.52272 6.51225 5.57313 6.13845ZM6.21587 10.1237C5.81919 10.0045 5.40095 10.2294 5.2817 10.6261C5.16246 11.0228 5.38736 11.441 5.78404 11.5602C6.42365 11.7525 7.13136 11.9087 7.8874 12.0234C8.29692 12.0856 8.6793 11.804 8.74146 11.3945C8.80362 10.9849 8.52203 10.6026 8.11251 10.5404C7.41722 10.4349 6.77942 10.2932 6.21587 10.1237Z\" fill=\"white\"></path> <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M10.6635 16.5223C10.7204 16.2736 10.7488 16.1493 10.6912 16.0746C10.6336 15.9999 10.5104 15.9959 10.2641 15.9879C7.84409 15.9091 5.38708 15.4342 3.1992 14.4046C3.00604 14.3137 2.81512 14.2177 2.62747 14.1164C2.3392 13.9608 2.19506 13.883 2.09753 13.9412C2 13.9993 2 14.1584 2 14.4765V18.9998C2 19.8027 2.43749 20.4479 2.96527 20.9158C3.49422 21.3848 4.20256 21.7614 4.99202 22.0575C6.57833 22.6523 8.70269 22.9998 11 22.9998C11.277 22.9998 11.5514 22.9948 11.8227 22.9848C12.219 22.9703 12.4171 22.9631 12.4672 22.8473C12.5174 22.7315 12.3782 22.5719 12.1 22.2526C11.1041 21.1097 10.5 19.6168 10.5 17.9789C10.5 17.4778 10.5565 16.9903 10.6635 16.5223ZM6.21587 17.1237C5.81919 17.0045 5.40095 17.2294 5.2817 17.6261C5.16246 18.0228 5.38736 18.441 5.78404 18.5602C6.42365 18.7525 7.13136 18.9087 7.8874 19.0234C8.29692 19.0856 8.6793 18.804 8.74146 18.3945C8.80362 17.9849 8.52203 17.6026 8.11251 17.5404C7.41722 17.4349 6.77942 17.2932 6.21587 17.1237Z\" fill=\"white\"></path> <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M19.6056 12.0284C19.0689 12.159 18.7398 12.6999 18.8704 13.2365L18.8873 13.3058C18.3149 13.0811 17.6917 12.9576 17.0404 12.9576C14.2612 12.9576 12 15.2012 12 17.9788C12 20.7564 14.2612 23 17.0404 23C19.4765 23 21.5117 21.278 21.9798 18.9829C22.0902 18.4417 21.741 17.9136 21.1998 17.8032C20.6587 17.6928 20.1305 18.0421 20.0202 18.5832C19.7396 19.959 18.5137 21 17.0404 21C15.3567 21 14 19.6429 14 17.9788C14 16.3147 15.3567 14.9576 17.0404 14.9576C17.7271 14.9576 18.3577 15.1828 18.8659 15.5627C18.8901 15.5808 18.9151 15.5978 18.9408 15.6136L19.8888 16.1967C20.2341 16.4091 20.6734 16.392 21.0011 16.1535C21.3288 15.915 21.4802 15.5023 21.3844 15.1084L20.8137 12.7635C20.6831 12.2269 20.1422 11.8978 19.6056 12.0284Z\" fill=\"white\"></path></svg></div><div class=\"navigation--item navigation--fullscreen rounded\"><svg class=\"navigation--fullscreen--enter\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" height=\"32px\" width=\"32px\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M344 0L488 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87L327 41c-6.9-6.9-8.9-17.2-5.2-26.2S334.3 0 344 0zM168 512L24 512c-13.3 0-24-10.7-24-24L0 344c0-9.7 5.8-18.5 14.8-22.2s19.3-1.7 26.2 5.2l39 39 87-87c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2s-12.5 14.8-22.2 14.8z\"></path></svg> <svg class=\"navigation--fullscreen--exit\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" height=\"32px\" width=\"32px\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M439 7c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2s-12.5 14.8-22.2 14.8l-144 0c-13.3 0-24-10.7-24-24l0-144c0-9.7 5.8-18.5 14.8-22.2s19.3-1.7 26.2 5.2l39 39L439 7zM72 272l144 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39L73 505c-9.4 9.4-24.6 9.4-33.9 0L7 473c-9.4-9.4-9.4-24.6 0-33.9l87-87L55 313c-6.9-6.9-8.9-17.2-5.2-26.2s12.5-14.8 22.2-14.8z\"></path></svg></div></nav>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<nav id=\"navigation-interaction-area\"><div id=\"navigation-interaction-area--previous-image\" hx-post=\"/image/previous\" hx-target=\"#kiosk\" hx-include=\".kiosk-history--entry\" hx-trigger=\"\n\t\t\t click throttle:1s,\n\t\t\t click from:.navigation--prev-image throttle:1s,\n\t\t\t keyup[key==&#39;ArrowLeft&#39;] from:body throttle:1s,\n\t\t\t kiosk-prev-image throttle:1s\n\t\t\t\" hx-on::before-request=\"kiosk.checkHistoryExists(event)\" hx-on::after-request=\"kiosk.startPolling()\" hx-on::after-swap=\"kiosk.cleanupFrames(), kiosk.releaseRequestLock()\"></div><div id=\"navigation-interaction-area--menu\"></div><div id=\"navigation-interaction-area--next-image\"></div></nav><div id=\"more-info\" class=\"hidden\" hx-swap-oob=\"true\"></div><nav class=\"navigation navigation-hidden\"><div class=\"navigation--media-buttons rounded\"><div class=\"navigation--item navigation--prev-image\"><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.2 288 416 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-306.7 0L214.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z\"></path></svg></div><div class=\"navigation--item navigation--play-pause\"><svg class=\"navigation--play-pause--pause\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\" height=\"32px\" width=\"32px\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M48 64C21.5 64 0 85.5 0 112L0 400c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48L48 64zm192 0c-26.5 0-48 21.5-48 48l0 288c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48l-32 0z\"></path></svg> <svg class=\"navigation--play-pause--play\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\" height=\"32px\" width=\"32px\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80L0 432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z\"></path></svg></div><div class=\"navigation--item navigation--next-image\"><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 448 512\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z\"></path></svg></div></div><div class=\"navigation--item navigation--more-info rounded\"><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 192 512\"><!--!Font Awesome Free 6.7.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M48 80a48 48 0 1 1 96 0A48 48 0 1 1 48 80zM0 224c0-17.7 14.3-32 32-32l64 0c17.7 0 32 14.3 32 32l0 224 32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 512c-17.7 0-32-14.3-32-32s14.3-32 32-32l32 0 0-192-32 0c-17.7 0-32-14.3-32-32z\"></path></svg></div><div class=\"navigation--item navigation--flush-cache rounded\" hx-get=\"/cache/flush\" hx-swap=\"none\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M2 5C2 4.19711 2.43749 3.55194 2.96527 3.08401C3.49422 2.61504 4.20256 2.2384 4.99202 1.94235C6.57833 1.34749 8.70269 1 11 1C13.2973 1 15.4217 1.34749 17.008 1.94235C17.7974 2.2384 18.5058 2.61504 19.0347 3.08401C19.5625 3.55194 20 4.19711 20 5V9.98763C20 10.0333 19.9996 10.0781 19.9989 10.1219C19.9959 10.2876 19.9945 10.3704 19.9431 10.4263C19.8917 10.4822 19.7934 10.4923 19.5967 10.5124C18.9826 10.5753 18.401 10.8669 17.985 11.3266C17.9032 11.4169 17.8623 11.4621 17.8187 11.4792C17.7751 11.4964 17.719 11.4916 17.6067 11.4819C17.4199 11.4659 17.231 11.4577 17.0404 11.4577C15.0435 11.4577 13.2497 12.3522 12.0481 13.7655C11.9557 13.8742 11.9095 13.9285 11.8524 13.956C11.7953 13.9836 11.7298 13.9858 11.599 13.9901C11.3982 13.9967 11.1984 14 11 14C8.6113 14 6.01354 13.5188 4.0508 12.5952C3.64779 12.4055 3.28325 12.2037 2.95806 11.9907C2.15337 11.4637 2 10.9324 2 9.98763V5ZM5.57313 6.13845C4.97883 5.9045 4.55524 5.65279 4.29209 5.41948C3.9354 5.10324 3.9354 4.89676 4.29209 4.58052C4.57279 4.33166 5.03602 4.06185 5.69427 3.81501C7.0034 3.32409 8.87903 3 11 3C13.121 3 14.9966 3.32409 16.3057 3.81501C16.964 4.06185 17.4272 4.33166 17.7079 4.58052C18.0646 4.89676 18.0646 5.10324 17.7079 5.41948C17.4272 5.66834 16.964 5.93815 16.3057 6.18499C14.9966 6.67591 13.121 7 11 7C10.1029 7 9.24969 6.94202 8.46467 6.83796C7.48782 6.70847 6.52272 6.51225 5.57313 6.13845ZM6.21587 10.1237C5.81919 10.0045 5.40095 10.2294 5.2817 10.6261C5.16246 11.0228 5.38736 11.441 5.78404 11.5602C6.42365 11.7525 7.13136 11.9087 7.8874 12.0234C8.29692 12.0856 8.6793 11.804 8.74146 11.3945C8.80362 10.9849 8.52203 10.6026 8.11251 10.5404C7.41722 10.4349 6.77942 10.2932 6.21587 10.1237Z\" fill=\"white\"></path> <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M10.6635 16.5223C10.7204 16.2736 10.7488 16.1493 10.6912 16.0746C10.6336 15.9999 10.5104 15.9959 10.2641 15.9879C7.84409 15.9091 5.38708 15.4342 3.1992 14.4046C3.00604 14.3137 2.81512 14.2177 2.62747 14.1164C2.3392 13.9608 2.19506 13.883 2.09753 13.9412C2 13.9993 2 14.1584 2 14.4765V18.9998C2 19.8027 2.43749 20.4479 2.96527 20.9158C3.49422 21.3848 4.20256 21.7614 4.99202 22.0575C6.57833 22.6523 8.70269 22.9998 11 22.9998C11.277 22.9998 11.5514 22.9948 11.8227 22.9848C12.219 22.9703 12.4171 22.9631 12.4672 22.8473C12.5174 22.7315 12.3782 22.5719 12.1 22.2526C11.1041 21.1097 10.5 19.6168 10.5 17.9789C10.5 17.4778 10.5565 16.9903 10.6635 16.5223ZM6.21587 17.1237C5.81919 17.0045 5.40095 17.2294 5.2817 17.6261C5.16246 18.0228 5.38736 18.441 5.78404 18.5602C6.42365 18.7525 7.13136 18.9087 7.8874 19.0234C8.29692 19.0856 8.6793 18.804 8.74146 18.3945C8.80362 17.9849 8.52203 17.6026 8.11251 17.5404C7.41722 17.4349 6.77942 17.2932 6.21587 17.1237Z\" fill=\"white\"></path> <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M19.6056 12.0284C19.0689 12.159 18.7398 12.6999 18.8704 13.2365L18.8873 13.3058C18.3149 13.0811 17.6917 12.9576 17.0404 12.9576C14.2612 12.9576 12 15.2012 12 17.9788C12 20.7564 14.2612 23 17.0404 23C19.4765 23 21.5117 21.278 21.9798 18.9829C22.0902 18.4417 21.741 17.9136 21.1998 17.8032C20.6587 17.6928 20.1305 18.0421 20.0202 18.5832C19.7396 19.959 18.5137 21 17.0404 21C15.3567 21 14 19.6429 14 17.9788C14 16.3147 15.3567 14.9576 17.0404 14.9576C17.7271 14.9576 18.3577 15.1828 18.8659 15.5627C18.8901 15.5808 18.9151 15.5978 18.9408 15.6136L19.8888 16.1967C20.2341 16.4091 20.6734 16.392 21.0011 16.1535C21.3288 15.915 21.4802 15.5023 21.3844 15.1084L20.8137 12.7635C20.6831 12.2269 20.1422 11.8978 19.6056 12.0284Z\" fill=\"white\"></path></svg></div><div class=\"navigation--item navigation--fullscreen rounded\"><svg class=\"navigation--fullscreen--enter\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" height=\"32px\" width=\"32px\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M344 0L488 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39-87 87c-9.4 9.4-24.6 9.4-33.9 0l-32-32c-9.4-9.4-9.4-24.6 0-33.9l87-87L327 41c-6.9-6.9-8.9-17.2-5.2-26.2S334.3 0 344 0zM168 512L24 512c-13.3 0-24-10.7-24-24L0 344c0-9.7 5.8-18.5 14.8-22.2s19.3-1.7 26.2 5.2l39 39 87-87c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2s-12.5 14.8-22.2 14.8z\"></path></svg> <svg class=\"navigation--fullscreen--exit\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" height=\"32px\" width=\"32px\"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d=\"M439 7c9.4-9.4 24.6-9.4 33.9 0l32 32c9.4 9.4 9.4 24.6 0 33.9l-87 87 39 39c6.9 6.9 8.9 17.2 5.2 26.2s-12.5 14.8-22.2 14.8l-144 0c-13.3 0-24-10.7-24-24l0-144c0-9.7 5.8-18.5 14.8-22.2s19.3-1.7 26.2 5.2l39 39L439 7zM72 272l144 0c13.3 0 24 10.7 24 24l0 144c0 9.7-5.8 18.5-14.8 22.2s-19.3 1.7-26.2-5.2l-39-39L73 505c-9.4 9.4-24.6 9.4-33.9 0L7 473c-9.4-9.4-9.4-24.6 0-33.9l87-87L55 313c-6.9-6.9-8.9-17.2-5.2-26.2s12.5-14.8 22.2-14.8z\"></path></svg></div></nav>")
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 20, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve navigation controls accessibility and safety

The navigation controls require the following enhancements:

  1. Add proper ARIA labels and roles for accessibility
  2. Add confirmation dialogue for cache flush operation
- <div class="navigation--item navigation--more-info rounded">
+ <button type="button" class="navigation--item navigation--more-info rounded" 
+         aria-label="Show more information">

- <div class="navigation--item navigation--flush-cache rounded" 
-      hx-get="/cache/flush" hx-swap="none">
+ <button type="button" class="navigation--item navigation--flush-cache rounded"
+         hx-get="/cache/flush" 
+         hx-confirm="Are you sure you want to flush the cache?"
+         hx-swap="none"
+         aria-label="Flush cache">

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

Copy link
Owner Author

Choose a reason for hiding this comment

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

Ignore all *_templ.go files.

Copy link
Contributor

Choose a reason for hiding this comment

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

@damongolding, understood. To ignore all *_templ.go files in future code reviews, you can configure CodeRabbit to exclude these files using the path_filters setting in your configuration. This will ensure that these generated files are not included in automated reviews.


✏️ Learnings added
Learnt from: damongolding
PR: damongolding/immich-kiosk#194
File: views/views_menu_templ.go:32-32
Timestamp: 2024-11-20T22:25:29.813Z
Learning: Ignore all `*_templ.go` files in code reviews.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

utils/utils.go Outdated
Comment on lines 426 to 440
func CreateQrCode(link string) string {
png, err := qrcode.Encode(link, qrcode.Medium, 256)
if err != nil {
log.Error("QR code", "err", err)
return ""
}

i, err := ImageToBase64(png)
if err != nil {
log.Error("QR code", "err", err)
return ""
}

return i
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

🛠️ Refactor suggestion

QR code size can be reduced to improve performance

The current 256x256 size for QR codes is indeed excessive, as the CSS shows the QR code is constrained to max-width: 14rem (approximately 224 pixels) and is displayed in a flex container with a border radius. A QR code size of 128x128 would be sufficient while maintaining readability.

The suggested improvements in the review are valid:

  • Reducing QR size to 128x128 will improve performance without affecting usability
  • Input validation is missing and should be added
  • Error logging can be more descriptive
  • Function documentation would improve maintainability

However, making the size configurable via parameter isn't necessary as the QR code has a single, well-defined use case in the template with consistent styling.

🔗 Analysis chain

Add input validation and improve error handling

The function has several areas for improvement:

  1. Missing input validation for the link parameter
  2. Silent failures might cause confusion downstream
  3. Fixed QR code size of 256x256 might be excessive for some use cases
  4. Missing function documentation

Consider this improved implementation:

+// CreateQrCode generates a QR code for the given link and returns it as a base64-encoded string.
+// It returns an empty string if the QR code generation or base64 encoding fails.
+// The QR code is generated with medium error correction level.
 func CreateQrCode(link string) string {
+    if link == "" {
+        log.Error("QR code generation failed: empty link provided")
+        return ""
+    }
+
+    // Use a more reasonable default size
+    const qrSize = 128
+
-    png, err := qrcode.Encode(link, qrcode.Medium, 256)
+    png, err := qrcode.Encode(link, qrcode.Medium, qrSize)
     if err != nil {
-        log.Error("QR code", "err", err)
+        log.Error("QR code generation failed", "link", link, "err", err)
         return ""
     }

     i, err := ImageToBase64(png)
     if err != nil {
-        log.Error("QR code", "err", err)
+        log.Error("QR code base64 encoding failed", "link", link, "err", err)
         return ""
     }

     return i
 }

Additionally, consider:

  1. Making the QR code size configurable via a parameter
  2. Adding URL validation for the link parameter
  3. Returning an error instead of an empty string to allow proper error handling upstream

Let's verify the QR code size impact:


Let me gather more information about the QR code usage and image dimensions.


Let me check the CSS styling for the QR code container to understand any size constraints.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check QR code usage in templates to determine if 256x256 size is necessary

# Search for QR code rendering in templates
rg -A 5 "CreateQrCode" 

Length of output: 1123


Script:

#!/bin/bash
# Check if there are any CSS styles or attributes that might affect the QR code size
rg -g '*.{css,templ}' 'img.*src=.*CreateQrCode' -B 2 -A 2

# Check if there are any other QR code related configurations or constants
rg -g '*.go' 'qr.*size|qrcode.*size|QR.*size' -i

Length of output: 395


Script:

#!/bin/bash
# Check CSS styles for the QR code container
rg -g '*.{css,scss}' 'more-info--image--qr-code' -B 2 -A 5

# Check the template file structure to understand the QR code's context
cat views/views_image.templ

Length of output: 11512

Comment on lines 554 to 595
/* src/css/image-more-info.css */
#more-info {
display: none;
}
.polling-paused.more-info .frame--image img {
-webkit-filter: grayscale(1) blur(4px) brightness(0.4);
filter: grayscale(1) blur(4px) brightness(0.4);
}
.polling-paused.more-info #more-info {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: -webkit-flex;
display: -moz-box;
display: flex;
gap: 0.4rem;
padding: 0.4rem;
z-index: 99998;
}
.polling-paused.more-info #more-info .more-info--image {
width: 100%;
height: 100%;
background-color: rgb(51 52 96 / 60%);
display: -webkit-flex;
display: -moz-box;
display: flex;
-webkit-flex-direction: column;
-moz-box-orient: vertical;
-moz-box-direction: normal;
flex-direction: column;
-webkit-justify-content: space-between;
-moz-box-pack: justify;
justify-content: space-between;
padding: 6rem 3rem 3rem 3rem;
color: #fff;
border-radius: 0.74rem;
display: flex;
flex-direction: column;
gap: 2rem;
}
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 20, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove duplicate display:flex declarations and consider accessibility improvements.

There are a few issues to address in the more-info overlay styles:

  1. Duplicate display:flex declarations (lines 568-570 and 592-593)
  2. The background colour rgb(51 52 96 / 60%) might not provide sufficient contrast for text

Apply this diff to fix the duplicates and improve accessibility:

    display: -webkit-flex;
    display: -moz-box;
    display: flex;
    -webkit-flex-direction: column;
       -moz-box-orient: vertical;
       -moz-box-direction: normal;
            flex-direction: column;
    -webkit-justify-content: space-between;
       -moz-box-pack: justify;
            justify-content: space-between;
    padding: 6rem 3rem 3rem 3rem;
    color: #fff;
    border-radius: 0.74rem;
-   display: flex;
-   flex-direction: column;
    gap: 2rem;
+   background-color: rgba(51, 52, 96, 0.85);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* src/css/image-more-info.css */
#more-info {
display: none;
}
.polling-paused.more-info .frame--image img {
-webkit-filter: grayscale(1) blur(4px) brightness(0.4);
filter: grayscale(1) blur(4px) brightness(0.4);
}
.polling-paused.more-info #more-info {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: -webkit-flex;
display: -moz-box;
display: flex;
gap: 0.4rem;
padding: 0.4rem;
z-index: 99998;
}
.polling-paused.more-info #more-info .more-info--image {
width: 100%;
height: 100%;
background-color: rgb(51 52 96 / 60%);
display: -webkit-flex;
display: -moz-box;
display: flex;
-webkit-flex-direction: column;
-moz-box-orient: vertical;
-moz-box-direction: normal;
flex-direction: column;
-webkit-justify-content: space-between;
-moz-box-pack: justify;
justify-content: space-between;
padding: 6rem 3rem 3rem 3rem;
color: #fff;
border-radius: 0.74rem;
display: flex;
flex-direction: column;
gap: 2rem;
}
/* src/css/image-more-info.css */
#more-info {
display: none;
}
.polling-paused.more-info .frame--image img {
-webkit-filter: grayscale(1) blur(4px) brightness(0.4);
filter: grayscale(1) blur(4px) brightness(0.4);
}
.polling-paused.more-info #more-info {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: -webkit-flex;
display: -moz-box;
display: flex;
gap: 0.4rem;
padding: 0.4rem;
z-index: 99998;
}
.polling-paused.more-info #more-info .more-info--image {
width: 100%;
height: 100%;
background-color: rgba(51, 52, 96, 0.85);
display: -webkit-flex;
display: -moz-box;
display: flex;
-webkit-flex-direction: column;
-moz-box-orient: vertical;
-moz-box-direction: normal;
flex-direction: column;
-webkit-justify-content: space-between;
-moz-box-pack: justify;
justify-content: space-between;
padding: 6rem 3rem 3rem 3rem;
color: #fff;
border-radius: 0.74rem;
gap: 2rem;
}

Copy link
Owner Author

Choose a reason for hiding this comment

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

Ignore everything in frontend/public/*

Copy link
Contributor

Choose a reason for hiding this comment

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

@damongolding, to have CodeRabbit ignore everything in frontend/public/*, you can update your CodeRabbit configuration to exclude this path using the path_filters option. Here's how you can set it up:

path_filters:
  exclude:
    - 'frontend/public/*'

This will prevent files under frontend/public/ from being included in future code reviews.

views/views_image_templ.go Outdated Show resolved Hide resolved
Comment on lines 153 to 157
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(utils.CreateQrCode(imageUrl(viewData.ImmichUrl, img.ImmichImage.ID)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 80, Col: 84}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for QR code generation

The utils.CreateQrCode() function may return an error that's currently not being checked. Ignoring this error could lead to runtime panics or silent failures. Ensure that errors are properly handled to maintain robustness.

Update the code to handle the error:

 var templ_7745c5c3_Var6 string
-templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(utils.CreateQrCode(imageUrl(viewData.ImmichUrl, img.ImmichImage.ID)))
+qrCode, err := utils.CreateQrCode(imageUrl(viewData.ImmichUrl, img.ImmichImage.ID))
+if err != nil {
+    return templ.Error{Err: err, FileName: `views/views_image.templ`, Line: 80, Col: 84}
+}
+templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(qrCode)
 if templ_7745c5c3_Err != nil {
     return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 80, Col: 84}
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(utils.CreateQrCode(imageUrl(viewData.ImmichUrl, img.ImmichImage.ID)))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 80, Col: 84}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
qrCode, err := utils.CreateQrCode(imageUrl(viewData.ImmichUrl, img.ImmichImage.ID))
if err != nil {
return templ.Error{Err: err, FileName: `views/views_image.templ`, Line: 80, Col: 84}
}
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(qrCode)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/views_image.templ`, Line: 80, Col: 84}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))

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 and nitpick comments (1)
.coderabbit.yaml (1)

9-9: Add a newline at the end of file

YAML files should end with a newline character to comply with POSIX standards and ensure proper file concatenation.

Apply this diff:

  - path: "*_templ.go"
-    action: ignore
+    action: ignore
+
🧰 Tools
🪛 yamllint

[error] 9-9: no new line character at the end of file

(new-line-at-end-of-file)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1df6799 and dd8d983.

📒 Files selected for processing (2)
  • .coderabbit.yaml (1 hunks)
  • frontend/src/css/image-more-info.css (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/css/image-more-info.css
🧰 Additional context used
🪛 yamllint
.coderabbit.yaml

[error] 9-9: no new line character at the end of file

(new-line-at-end-of-file)

🔇 Additional comments (1)
.coderabbit.yaml (1)

1-9: Path filters configuration looks sensible

The configuration appropriately excludes:

  • Example CSS file that shouldn't be processed
  • Public assets directory that likely contains generated files
  • Generated Go template files

This helps focus the reviews on meaningful code changes.

🧰 Tools
🪛 yamllint

[error] 9-9: no new line character at the end of file

(new-line-at-end-of-file)

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between dd8d983 and a59332c.

📒 Files selected for processing (1)
  • .coderabbit.yaml (1 hunks)
🔇 Additional comments (2)
.coderabbit.yaml (2)

6-7: Verify the frontend/public directory structure

The configuration to ignore the public directory is properly formatted. Let's confirm the directory structure.

✅ Verification successful

Frontend public directory exists and is properly configured for ignoring

The verification confirms that the frontend/public/ directory exists in the expected location, validating the ignore configuration in .coderabbit.yaml.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the frontend/public directory exists
# Expected: Directory should exist as it's typically used for static assets

fd -t d "^public$" frontend/

Length of output: 47


9-10: Verify the template file pattern

The wildcard pattern for ignoring template files is correct. Let's verify if there are matching files.

✅ Verification successful

Template file pattern correctly matches existing files

The pattern *_templ.go successfully matches 8 template files in the views directory, confirming that the ignore pattern is correctly configured to exclude Go template files from analysis.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for template files matching the pattern
# Expected: Should find Go template files if they exist

fd "_templ\.go$"

Length of output: 249

.coderabbit.yaml Outdated
Comment on lines 1 to 4
reviews:
path_filters:
- path: "custom.example.css"
action: ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

The path filter configuration appears to be incorrect

This CSS file appears to be an actual stylesheet containing real application styles, not just an example file. It contains numerous CSS rules for various components like clock, weather, menu, and kiosk functionality. Ignoring this file would mean excluding important styling rules from code reviews.

  • Consider removing this path filter from .coderabbit.yaml as the file appears to be a crucial part of the application's styling system.
  • If you need to exclude specific CSS files, ensure you're targeting the correct files that should genuinely be ignored.
🔗 Analysis chain

Verify the existence of the example CSS file

The path filter configuration looks correct. However, let's verify if this example file exists in the repository.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the example CSS file exists
# Expected: No matches as it should be an example file that doesn't exist

fd "custom.example.css"

Length of output: 42


Script:

#!/bin/bash
# Let's check the content of the CSS file to understand if it's truly an example file
cat custom.example.css

Length of output: 4854

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: 13

🧹 Outside diff range and nitpick comments (25)
frontend/src/css/vars.css (1)

7-7: Consider grouping related gradients

Whilst the gradient section is well-commented, consider expanding this section if more gradients are planned. This would help maintain a scalable structure as the design system grows.

frontend/src/ts/menu.ts (2)

11-11: Add type annotation for better type safety

Add explicit type annotation to the variable declaration for better TypeScript type safety and code readability.

-let imageOverlayVisible = false;
+let imageOverlayVisible: boolean = false;

31-46: Add JSDoc documentation for the new functions

The new overlay functions lack documentation. Add JSDoc comments to maintain consistency with the existing codebase style and improve maintainability.

+/**
+ * Shows the image overlay if polling is paused
+ */
 function showImageOverlay() {

+/**
+ * Hides the image overlay
+ */
 function hideImageOverlay() {

+/**
+ * Toggles the visibility of the image overlay
+ */
 function toggleImageOverlay() {
frontend/src/css/image-more-info.css (4)

1-6: Consider enhancing accessibility for screen readers

Whilst the text selection functionality is good, consider adding ARIA attributes to improve screen reader support.

 #more-info {
     display: none;
     * {
         user-select: text;
+        cursor: text;
     }
+    &[aria-hidden="true"] {
+        display: none;
+    }
+    &[aria-hidden="false"] {
+        display: flex;
+    }
 }

9-11: Consider using CSS custom properties for filter values

Extract the filter values into CSS custom properties for better maintainability and consistency.

+:root {
+    --image-blur-amount: 4px;
+    --image-brightness: 0.4;
+}
 .polling-paused.more-info {
     .frame--image img {
-        filter: grayscale(1) blur(4px) brightness(0.4);
+        filter: grayscale(1) blur(var(--image-blur-amount)) brightness(var(--image-brightness));
     }

24-24: Consider reducing the z-index value

The z-index value of 99998 is unnecessarily high and could cause stacking context issues.

-        z-index: 99998;
+        z-index: 10;

29-29: Use CSS custom properties for colours

Convert the RGB colour value to a CSS custom property for better theme management.

+:root {
+    --overlay-background: rgb(51 52 96 / 60%);
+}
-            background-color: rgb(51 52 96 / 60%);
+            background-color: var(--overlay-background);
webhooks/webhooks.go (1)

Line range hint 67-116: The existing Trigger function seamlessly supports the new event.

The generic webhook handling implementation with proper error handling, configurable timeouts, and flexible payload structure makes this a clean extension of functionality. No modifications to the core webhook logic were necessary.

Consider documenting the new webhook event in the project's webhook documentation to help users integrate with this feature.

custom.example.css (3)

65-79: Consider organising CSS with BEM methodology

The new overlay-related styles could benefit from following the Block Element Modifier (BEM) methodology for better maintainability. For example:

.more-info {}
.more-info__image {}
.more-info__image--polling-paused {}

This would make the relationship between components clearer and reduce CSS specificity issues.

Would you like me to help restructure these selectors using BEM?

🧰 Tools
🪛 Biome

[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 77-77: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 78-78: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 79-79: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


76-77: Consider using CSS custom properties for layout values

The landscape layout styles could benefit from CSS custom properties to maintain consistent values:

:root {
  --more-info-width: 300px;
  --more-info-padding: 1rem;
}

This would make it easier to maintain consistent spacing and dimensions across different layouts.

🧰 Tools
🪛 Biome

[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 77-77: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


Line range hint 1-1: Consider adding documentation for customisation

As this is an example file, it would be helpful to add comments explaining:

  • How to customise the styles
  • Which values should be modified
  • The relationship between different CSS modules

This would make it easier for users to understand how to implement their own styles.

🧰 Tools
🪛 Biome

[error] 40-40: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 41-41: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 43-43: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 44-44: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 45-45: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 46-46: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

views/views_menu.templ (1)

23-23: Consider enhancing the more-info container's HTMX integration

The more-info container is properly structured for out-of-band swapping, but it lacks explicit HTMX attributes for content loading and visibility toggling.

Consider adding these HTMX attributes:

-<div id="more-info" class="hidden" hx-swap-oob="true"></div>
+<div
+    id="more-info"
+    class="hidden"
+    hx-swap-oob="true"
+    hx-swap="innerHTML"
+    hx-target="this"
+></div>
immich/immich.go (2)

50-55: Consider adjusting connection pool settings based on load patterns

The transport configuration uses fixed values that might need adjustment based on your application's traffic patterns:

  • MaxIdleConns: 100 might be excessive for low-traffic scenarios
  • IdleConnTimeout: 90s could lead to connection churn under bursty traffic

Consider implementing monitoring to track connection pool utilisation and adjust these values accordingly. Key metrics to monitor:

  • Connection pool saturation
  • Connection establishment latency
  • Connection lifetime distribution

47-59: Consider implementing circuit breaker pattern

The HTTP client configuration would benefit from a circuit breaker implementation to handle API failures gracefully. This is particularly important given the connection pooling configuration.

Consider using a library like sony/gobreaker or afex/hystrix-go to implement circuit breaking. Example implementation:

import "github.com/sony/gobreaker"

var (
    breaker = gobreaker.NewCircuitBreaker(gobreaker.Settings{
        Name:        "immich-api",
        MaxRequests: 3,
        Interval:    10 * time.Second,
        Timeout:     60 * time.Second,
        ReadyToTrip: func(counts gobreaker.Counts) bool {
            failureRatio := float64(counts.TotalFailures) / float64(counts.Requests)
            return counts.Requests >= 3 && failureRatio >= 0.6
        },
    })
    
    httpTransport = &http.Transport{
        MaxIdleConns:        100,
        IdleConnTimeout:     90 * time.Second,
        DisableKeepAlives:   false,
        MaxIdleConnsPerHost: 100,
    }
)
views/views_image.templ (3)

25-25: Consider lazy loading the additional information

The renderMoreInfo template is always rendered for all images, which might impact initial page load performance. Consider lazy loading this information when the user requests it.

-@renderMoreInfo(viewData)
+<div
+    hx-get="/more-info"
+    hx-trigger="click"
+    hx-target="#more-info"
+    hx-swap="innerHTML"
+>Show more info</div>
+<div id="more-info"></div>

79-88: Add feedback for webhook trigger button

The webhook trigger button lacks visual feedback and loading states. Consider adding HTMX indicators and success/error feedback.

 <button
     class="more-info--webhook"
     hx-post="/webhooks"
     hx-trigger="click"
     hx-include=".kiosk-history--entry"
     hx-headers='{"kiosk-webhook-event": "user.webhook.trigger.info_overlay"}'
+    hx-indicator="#webhook-indicator"
+    hx-swap="outerHTML"
 >
     Trigger webhook
+    <span id="webhook-indicator" class="htmx-indicator">
+        Processing...
+    </span>
 </button>

46-95: Add loading states for image information

The more info section could benefit from progressive enhancement and loading states.

  1. Add loading indicators for QR code generation
  2. Progressive loading of image details
  3. Error states for failed operations

Example implementation:

 <div id="more-info" class="hidden" hx-swap-oob="true">
     for _, img := range viewData.Images {
         <div class="more-info--image"
+            hx-trigger="revealed"
+            hx-get="/api/image-details/{img.ImmichImage.ID}"
+            hx-indicator=".loading-indicator"
         >
+            <div class="loading-indicator">Loading image details...</div>
             ...
         </div>
     }
 </div>
utils/utils.go (3)

Line range hint 42-52: Enhance type documentation with usage examples

The type documentation could be more descriptive by including usage examples and explaining the relationship between WeightedAsset and AssetWithWeighting.

Add more detailed documentation:

-// WeightedAsset represents an asset with a type and ID
+// WeightedAsset represents an asset with a type identifier and unique ID.
+// It is typically used in conjunction with AssetWithWeighting for weighted random selection.
 type WeightedAsset struct {
     Type string
     ID   string
 }

-// AssetWithWeighting represents a WeightedAsset with an associated weight value
+// AssetWithWeighting combines a WeightedAsset with its weight value.
+// The weight value influences the probability of the asset being selected
+// in weighted random selection operations.
 type AssetWithWeighting struct {
     Asset  WeightedAsset
     Weight int
 }

Line range hint 394-428: Consider explicit time zone handling

The function uses the time zone from currentTime, but this might lead to unexpected behaviour if the caller provides times in different zones.

Consider adding a time zone parameter or documenting the expected time zone behaviour:

-func IsSleepTime(sleepStartTime, sleepEndTime string, currentTime time.Time) (bool, error) {
+// IsSleepTime checks if the current time falls within a sleep period.
+// All times are interpreted in the time zone of currentTime.
+func IsSleepTime(sleepStartTime, sleepEndTime string, currentTime time.Time) (bool, error) {

429-433: Enhance error handling and documentation

The function could be more robust by handling additional edge cases and providing more detailed documentation.

Consider this enhanced implementation:

-// FileExists checks if a file exists at the specified path
+// FileExists checks if a file exists and is accessible at the specified path.
+// It returns false if the file doesn't exist or if there are permission issues.
 func FileExists(filename string) bool {
-    _, err := os.Stat(filename)
-    return !os.IsNotExist(err)
+    info, err := os.Stat(filename)
+    if err != nil {
+        return false
+    }
+    return !info.IsDir()
 }
README.md (1)

765-771: LGTM! Clear and well-structured webhook events documentation.

The table provides a comprehensive overview of available webhook events with clear descriptions. The documentation will help users understand and implement webhook functionality effectively.

Consider adding example payloads for each event type to help users understand the data structure they'll receive. For instance:

| Event         | Description                                             | Example Payload |
|--------------|----------------------------------------------------------|----------------|
|`asset.new`   | Triggered when a new image is requested from Kiosk      | `{"event": "asset.new", ...}` |
immich/immich_helpers.go (1)

Line range hint 147-154: Include unexpected status codes in retry logic

Currently, the function does not retry when an unexpected status code is received, and lastErr may remain nil, leading to incomplete error messages.

Modify the logic to include unexpected status codes in the retry mechanism and ensure lastErr is assigned accordingly. Apply this diff to assign lastErr:

     if res.StatusCode < 200 || res.StatusCode >= 300 {
         err = fmt.Errorf("unexpected status code: %d", res.StatusCode)
         log.Error(err)
+        lastErr = err
         _, _ = io.Copy(io.Discard, res.Body)
-        return responseBody, err
+        continue
     }
frontend/public/assets/css/kiosk.css (3)

588-590: Refactor to remove outdated -moz-box display property

The display: -moz-box; property is outdated and no longer necessary. Modern browsers, including Firefox, support display: flex; without prefixes.

Apply this change to simplify the code:

      display: -webkit-flex;
-     display: -moz-box;
      display: flex;

This enhances code maintainability and ensures better cross-browser compatibility.


591-594: Simplify flex-direction properties by removing obsolete -moz-box prefixes

The -moz-box-orient and -moz-box-direction properties are obsolete. Use standard flex-direction for consistency.

Apply this diff to clean up the code:

      -webkit-flex-direction: column;
-     -moz-box-orient: vertical;
-     -moz-box-direction: normal;
      flex-direction: column;

This modernises the CSS and improves readability.


595-597: Remove outdated -moz-box-pack property

The -moz-box-pack property is deprecated. The standard justify-content property is sufficient.

Apply this change:

      -webkit-justify-content: space-between;
-     -moz-box-pack: justify;
      justify-content: space-between;

This streamlines the code and ensures it adheres to current CSS standards.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a59332c and be96fc4.

📒 Files selected for processing (20)
  • README.md (1 hunks)
  • custom.example.css (5 hunks)
  • frontend/public/assets/css/kiosk.css (9 hunks)
  • frontend/src/css/image-more-info.css (1 hunks)
  • frontend/src/css/menu.css (5 hunks)
  • frontend/src/css/vars.css (1 hunks)
  • frontend/src/ts/kiosk.ts (2 hunks)
  • frontend/src/ts/menu.ts (3 hunks)
  • go.mod (1 hunks)
  • immich/immich.go (1 hunks)
  • immich/immich_album.go (1 hunks)
  • immich/immich_helpers.go (3 hunks)
  • main.go (1 hunks)
  • routes/routes_webhooks.go (1 hunks)
  • utils/utils.go (6 hunks)
  • views/views_image.templ (2 hunks)
  • views/views_image_templ.go (18 hunks)
  • views/views_menu.templ (2 hunks)
  • views/views_menu_templ.go (1 hunks)
  • webhooks/webhooks.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/src/css/menu.css
  • go.mod
  • views/views_menu_templ.go
🧰 Additional context used
🪛 Biome
custom.example.css

[error] 43-43: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 77-77: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 78-78: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 79-79: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 96-96: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 156-156: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 165-165: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

frontend/src/ts/kiosk.ts

[error] 167-168: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 169-169: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🔇 Additional comments (24)
frontend/src/css/vars.css (1)

2-5: Well-structured colour system implementation

The new colour variables establish a clear and maintainable colour system. The semantic naming convention (light-grey, cool-grey, mint-green) makes the purpose of each colour clear whilst maintaining consistency.

Let's verify the usage of these new colour variables across the codebase:

✅ Verification successful

New colour variables are actively used across multiple UI components

The verification confirms these colour variables are properly utilised across several key UI components:

  • image-more-info.css: Used for information overlays
  • menu.css: Applied to menu components
  • kiosk.css: Implemented in the kiosk interface

The consistent usage of --mint-green for backgrounds and --cool-grey for text/icons demonstrates a cohesive design system implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for usage of the new colour variables
# Expected: Find references in CSS/SCSS files using these variables

rg --type css "var\(--(light-grey|cool-grey|mint-green)\)"

Length of output: 622

frontend/src/ts/menu.ts (2)

65-67: LGTM! Export modifications look good

The new functions are properly exported, maintaining the module's interface consistency.


31-46: Verify overlay functionality integration

Let's verify how these overlay functions are integrated with other components in the codebase.

✅ Verification successful

Overlay functionality is properly integrated across the codebase

The verification shows that the overlay functions are well-integrated and used appropriately:

  • Functions are exported from menu.ts and imported where needed (e.g., hideImageOverlay in polling.ts)
  • toggleImageOverlay is used in kiosk.ts for user interactions
  • CSS classes (polling-paused and more-info) are consistently used across stylesheets with proper styling for different states and components
  • The implementation follows a clear pattern where hideImageOverlay is called during polling operations to ensure proper state management
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage of overlay functions and related CSS classes

# Check for overlay function usage
echo "Checking function usage:"
rg -t ts "(showImageOverlay|hideImageOverlay|toggleImageOverlay)"

# Check for related CSS classes
echo -e "\nChecking CSS class usage:"
rg -t css "\.more-info|\.polling-paused"

Length of output: 4032

frontend/src/css/image-more-info.css (1)

71-79: Responsive layout implementation looks good

The landscape view adaptation is well-implemented using flex direction changes.

webhooks/webhooks.go (1)

19-23: LGTM! The new webhook event constant follows established patterns.

The new UserWebhookTriggerInfoOverlay constant is well-integrated with the existing webhook events, following consistent naming and value patterns.

Let's verify the webhook event handling implementation:

✅ Verification successful

The new webhook event is properly integrated and handled

The verification confirms that:

  • The new webhook event is properly defined and documented in README.md
  • The event is triggered via an HTMX button in the image details overlay
  • The Trigger function handles all webhook events uniformly, including the new one, by:
    • Validating the event type against configured webhooks
    • Creating a standardised payload with image details
    • Sending POST requests to configured webhook URLs
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the webhook event handling implementation
# Expected: Find the handler for the new info_overlay event

# Search for handlers of the new webhook event
rg -A 5 "user\.webhook\.trigger\.info_overlay"

# Look for webhook route definitions
ast-grep --pattern 'func $_($$_) {
  $$$
  $event := $$$
  if $event == "user.webhook.trigger.info_overlay" {
    $$$
  }
  $$$
}'

Length of output: 1947


Script:

#!/bin/bash
# Let's verify the webhook handling implementation by checking the Trigger function
# and related webhook handling code

# Find the Trigger function implementation
ast-grep --pattern 'func Trigger($$$) {
  $$$
}'

# Look for webhook handler routes
rg -A 5 "func.*webhook.*handler"

# Check for any webhook event validation
rg -A 5 "WebhookEvent.*validation"

Length of output: 2538

main.go (1)

128-129: Implementation follows established patterns

The webhook route is properly integrated into the existing routing structure and follows the established pattern of route definitions. The use of POST method is appropriate for webhook endpoints.

views/views_menu.templ (2)

27-27: Excellent accessibility improvements

The addition of ARIA attributes to the SVG icons enhances screen reader compatibility whilst properly hiding decorative elements.

Also applies to: 43-43


49-54: ⚠️ Potential issue

Address previous review feedback for the more-info button

The implementation still requires the improvements mentioned in the previous review regarding interactivity and accessibility.

Additionally, consider adding visual feedback for hover and active states:

-<div class="navigation--item navigation--more-info rounded">
+<div
+    class="navigation--item navigation--more-info rounded"
+    data-tooltip="More Information"
+    hx-get="/image/info"
+    hx-target="#more-info"
+    hx-trigger="click"
+    role="button"
+    aria-label="Show more information"
+>
immich/immich.go (1)

58-59: Verify timeout configuration alignment

The HTTP client timeout is derived from requestConfig.Kiosk.HTTPTimeout, but there's no validation to ensure it's greater than the IdleConnTimeout (90s) set in the transport configuration.

✅ Verification successful

Let me gather more information about the timeout configurations.


Let me search for the transport configuration to verify the timeout settings.


Let me try a different search pattern to find the transport and timeout configurations.


HTTP client timeout configuration is properly aligned

The HTTP client timeout is set to the value from requestConfig.Kiosk.HTTPTimeout, which defaults to 20 seconds (from config.example.yaml). This is well below the IdleConnTimeout of 90 seconds set in the transport configuration, ensuring proper timeout hierarchy. The shorter HTTP timeout will trigger before the idle connection timeout, preventing any timing conflicts.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for timeout configuration in the codebase
# Expected: Find the HTTPTimeout configuration to verify its value

# Search for HTTPTimeout configuration
rg -A 2 "HTTPTimeout.*=.*" 

# Search for any timeout-related configuration
rg -A 2 "Timeout.*=.*[0-9]"

Length of output: 88338


Script:

#!/bin/bash
# Search for timeout-related configurations in the codebase
rg -A 2 "HTTPTimeout.*=.*[0-9]" 
rg -A 2 "IdleConnTimeout.*=.*[0-9]" 
rg -A 2 "timeout.*=.*[0-9]" 

Length of output: 88381


Script:

#!/bin/bash
# Search for transport configuration and timeout settings
rg -A 5 "transport.*:.*{" 
rg -A 5 "IdleConnTimeout.*=.*" 
rg -A 5 "httpTransport.*:.*" 

Length of output: 185


Script:

#!/bin/bash
# Search for transport and timeout configurations with fixed patterns
rg -A 5 "Transport:" 
rg -A 5 "transport:" 
rg -A 5 "Timeout:" 
rg -A 5 "timeout:" 

Length of output: 90421

views/views_image.templ (3)

7-8: LGTM: Appropriate standard library imports

The added imports are necessary for URL manipulation in the new imageUrl function.


74-76: Previous accessibility comment is still valid


91-91: Previous QR code accessibility comment is still valid

views/views_image_templ.go (3)

70-85: Past review comment is still valid.

The existing review comment about URL encoding the imageID parameter is still applicable.


194-196: LGTM: Improved variable naming

The variable renaming enhances code readability and maintains consistency across the codebase.

Also applies to: 227-229, 262-264


594-599: 🛠️ Refactor suggestion

Enhance image URL security

Consider implementing additional security measures for image URLs:

  1. Validate image URLs against an allowlist of trusted domains
  2. Implement Content Security Policy headers to restrict image sources
  3. Add URL sanitisation to prevent XSS via malicious URLs

Also applies to: 641-646, 688-693

routes/routes_webhooks.go (1)

85-85: Asynchronous Call to webhooks.Trigger May Suppress Errors

The webhooks.Trigger function is called asynchronously using go, which means any errors returned by this function will not be captured or logged. This could make debugging difficult if the webhook triggering fails.

Consider whether the asynchronous call is necessary. If it is, ensure that errors are properly handled within the webhooks.Trigger function itself. Alternatively, remove the goroutine to handle errors directly:

-			go webhooks.Trigger(requestData, KioskVersion, webhooks.UserWebhookTriggerInfoOverlay, ViewData)
+			if err := webhooks.Trigger(requestData, KioskVersion, webhooks.UserWebhookTriggerInfoOverlay, ViewData); err != nil {
+				log.Error("Failed to trigger webhook", "error", err)
+				return err
+			}

This modification allows you to capture and log any errors from the webhooks.Trigger function.

frontend/src/ts/kiosk.ts (4)

18-18: Import of toggleImageOverlay added correctly

The toggleImageOverlay function is properly imported from the menu module, preparing it for use later in the code.


155-156: Event listeners now correctly invoke togglePolling()

The event listeners for menuInteraction and menuPausePlayButton now correctly call togglePolling() when clicked, ensuring the polling functionality toggles as expected.


159-180: Refactor the keydown event handler for better maintainability

A previous suggestion to refactor the keydown event handler is still applicable. Refactoring can enhance readability and maintainability by simplifying the logic and clarifying variable usage.

🧰 Tools
🪛 Biome

[error] 167-168: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 169-169: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


188-190: Event listener for .navigation--more-info added appropriately

The event listener for the .navigation--more-info element correctly invokes toggleImageOverlay() on click, integrating the overlay functionality into the user interface.

frontend/public/assets/css/kiosk.css (4)

374-376: No issues with opacity adjustment for .image--metadata

The opacity reduction for .image--metadata when polling is paused and more info is displayed is appropriate.


587-587: Consider improving background colour for accessibility

The background colour rgb(51 52 96 / 60%) might not provide sufficient contrast with the text, potentially affecting readability.


756-758: No issues with opacity adjustment for #clock-weather-container

Dimming the clock and weather container when more info is displayed enhances focus on the overlay content.


1255-1255: Ensure correct stacking context with z-index

Setting z-index: 99997; for #navigation-interaction-area seems appropriate to manage layering of interactive elements.

Comment on lines 81 to 94
.more-info--webhook {
background-color: var(--mint-green);
outline: none;
border: none;
color: var(--cool-grey);
font-weight: 600;
border-radius: 60rem;
padding: 0.5rem 2rem;
font-size: 1rem;
cursor: pointer;
&:hover {
filter: brightness(85%);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance button interaction states

Add transition effects and keyboard focus states for better accessibility and user experience.

 .more-info--webhook {
     background-color: var(--mint-green);
     outline: none;
     border: none;
     color: var(--cool-grey);
     font-weight: 600;
     border-radius: 60rem;
     padding: 0.5rem 2rem;
     font-size: 1rem;
     cursor: pointer;
+    transition: filter 0.2s ease;
+
     &:hover {
         filter: brightness(85%);
     }
+    &:focus-visible {
+        outline: 2px solid var(--cool-grey);
+        outline-offset: 2px;
+    }
+    &:active {
+        filter: brightness(75%);
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.more-info--webhook {
background-color: var(--mint-green);
outline: none;
border: none;
color: var(--cool-grey);
font-weight: 600;
border-radius: 60rem;
padding: 0.5rem 2rem;
font-size: 1rem;
cursor: pointer;
&:hover {
filter: brightness(85%);
}
}
.more-info--webhook {
background-color: var(--mint-green);
outline: none;
border: none;
color: var(--cool-grey);
font-weight: 600;
border-radius: 60rem;
padding: 0.5rem 2rem;
font-size: 1rem;
cursor: pointer;
transition: filter 0.2s ease;
&:hover {
filter: brightness(85%);
}
&:focus-visible {
outline: 2px solid var(--cool-grey);
outline-offset: 2px;
}
&:active {
filter: brightness(75%);
}
}

main.go Outdated
Comment on lines 128 to 129
e.POST("/webhooks", routes.Webhooks(baseConfig))

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Additional security measures needed for webhook endpoint

The codebase review confirms that while webhook functionality is implemented, it lacks essential security measures. The current implementation:

  • Has no rate limiting middleware
  • No CORS protection
  • No request signature validation
  • No IP allowlisting

Specific areas requiring attention:

  • main.go: Add rate limiting middleware before the webhook route
  • routes/routes_webhooks.go: Implement webhook signature validation
  • config/config.go: Add configuration options for webhook security settings (allowed IPs, secrets)
🔗 Analysis chain

Consider additional security measures for webhook endpoint

As webhook endpoints are exposed to external systems, consider implementing:

  • Rate limiting to prevent DoS attacks
  • CORS policy if needed for cross-origin requests
  • Request signature validation or webhook secrets
  • IP allowlisting for trusted sources

Let's check if any rate limiting or CORS middleware is already configured:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for rate limiting or CORS middleware configuration
rg -A 5 'middleware\.(CORS|RateLimit)'

# Check if there are any existing webhook security patterns
ast-grep --pattern 'func Webhooks($_) {
  $$$
}'

Length of output: 91


Script:

#!/bin/bash
# Let's try different patterns to find security-related middleware and webhook handler
rg -i "(cors|rate.?limit|security|webhook)" -A 5

# Search for the webhook handler implementation
fd -e go -x cat {} | grep -A 10 "func.*Webhook"

# Look for middleware setup in main.go
cat main.go

Length of output: 18263

immich/immich_album.go Show resolved Hide resolved
views/views_image.templ Outdated Show resolved Hide resolved
utils/utils.go Outdated Show resolved Hide resolved
routes/routes_webhooks.go Outdated Show resolved Hide resolved
frontend/src/ts/kiosk.ts Outdated Show resolved Hide resolved
immich/immich_helpers.go Outdated Show resolved Hide resolved
immich/immich_helpers.go Show resolved Hide resolved
immich/immich_helpers.go Show resolved Hide resolved
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: 8

🧹 Outside diff range and nitpick comments (15)
frontend/src/css/vars.css (1)

2-6: LGTM! Consider documenting colour usage.

The new colour variables are well-organised and follow consistent British English naming conventions. However, it would be beneficial to document the intended usage of each colour to maintain design consistency across the application.

Add comments to describe the intended usage of each colour variable:

 /* colours */
-    --light-grey: #f7f9f8;
-    --cool-grey: #333460;
-    --mint-green: #1ed2bb;
-    --yellow: #e7e65f;
+    /* Background colour for light surfaces */
+    --light-grey: #f7f9f8;
+    /* Primary text and interactive elements */
+    --cool-grey: #333460;
+    /* Accent colour for highlights and CTAs */
+    --mint-green: #1ed2bb;
+    /* Warning and notification states */
+    --yellow: #e7e65f;
common/common.go (2)

19-21: Consider a more robust secret initialisation approach.

The current implementation has several potential issues:

  1. Secret regenerates on every process restart, which might break existing sessions
  2. No visible error handling from GenerateSharedSecret
  3. Init functions can make testing more challenging

Consider implementing a more robust secret management system:

  1. Load from secure environment variables or a secret manager
  2. Implement proper error handling
  3. Add logging for secret rotation events
  4. Consider using a dedicated initialisation function called from main

Would you like me to provide a detailed implementation example?


SharedSecret implementation follows secure practices but needs minor improvements

The verification reveals a generally secure implementation with a few areas for enhancement:

  • The secret generation uses cryptographically secure random numbers (crypto/rand) and appropriate key length (256-bit)
  • Signature validation employs constant-time comparison via hmac.Equal
  • However, there are two areas that need attention:
    • Error handling in IsValidSignature silently ignores hex decoding errors with _
    • The secret generation failure is handled with log.Fatalf, which could expose the secret value in logs

Recommendations:

  • Add proper error handling in IsValidSignature to return false on invalid hex input
  • Replace log.Fatalf with a more secure error handling that doesn't risk exposing the secret
🔗 Analysis chain

Line range hint 9-21: Verify the usage and security of SharedSecret across the codebase.

Let's analyse how this secret is used and ensure proper security practices.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Analyse SharedSecret usage and security implications

# Check for direct SharedSecret references
echo "Checking for SharedSecret usage:"
rg "SharedSecret" --type go -C 3

# Check for potential security risks
echo -e "\nChecking for potential logging of the secret:"
rg "log|fmt.Print|println" --type go -C 3 | rg -i "secret"

# Check for proper error handling around secret usage
echo -e "\nChecking error handling patterns:"
ast-grep --pattern 'if err := $$$; err != nil { $$$ }' --type go

Length of output: 2430


Script:

#!/bin/bash
# Let's verify the security aspects more thoroughly

# Check the implementation of GenerateSharedSecret and related functions
echo "Checking secret generation and signature calculation:"
rg -t go "func.*Shared.*|func.*Secret.*|func.*Signature.*" -C 5

# Check for any potential exposure of the secret in responses or logs
echo -e "\nChecking for potential secret exposure:"
rg -t go "json:|fmt\.|log\." -C 3 | rg -i "secret|signature"

# Check webhook signature validation implementation
echo -e "\nChecking webhook signature validation:"
ast-grep --pattern 'func IsValidSignature($_, $_) bool {
  $$$
}'

Length of output: 3877

immich/immich_faces.go (1)

Line range hint 28-33: Consider enhancing error logging for better debugging

The current error logging could be more specific to help identify the source of failures. Consider adding more context to the error messages and utilising structured logging fields effectively.

Here's a suggested improvement:

 	body, err := immichApiCall("GET", apiUrl.String(), nil)
 	if err != nil {
 		_, err = immichApiFail(faces, err, body, apiUrl.String())
-		log.Error("adding faces", "err", err)
+		log.Error("failed to fetch faces from API", 
+			"err", err,
+			"asset_id", i.ID,
+			"endpoint", apiUrl.String())
 		return
 	}

 	err = json.Unmarshal(body, &faces)
 	if err != nil {
 		_, err = immichApiFail(faces, err, body, apiUrl.String())
-		log.Error("adding faces", "err", err)
+		log.Error("failed to unmarshal faces response",
+			"err", err,
+			"asset_id", i.ID,
+			"response_size", len(body))
 		return
 	}

Also applies to: 35-40

frontend/src/ts/kiosk.ts (2)

160-181: Consider extracting the KeyI handler logic

The KeyI case handling is quite complex. Consider extracting it into a separate function for better readability and maintainability.

+ function handleInfoKeyPress(): void {
+   const isPollingPaused = document.body.classList.contains("polling-paused");
+   const hasMoreInfo = document.body.classList.contains("more-info");
+
+   if (isPollingPaused && hasMoreInfo) {
+     togglePolling();
+     toggleImageOverlay();
+   } else {
+     if (!isPollingPaused) {
+       togglePolling();
+     }
+     toggleImageOverlay();
+   }
+ }

  switch (e.code) {
    case "Space":
      e.preventDefault();
      togglePolling(true);
      break;
    case "KeyI": {
      e.preventDefault();
-     const isPollingPaused = document.body.classList.contains("polling-paused");
-     const hasMoreInfo = document.body.classList.contains("more-info");
-
-     if (isPollingPaused && hasMoreInfo) {
-       togglePolling();
-       toggleImageOverlay();
-     } else {
-       if (!isPollingPaused) {
-         togglePolling();
-       }
-       toggleImageOverlay();
-     }
+     handleInfoKeyPress();
      break;
    }
  }

189-191: Maintain consistency in DOM element selection

For consistency with other DOM element selections in this file, consider using htmx.find() instead of querySelector.

- document
-   .querySelector(".navigation--more-info")
-   ?.addEventListener("click", () => toggleImageOverlay());
+ htmx
+   .find(".navigation--more-info")
+   ?.addEventListener("click", () => toggleImageOverlay());
views/views_image.templ (1)

48-50: Add documentation for the webhookSignature function

Consider adding documentation to explain:

  • The purpose of the function
  • The format of the signature
  • The security implications
+// webhookSignature generates a signature for webhook authentication.
+// It combines the shared secret with the current Unix timestamp
+// to create a time-based signature for securing webhook requests.
+//
+// Returns:
+//   - A string containing the calculated signature
 func webhookSignature() string {
     return utils.CalculateSignature(common.SharedSecret, strconv.FormatInt(time.Now().Unix(), 10))
 }
utils/utils.go (3)

46-50: Enhance type documentation with usage examples

The WeightedAsset and AssetWithWeighting types would benefit from more detailed documentation explaining their purpose and providing usage examples.

Add documentation like this:

-// WeightedAsset represents an asset with a type and ID
+// WeightedAsset represents an asset with a type and ID.
+// It is used in weighted random selection algorithms.
+//
+// Example:
+//   asset := WeightedAsset{
+//     Type: "image",
+//     ID:   "123",
+//   }
 type WeightedAsset struct {
     Type string
     ID   string
 }

-// AssetWithWeighting represents a WeightedAsset with an associated weight value
+// AssetWithWeighting represents a WeightedAsset with an associated weight value.
+// The weight value influences the probability of the asset being selected.
+//
+// Example:
+//   weighted := AssetWithWeighting{
+//     Asset:  WeightedAsset{Type: "image", ID: "123"},
+//     Weight: 10,
+//   }
 type AssetWithWeighting struct {
     Asset  WeightedAsset
     Weight int
 }

Also applies to: 51-55


Line range hint 339-396: Add validation for empty or whitespace-only input

The parseTimeString function should validate for empty or whitespace-only input before processing.

Consider this improvement:

 func parseTimeString(timeStr string) (time.Time, error) {
+    // Trim whitespace and validate
+    timeStr = strings.TrimSpace(timeStr)
+    if timeStr == "" {
+        return time.Time{}, fmt.Errorf("invalid time format: empty or whitespace-only input")
+    }
+
     // Extract only the digits
     digits := regexp.MustCompile(`\d`).FindAllString(timeStr, -1)

433-436: Enhance FileExists with additional checks

The FileExists function could be more robust by checking if the path is a directory and handling symlinks.

Consider this enhancement:

 func FileExists(filename string) bool {
-    _, err := os.Stat(filename)
-    return !os.IsNotExist(err)
+    info, err := os.Stat(filename)
+    if err != nil {
+        return false
+    }
+    return !info.IsDir()
 }
routes/routes_webhooks.go (3)

80-80: Use consistent variable naming conventions

The variable ViewData should start with a lowercase letter to follow Go's naming conventions for local variables.

Apply this change:

-	ViewData := views.ViewData{
+	viewData := views.ViewData{

And update all references to ViewData accordingly.


109-109: Consider handling errors from webhooks.Trigger

Launching webhooks.Trigger in a background goroutine without handling potential errors or applying context cancellation may lead to unexpected behaviour.

Consider modifying the code to handle errors and context:

-	go webhooks.Trigger(requestData, KioskVersion, webhooks.UserWebhookTriggerInfoOverlay, ViewData)
+	go func() {
+		if err := webhooks.Trigger(requestData, KioskVersion, webhooks.UserWebhookTriggerInfoOverlay, viewData); err != nil {
+			log.Error("Failed to trigger webhook", "error", err)
+		}
+	}()

73-73: Include requestID in error logs for better traceability

Including requestID in error logs can improve debugging and traceability of issues.

Apply this change:

-				log.Error("webhook request missing history")
+				log.Error(requestID, "message", "webhook request missing history")
frontend/public/assets/css/kiosk.css (2)

1307-1311: Verify colour contrast for hover states

When hovering over .navigation--item, the background changes to var(--mint-green) and the SVG fill changes to var(--cool-grey). Please confirm that the contrast between the icon and background meets accessibility standards to maintain readability.


1345-1348: Ensure icon size is adequate for usability

The SVG icons for .navigation--more-info are set to a size of 1.5rem. Please check that this size is sufficient for users to easily interact with, especially on devices with higher resolutions or for users with visual impairments.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between be96fc4 and 2652519.

📒 Files selected for processing (13)
  • .coderabbitignore (0 hunks)
  • common/common.go (2 hunks)
  • frontend/public/assets/css/kiosk.css (9 hunks)
  • frontend/src/css/vars.css (1 hunks)
  • frontend/src/ts/kiosk.ts (2 hunks)
  • immich/immich.go (1 hunks)
  • immich/immich_faces.go (1 hunks)
  • immich/immich_helpers.go (4 hunks)
  • main.go (2 hunks)
  • routes/routes_webhooks.go (1 hunks)
  • utils/utils.go (7 hunks)
  • views/views_image.templ (2 hunks)
  • views/views_image_templ.go (18 hunks)
💤 Files with no reviewable changes (1)
  • .coderabbitignore
🚧 Files skipped from review as they are similar to previous changes (2)
  • immich/immich.go
  • immich/immich_helpers.go
🔇 Additional comments (15)
common/common.go (1)

4-7: LGTM! Import changes are appropriate.

The addition of the utils package import is necessary for accessing the GenerateSharedSecret function.

immich/immich_faces.go (1)

22-22: LGTM: API endpoint path update is consistent

The removal of the trailing slash aligns with modern API practices and maintains consistency with other endpoint changes in the codebase.

Let's verify the consistency of API endpoint paths across the codebase:

main.go (1)

28-28: ⚠️ Potential issue

Critical: Enhance webhook endpoint security

Whilst the addition of rate limiting is a positive step, the webhook endpoint requires additional security measures:

  1. The current rate limit of 20 requests/second appears excessive for a kiosk application. Consider reducing this to a more conservative value, such as 1-2 requests/second.

  2. Several critical security measures are missing:

    • CORS protection
    • IP allowlisting for trusted sources
    • Request signature validation
    • Request body size limits

Consider implementing these security enhancements:

 // Middleware
 e.Use(middleware.Recover())
 e.Use(middleware.RequestID())
+e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
+    AllowOrigins: []string{"trusted-origin.com"},
+    AllowMethods: []string{http.MethodPost},
+}))
+
+// IP allowlist middleware
+e.Use(middleware.IPExtractor(func(c echo.Context) string {
+    return c.RealIP()
+}))
+e.Use(middleware.IPFilter(middleware.IPFilterConfig{
+    Skipper: middleware.DefaultSkipper,
+    Allow:   []string{"127.0.0.1/32", "trusted-ip-range"},
+}))
+
+// Request body size limit
+e.Use(middleware.BodyLimit("10K"))

 // ... existing middleware ...

-e.POST("/webhooks", routes.Webhooks(baseConfig), middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(rate.Limit(20))))
+e.POST("/webhooks", routes.Webhooks(baseConfig),
+    middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(rate.Limit(2))),
+    validateWebhookSignature(baseConfig),
+)

Let's verify the current security measures:

Also applies to: 129-130

frontend/src/ts/kiosk.ts (2)

18-18: LGTM: Clean import addition

The new import is properly organised with related menu functionality imports.


155-156: LGTM: Event listener implementation fixed

The event listeners now properly invoke the togglePolling function, addressing the previous issue where the function reference wasn't being executed.

views/views_image.templ (4)

28-28: LGTM: Proper placement of the more info component

The addition of renderMoreInfo follows the existing pattern and is logically placed after the history component.


81-83: Improve link accessibility

The current link text "The link" is not descriptive enough for screen readers.


98-100: Add alt text and error handling for QR code

The QR code image lacks alt text and error handling for the QR code generation.


86-96: Review webhook trigger security implementation

The webhook trigger implementation requires security review:

  1. Consider rate limiting beyond throttling
  2. Verify the timestamp validation on the server side
  3. Add loading state to prevent double submissions
✅ Verification successful

Let me check the webhook implementation further to verify the security concerns.


Webhook security implementation is adequate

The implementation has proper security measures in place:

  • Rate limiting is implemented using Echo's middleware with a limit of 20 requests
  • Webhook signatures are generated using a shared secret
  • Request throttling is implemented on the client side (2s)

The current implementation provides sufficient protection against abuse through:

  • Server-side rate limiting
  • Signature verification
  • Client-side throttling
  • Request ID tracking for audit purposes
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check webhook implementation security

# Check for timestamp validation in webhook handlers
rg -A 5 "X-Timestamp" --type go

# Check for rate limiting implementation
rg -A 5 "throttle|rate.?limit" --type go

Length of output: 12021


Script:

#!/bin/bash
# Check webhook handler implementation for security measures
rg -A 10 "func.*webhook" --type go

# Check for rate limiting middleware or similar security measures
rg -A 10 "middleware|limiter" --type go

Length of output: 2805

utils/utils.go (1)

439-465: LGTM! Well-implemented QR code generation

The function has proper input validation, error handling, and uses an appropriate QR code size.

routes/routes_webhooks.go (1)

93-95: Handle errors returned by image.AssetInfo

The call to image.AssetInfo(requestID) may return an error, which is not currently being checked or handled.

frontend/public/assets/css/kiosk.css (4)

375-377: Verify readability with reduced opacity

Reducing the opacity of .image--metadata to 0.2 may make the text difficult to read. Please ensure that the metadata remains legible to maintain good user experience and accessibility.


568-593: Duplicate display: flex declarations and background colour contrast issues remain

The previously mentioned issues regarding duplicate display: flex declarations and the potential low contrast of the background colour rgb(51 52 96 / 60%) are still present in this code segment. Please refer to the earlier review comment for details.


757-759: Ensure clock and weather information remain legible at reduced opacity

Setting the opacity of #clock-weather-container to 0.2 might result in the clock and weather elements being hard to read. Verify that these elements remain clear and accessible to users under this styling.


1256-1256: Check the effect of z-index: 99997 on stacking order

Adding a high z-index to #navigation-interaction-area could affect the stacking order of overlapping elements. Ensure that it does not unintentionally overlay other important UI components.

frontend/src/css/vars.css Show resolved Hide resolved
"github.com/damongolding/immich-kiosk/utils"
)

var SharedSecret string
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add documentation for the exported SharedSecret variable.

As per Go conventions, exported variables should be documented. Additionally, consider whether this secret truly needs to be globally accessible.

Add documentation and consider encapsulation:

+// SharedSecret is a cryptographic secret used for secure communications.
+// Warning: This is a global mutable state. Access should be controlled carefully.
 var SharedSecret string

Consider wrapping this in a thread-safe accessor pattern:

type secretManager struct {
    secret string
    mu     sync.RWMutex
}

func (sm *secretManager) GetSecret() string {
    sm.mu.RLock()
    defer sm.mu.RUnlock()
    return sm.secret
}

Comment on lines +31 to +46
func immichImageUrl(baseUrl, imageID string) string {

u, err := url.Parse(baseUrl)
if err != nil {
return "#"
}

apiUrl := url.URL{
Scheme: u.Scheme,
Host: u.Host,
Path: path.Join("photos", imageID),
}

return apiUrl.String()

}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance error handling in immichImageUrl function

The current implementation silently fails by returning "#" when URL parsing fails. Consider:

  1. Validating the input parameters
  2. Logging errors for debugging
  3. Using a more meaningful fallback URL
 func immichImageUrl(baseUrl, imageID string) string {
+    if baseUrl == "" || imageID == "" {
+        log.Printf("Invalid parameters: baseUrl=%q, imageID=%q", baseUrl, imageID)
+        return "/static/error.jpg"
+    }
 
     u, err := url.Parse(baseUrl)
     if err != nil {
-        return "#"
+        log.Printf("Failed to parse base URL %q: %v", baseUrl, err)
+        return "/static/error.jpg"
     }
 
     apiUrl := url.URL{
         Scheme: u.Scheme,
         Host:   u.Host,
         Path:   path.Join("photos", imageID),
     }
 
     return apiUrl.String()
 }

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

utils/utils.go Outdated
Comment on lines 467 to 475
// generateSharedSecret generates a random 256-bit (32-byte) secret.
func GenerateSharedSecret() string {
secret := make([]byte, 32)
_, err := crand.Read(secret)
if err != nil {
log.Fatalf("Failed to generate secret: %v", err)
}
return hex.EncodeToString(secret)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Improve error handling in GenerateSharedSecret

Using log.Fatalf in a library function is problematic as it forces the entire application to terminate. Instead, return the error to allow the caller to handle it appropriately.

Apply this fix:

-func GenerateSharedSecret() string {
+func GenerateSharedSecret() (string, error) {
     secret := make([]byte, 32)
     _, err := crand.Read(secret)
     if err != nil {
-        log.Fatalf("Failed to generate secret: %v", err)
+        return "", fmt.Errorf("failed to generate secret: %w", err)
     }
-    return hex.EncodeToString(secret)
+    return hex.EncodeToString(secret), nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// generateSharedSecret generates a random 256-bit (32-byte) secret.
func GenerateSharedSecret() string {
secret := make([]byte, 32)
_, err := crand.Read(secret)
if err != nil {
log.Fatalf("Failed to generate secret: %v", err)
}
return hex.EncodeToString(secret)
}
// generateSharedSecret generates a random 256-bit (32-byte) secret.
func GenerateSharedSecret() (string, error) {
secret := make([]byte, 32)
_, err := crand.Read(secret)
if err != nil {
return "", fmt.Errorf("failed to generate secret: %w", err)
}
return hex.EncodeToString(secret), nil
}

Comment on lines 90 to 92
func webhookSignature() string {
return utils.CalculateSignature(common.SharedSecret, strconv.FormatInt(time.Now().Unix(), 10))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enhance webhook security measures

The webhook implementation requires additional security controls:

  1. The signature generation should include more entropy than just the timestamp
  2. The webhook endpoint needs rate limiting
  3. The included data from .kiosk-history--entry should be validated
  4. CSRF protection should be implemented

Apply this diff to improve signature generation:

 func webhookSignature() string {
-    return utils.CalculateSignature(common.SharedSecret, strconv.FormatInt(time.Now().Unix(), 10))
+    nonce := utils.GenerateRandomString(16)
+    timestamp := strconv.FormatInt(time.Now().Unix(), 10)
+    return utils.CalculateSignature(common.SharedSecret, timestamp + "." + nonce)
 }

Additionally:

  1. Implement rate limiting middleware for the webhook endpoint
  2. Add request validation for the included data
  3. Add CSRF protection using a middleware like gorilla/csrf

Also applies to: 155-160

Comment on lines 73 to 88
func immichImageUrl(baseUrl, imageID string) string {

u, err := url.Parse(baseUrl)
if err != nil {
return "#"
}

apiUrl := url.URL{
Scheme: u.Scheme,
Host: u.Host,
Path: path.Join("photos", imageID),
}

return apiUrl.String()

}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add URL encoding for the imageID parameter

The imageID parameter should be URL-encoded to safely handle special characters in the ID.

Apply this diff to add URL encoding:

 func immichImageUrl(baseUrl, imageID string) string {
     u, err := url.Parse(baseUrl)
     if err != nil {
         return "#"
     }
+    encodedID := url.PathEscape(imageID)
     apiUrl := url.URL{
         Scheme: u.Scheme,
         Host:   u.Host,
-        Path:   path.Join("photos", imageID),
+        Path:   path.Join("photos", encodedID),
     }
     return apiUrl.String()
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func immichImageUrl(baseUrl, imageID string) string {
u, err := url.Parse(baseUrl)
if err != nil {
return "#"
}
apiUrl := url.URL{
Scheme: u.Scheme,
Host: u.Host,
Path: path.Join("photos", imageID),
}
return apiUrl.String()
}
func immichImageUrl(baseUrl, imageID string) string {
u, err := url.Parse(baseUrl)
if err != nil {
return "#"
}
encodedID := url.PathEscape(imageID)
apiUrl := url.URL{
Scheme: u.Scheme,
Host: u.Host,
Path: path.Join("photos", encodedID),
}
return apiUrl.String()
}

Comment on lines 172 to 174
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(utils.CreateQrCode(immichImageUrl(viewData.ImmichUrl, img.ImmichImage.ID)))
if templ_7745c5c3_Err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for QR code generation

The utils.CreateQrCode function may return an error that's currently not being handled.

Apply this diff to add error handling:

-var templ_7745c5c3_Var7 string
-templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(utils.CreateQrCode(immichImageUrl(viewData.ImmichUrl, img.ImmichImage.ID)))
+qrCode, err := utils.CreateQrCode(immichImageUrl(viewData.ImmichUrl, img.ImmichImage.ID))
+if err != nil {
+    return templ.Error{Err: err, FileName: `views/views_image.templ`, Line: 173, Col: 84}
+}
+templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(qrCode)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(utils.CreateQrCode(immichImageUrl(viewData.ImmichUrl, img.ImmichImage.ID)))
if templ_7745c5c3_Err != nil {
qrCode, err := utils.CreateQrCode(immichImageUrl(viewData.ImmichUrl, img.ImmichImage.ID))
if err != nil {
return templ.Error{Err: err, FileName: `views/views_image.templ`, Line: 173, Col: 84}
}
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(qrCode)
if templ_7745c5c3_Err != nil {

routes/routes_webhooks.go Show resolved Hide resolved
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

🧹 Outside diff range and nitpick comments (5)
frontend/src/ts/kiosk.ts (1)

148-167: Consider refactoring for better readability and efficiency

The function logic can be simplified using early returns and consolidated state changes.

Consider this refactoring:

 function handleInfoKeyPress(): void {
   const isPollingPaused = document.body.classList.contains("polling-paused");
   const hasMoreInfo = document.body.classList.contains("more-info");

-  if (isPollingPaused && hasMoreInfo) {
-    togglePolling();
-    toggleImageOverlay();
-  } else {
-    if (!isPollingPaused) {
-      togglePolling();
-    }
-    toggleImageOverlay();
-  }
+  // If showing more info, hide it and resume polling
+  if (isPollingPaused && hasMoreInfo) {
+    togglePolling();
+    toggleImageOverlay();
+    return;
+  }
+
+  // Ensure polling is paused before showing more info
+  if (!isPollingPaused) {
+    togglePolling();
+  }
+  toggleImageOverlay();
 }
views/views_image.templ (1)

54-56: Consider using millisecond precision for webhook timestamp

The current implementation uses Unix seconds. For better precision in webhook signature verification, consider using milliseconds.

 func webhookSignature() string {
-    return utils.CalculateSignature(common.SharedSecret, strconv.FormatInt(time.Now().Unix(), 10))
+    return utils.CalculateSignature(common.SharedSecret, strconv.FormatInt(time.Now().UnixMilli(), 10))
 }
utils/utils.go (3)

46-55: Enhance type documentation with usage examples

The WeightedAsset and AssetWithWeighting types would benefit from more detailed documentation, including usage examples and field descriptions.

Add comprehensive documentation like this:

-// WeightedAsset represents an asset with a type and ID
+// WeightedAsset represents an asset with a type identifier and unique ID.
+// It is used in weighted random selection algorithms where different types
+// of assets need to be selected with varying probabilities.
+//
+// Example usage:
+//   asset := WeightedAsset{
+//     Type: "image",
+//     ID:   "abc123",
+//   }
 type WeightedAsset struct {
     Type string
     ID   string
 }

Line range hint 80-92: Add input validation and error handling

The function should validate input and handle edge cases gracefully.

Consider this improved implementation:

-func DateToJavascriptLayout(input string) string {
+func DateToJavascriptLayout(input string) (string, error) {
+    if input == "" {
+        return "", fmt.Errorf("empty input string")
+    }
+
     replacer := strings.NewReplacer(
         "YYYY", "yyyy",
         "YY", "yy",
         "DDDD", "EEEE",
         "DDD", "EEE",
         "DD", "dd",
         "D", "d",
     )
-    return replacer.Replace(input)
+    result := replacer.Replace(input)
+    if result == input {
+        return "", fmt.Errorf("no valid date format tokens found in input")
+    }
+    return result, nil
}

440-445: Consider additional error cases

The function could be more robust by distinguishing between different types of errors.

Consider this enhanced implementation:

-func FileExists(filename string) bool {
+func FileExists(filename string) (bool, error) {
+    if filename == "" {
+        return false, fmt.Errorf("empty filename")
+    }
     info, err := os.Stat(filename)
-    return !os.IsNotExist(err)
+    if err != nil {
+        if os.IsNotExist(err) {
+            return false, nil
+        }
+        return false, fmt.Errorf("error checking file: %w", err)
+    }
+    return !info.IsDir(), nil
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2652519 and c8f8ca6.

📒 Files selected for processing (6)
  • common/common.go (2 hunks)
  • frontend/src/ts/kiosk.ts (4 hunks)
  • routes/routes_webhooks.go (1 hunks)
  • utils/utils.go (7 hunks)
  • views/views_image.templ (2 hunks)
  • views/views_image_templ.go (18 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • routes/routes_webhooks.go
🧰 Additional context used
📓 Path-based instructions (1)
views/views_image_templ.go (1)

Pattern views/*_templ.go: ignore these generated templ files

🔇 Additional comments (11)
common/common.go (2)

10-10: Previous review comment about documenting SharedSecret still applies


4-8: Verify the security of secret generation

Let's verify the implementation of GenerateSharedSecret to ensure it uses cryptographically secure random number generation.

Also applies to: 20-26

✅ Verification successful

Secret generation implementation is cryptographically secure

The implementation of GenerateSharedSecret in utils/utils.go uses crypto/rand package and Read function to generate random bytes, which is the recommended approach for cryptographically secure random number generation in Go. The function:

  • Allocates 32 bytes of memory
  • Uses crypto/rand.Read to fill it with cryptographically secure random data
  • Properly handles errors
  • Returns the hex-encoded string representation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the implementation of GenerateSharedSecret

# Look for the implementation
ast-grep --pattern 'func GenerateSharedSecret() (string, error) {
  $$$
}'

# Check for secure random number generation usage
rg -A 5 'crypto/rand|rand\.Read'

Length of output: 917

frontend/src/ts/kiosk.ts (2)

18-18: LGTM: Import and DOM element setup look good!

The toggleImageOverlay import and moreInfoButton constant follow the established patterns in the codebase.

Also applies to: 80-82


200-201: LGTM: More info button handler is properly implemented

The click event listener follows the established patterns in the codebase.

views/views_image.templ (1)

31-46: ⚠️ Potential issue

Enhance error handling and input validation

The current implementation has several potential issues:

  1. No validation of input parameters
  2. Silent failure with an invalid fallback URL
  3. No error logging for debugging

Apply this improvement:

-func immichImageUrl(baseUrl, imageID string) string {
+func immichImageUrl(baseUrl, imageID string) string {
+    if baseUrl == "" || imageID == "" {
+        log.Printf("immichImageUrl: Invalid parameters - baseUrl: %q, imageID: %q", baseUrl, imageID)
+        return "/static/placeholder-image.jpg"
+    }
+
     u, err := url.Parse(baseUrl)
     if err != nil {
-        return "#"
+        log.Printf("immichImageUrl: Failed to parse base URL %q: %v", baseUrl, err)
+        return "/static/placeholder-image.jpg"
     }

     apiUrl := url.URL{
         Scheme: u.Scheme,
         Host:   u.Host,
         Path:   path.Join("photos", imageID),
     }

     return apiUrl.String()
 }

Likely invalid or redundant comment.

utils/utils.go (3)

339-347: LGTM! Well-structured error handling

The input validation and error handling are thorough and well-implemented.


446-472: LGTM! Well-implemented QR code generation

The implementation follows best practices with proper input validation, error handling, and optimal QR code size.


498-506: Consider timezone handling in timestamp validation

The timestamp validation should consider timezone differences.

Let's verify the timestamp handling:

Consider this improvement:

 func IsValidTimestamp(receivedTimestamp string, toleranceSeconds int) bool {
     ts, err := strconv.ParseInt(receivedTimestamp, 10, 64)
     if err != nil {
         return false
     }
-    currentTime := time.Now().Unix()
+    currentTime := time.Now().UTC().Unix()
     return abs(currentTime-ts) <= int64(toleranceSeconds)
 }
views/views_image_templ.go (3)

16-20: Imports look good!

The new imports are appropriate for the added URL construction and webhook functionality.


65-68: LGTM: Clean integration of the new renderMoreInfo component

The addition follows the established pattern of component rendering in the file.


220-222: Good improvement: More descriptive variable names

The variable renaming enhances code readability while maintaining functionality.

Also applies to: 253-255, 288-290

common/common.go Outdated Show resolved Hide resolved
frontend/src/ts/kiosk.ts Show resolved Hide resolved
Comment on lines 87 to 89
<a href={ templ.SafeURL(immichImageUrl(viewData.ImmichUrl, img.ImmichImage.ID)) } target="_blank">
The link
</a>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use descriptive link text for better accessibility

The current generic link text "The link" doesn't provide context about its purpose.

 <a href={ templ.SafeURL(immichImageUrl(viewData.ImmichUrl, img.ImmichImage.ID)) } target="_blank">
-    The link
+    View original image
 </a>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a href={ templ.SafeURL(immichImageUrl(viewData.ImmichUrl, img.ImmichImage.ID)) } target="_blank">
The link
</a>
<a href={ templ.SafeURL(immichImageUrl(viewData.ImmichUrl, img.ImmichImage.ID)) } target="_blank">
View original image
</a>

views/views_image.templ Show resolved Hide resolved
Comment on lines 92 to 102
<button
class="more-info--webhook"
hx-post="/webhooks"
hx-trigger="click throttle:2s"
hx-include=".kiosk-history--entry"
hx-headers={ fmt.Sprintf(`{"X-Timestamp": "%d", "X-Signature": "%s", "kiosk-webhook-event": "user.webhook.trigger.info_overlay"}`, time.Now().Unix(), webhookSignature()) }
hx-swap="textContent"
>
Trigger webhook
</button>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance webhook button UX and reliability

The current implementation could benefit from several improvements:

  1. The throttle time of 2s might be too short for webhook processing
  2. Missing loading state during webhook execution
  3. No feedback on success/failure
 <button
     class="more-info--webhook"
     hx-post="/webhooks"
-    hx-trigger="click throttle:2s"
+    hx-trigger="click throttle:5s"
     hx-include=".kiosk-history--entry"
     hx-headers={ fmt.Sprintf(`{"X-Timestamp": "%d", "X-Signature": "%s", "kiosk-webhook-event": "user.webhook.trigger.info_overlay"}`, time.Now().Unix(), webhookSignature()) }
     hx-swap="textContent"
+    hx-indicator="#webhook-spinner"
 >
     Trigger webhook
+    <span id="webhook-spinner" class="htmx-indicator">
+        Processing...
+    </span>
 </button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button
class="more-info--webhook"
hx-post="/webhooks"
hx-trigger="click throttle:2s"
hx-include=".kiosk-history--entry"
hx-headers={ fmt.Sprintf(`{"X-Timestamp": "%d", "X-Signature": "%s", "kiosk-webhook-event": "user.webhook.trigger.info_overlay"}`, time.Now().Unix(), webhookSignature()) }
hx-swap="textContent"
>
Trigger webhook
</button>
</div>
<button
class="more-info--webhook"
hx-post="/webhooks"
hx-trigger="click throttle:5s"
hx-include=".kiosk-history--entry"
hx-headers={ fmt.Sprintf(`{"X-Timestamp": "%d", "X-Signature": "%s", "kiosk-webhook-event": "user.webhook.trigger.info_overlay"}`, time.Now().Unix(), webhookSignature()) }
hx-swap="textContent"
hx-indicator="#webhook-spinner"
>
Trigger webhook
<span id="webhook-spinner" class="htmx-indicator">
Processing...
</span>
</button>
</div>

utils/utils.go Show resolved Hide resolved
views/views_image_templ.go Outdated Show resolved Hide resolved
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: 5

🧹 Outside diff range and nitpick comments (3)
frontend/src/css/image-more-info.css (2)

1-6: Consider using a class selector instead of ID

Using ID selectors (#more-info) creates tight coupling and makes the styles harder to override. Consider using a class-based approach for better maintainability.

-#more-info {
+.more-info {
    display: none;
    * {
        user-select: text;
    }
}

8-65: Consider improvements to overlay implementation

A few suggestions to enhance the implementation:

  1. The z-index value (99998) seems arbitrarily high. Consider using a lower value or CSS custom properties for z-index management.
  2. The RGB colour with opacity could use modern CSS colour syntax.
  3. Consider extracting magic numbers (padding values) into CSS custom properties.
.polling-paused.more-info {
    .frame--image img {
-        filter: grayscale(1) blur(4px) brightness(0.4);
+        filter: grayscale(100%) blur(4px) brightness(0.4);
    }

    #more-info {
        /* ... */
-        z-index: 99998;
+        z-index: var(--z-overlay, 100);

        .more-info--image {
-            background-color: rgb(51 52 96 / 60%);
+            background-color: oklch(30% 0.1 270 / 0.6);
            
-            padding: 6rem 3rem 3rem 3rem;
+            padding: var(--spacing-xl) var(--spacing-lg) var(--spacing-lg) var(--spacing-lg);
views/views_image.templ (1)

51-59: Consider adding error handling for edge cases

The webhook signature generation should handle cases where SharedSecret is empty or invalid.

 func webhookSignature() string {
+    if common.SharedSecret == "" {
+        log.Printf("Warning: SharedSecret is empty")
+        return ""
+    }
     return utils.CalculateSignature(common.SharedSecret, strconv.FormatInt(time.Now().Unix(), 10))
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5de4ab6 and 47d8c27.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (8)
  • custom.example.css (5 hunks)
  • frontend/public/assets/css/kiosk.css (9 hunks)
  • frontend/src/css/image-more-info.css (1 hunks)
  • go.mod (1 hunks)
  • immich/immich.go (3 hunks)
  • immich/immich_helpers.go (4 hunks)
  • views/views_image.templ (2 hunks)
  • views/views_image_templ.go (18 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • go.mod
  • immich/immich.go
  • immich/immich_helpers.go
🧰 Additional context used
📓 Path-based instructions (2)
custom.example.css (1)

Pattern custom.example.css: ignore this file

views/views_image_templ.go (1)

Pattern views/*_templ.go: ignore these generated templ files

🪛 Biome (1.9.4)
custom.example.css

[error] 43-43: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 77-77: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 78-78: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 79-79: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 96-96: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 156-156: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 165-165: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

🔇 Additional comments (11)
frontend/src/css/image-more-info.css (1)

78-83: LGTM! Clean implementation of button group styles

The flex container implementation for button grouping is well-structured and follows best practices.

custom.example.css (1)

Line range hint 1-999: Skipping review of this file

This file matches the ignore pattern custom.example.css specified in the coding guidelines. Additionally, the file owner has explicitly requested to add this file to the ignore list in past review comments.

🧰 Tools
🪛 Biome (1.9.4)

[error] 62-62: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 63-63: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 64-64: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 77-77: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 78-78: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 79-79: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 81-81: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 82-82: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

views/views_image.templ (3)

4-15: LGTM: Clean integration of new imports and template modification

The new imports are properly organised and the renderMoreInfo integration follows the existing template pattern.

Also applies to: 31-32


34-49: Previous review comments about error handling remain valid


89-136: Improve heading hierarchy in more info section

The camera make and model information uses h3 headings at the same level as the filename, which might not represent the correct content hierarchy.

-                            <h3>
+                            <h4>
                                 { img.ImmichImage.ExifInfo.Make }
-                            </h3>
+                            </h4>
frontend/public/assets/css/kiosk.css (3)

3-5: LGTM: Well-structured colour variables

The colour variables are semantically named and follow consistent conventions.


375-377: LGTM: Appropriate visual hierarchy

Reducing metadata opacity when showing more info helps direct user attention to the overlay content.


1270-1270: LGTM: Consistent navigation styling

The navigation updates maintain visual consistency while improving interactive feedback through hover states and appropriate icon sizing.

Also applies to: 1287-1287, 1321-1325, 1337-1338, 1359-1362

views/views_image_templ.go (3)

76-91: Existing issue: URL encoding needed

This issue was previously identified. Please refer to the existing comment about adding URL encoding for the imageID parameter.


93-101: Existing issue: Enhance webhook security

This issue was previously identified. Please refer to the existing comment about improving the webhook signature generation with additional entropy.


131-286: Existing issue: Add error handling for QR code generation

This issue was previously identified. Please refer to the existing comment about adding error handling for the QR code generation.

frontend/src/css/image-more-info.css Outdated Show resolved Hide resolved
frontend/src/css/image-more-info.css Outdated Show resolved Hide resolved
views/views_image.templ Outdated Show resolved Hide resolved
frontend/public/assets/css/kiosk.css Outdated Show resolved Hide resolved
views/views_image_templ.go Outdated Show resolved Hide resolved
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

🧹 Outside diff range and nitpick comments (5)
frontend/src/css/image-more-info.css (2)

1-6: Good accessibility consideration with text selection enabled!

The base setup looks good. Consider adding aria-hidden="true" to the HTML element when it's not visible to improve screen reader compatibility.


8-65: Consider standardising units and reviewing z-index value

The styles are well-structured, but there are some consistency improvements to consider:

  1. Mixed usage of rem and px units (e.g., gap: 0.4rem vs padding: 6rem)
  2. Very high z-index (99998) might be unnecessary

Consider standardising to rem units and using a lower z-index value:

#more-info {
-   gap: 0.4rem;
-   padding: 0.4rem;
+   gap: 0.25rem;
+   padding: 0.25rem;
-   z-index: 99998;
+   z-index: 100;
}
views/views_image.templ (2)

51-59: Consider enhancing webhook security measures

The current implementation could benefit from additional security measures:

  1. Add signature expiry validation to prevent replay attacks
  2. Implement rate limiting for signature generation

Consider these enhancements:

 func webhookSignature() string {
+    // Add expiry time (e.g., 5 minutes from now)
+    expiryTime := time.Now().Add(5 * time.Minute).Unix()
+    payload := fmt.Sprintf("%d:%d", time.Now().Unix(), expiryTime)
-    return utils.CalculateSignature(common.SharedSecret, strconv.FormatInt(time.Now().Unix(), 10))
+    return utils.CalculateSignature(common.SharedSecret, payload)
 }

89-136: Consider breaking down the large template into smaller components

The current implementation could benefit from being split into smaller, reusable components:

  1. Camera information component
  2. File details component
  3. Actions component (link and webhook button)

Example refactor for the camera information section:

+templ renderCameraInfo(image immich.ImmichAsset) {
+    <div>
+        <div>
+            <h3>{ image.ExifInfo.Make }</h3>
+        </div>
+        <div>
+            { image.ExifInfo.Model }
+        </div>
+    </div>
+}

 templ renderMoreInfo(viewData ViewData) {
     <div id="more-info" hx-swap-oob="true">
         for _, img := range viewData.Images {
             <div class="more-info--image">
                 <div class="more-info--image--data">
-                    <div>
-                        <div>
-                            <h3>
-                                { img.ImmichImage.ExifInfo.Make }
-                            </h3>
-                        </div>
-                        <div>
-                            { img.ImmichImage.ExifInfo.Model }
-                        </div>
-                    </div>
+                    @renderCameraInfo(img.ImmichImage)
README.md (1)

684-689: Capitalise the 'I' key in keyboard shortcuts table for consistency

For consistency with other key names in the table (Spacebar, Right Arrow, Left Arrow), the 'i' key should be capitalised.

| Key           | Action                                                   |
|---------------|----------------------------------------------------------|
| _ Spacebar    | Play/Pause and Toggle Menu                               |
| → Right Arrow | Next Image(s)                                            |
| ← Left Arrow  | Previous Image(s)                                        |
-| i Key         | Play/Pause and Toggle Menu and display more info overlay |
+| I Key         | Play/Pause and Toggle Menu and display more info overlay |
🧰 Tools
🪛 LanguageTool

[uncategorized] ~689-~689: Did you mean “I”?
Context: ... | | i Key | Play/Pause and Toggle Men...

(I_LOWERCASE_PREMIUM)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 47d8c27 and 4d5cb2a.

📒 Files selected for processing (6)
  • README.md (2 hunks)
  • custom.example.css (5 hunks)
  • frontend/public/assets/css/kiosk.css (9 hunks)
  • frontend/src/css/image-more-info.css (1 hunks)
  • views/views_image.templ (2 hunks)
  • views/views_image_templ.go (18 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
custom.example.css (1)

Pattern custom.example.css: ignore this file

frontend/public/assets/css/kiosk.css (1)

Pattern frontend/public/**: exclude

views/views_image_templ.go (1)

Pattern views/*_templ.go: exclude

🪛 LanguageTool
README.md

[uncategorized] ~689-~689: Did you mean “I”?
Context: ... | | i Key | Play/Pause and Toggle Men...

(I_LOWERCASE_PREMIUM)

🪛 Biome (1.9.4)
custom.example.css

[error] 43-43: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 77-77: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 78-78: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 79-79: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 96-96: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 156-156: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 165-165: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

🔇 Additional comments (11)
frontend/src/css/image-more-info.css (1)

67-75: Clean landscape layout adaptation!

The landscape mode styles are well-implemented with appropriate flex direction changes.

custom.example.css (1)

Line range hint 1-165: Skipping review of this file

As per the coding guidelines, files matching the pattern custom.example.css should be ignored. Additionally, past review comments confirm this file should be added to the ignore list.

🧰 Tools
🪛 Biome (1.9.4)

[error] 62-62: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 63-63: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 64-64: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 77-77: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 78-78: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 79-79: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 81-81: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 82-82: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

views/views_image.templ (1)

61-87: Well-implemented with proper security measures

The function demonstrates good practices:

  • Proper XSS protection using templ.EscapeString
  • Appropriate handling of empty cases
  • Clean separation of concerns
frontend/public/assets/css/kiosk.css (5)

3-6: LGTM! Good use of CSS variables for theming.

The addition of color variables improves maintainability and consistency across the application.


375-377: LGTM! Consistent opacity handling.

The opacity reduction for image metadata when showing more info creates a clear visual hierarchy.


774-776: LGTM! Consistent opacity treatment.

The opacity reduction for the clock-weather container aligns with the overall overlay design pattern.


1273-1273: LGTM! Well-structured navigation styling.

The z-index changes ensure proper layering of UI elements, and the hover states provide good visual feedback. The icon sizing is consistent with the UI scale.

Also applies to: 1290-1290, 1324-1328, 1340-1341, 1362-1365


558-604: 🛠️ Refactor suggestion

Consider improving overlay contrast and removing duplicate flex declarations.

The semi-transparent background (rgb(51 52 96 / 60%)) might not provide sufficient contrast for text content. Additionally, there are duplicate flex declarations that can be simplified.

Apply this diff to improve accessibility and remove duplicates:

.polling-paused.more-info #more-info .more-info--image {
      width: 100%;
      height: 100%;
-     background-color: rgb(51 52 96 / 60%);
+     background-color: rgb(51 52 96 / 85%);
      display: -webkit-flex;
      display: -moz-box;
      display: flex;
      -webkit-flex-direction: column;
         -moz-box-orient: vertical;
         -moz-box-direction: normal;
              flex-direction: column;
      -webkit-justify-content: space-between;
         -moz-box-pack: justify;
              justify-content: space-between;
      gap: 2rem;
      padding: 6rem 3rem 3rem 3rem;
      color: #fff;
+     text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
      border-radius: 0.74rem;
      overflow: hidden;
    }

Likely invalid or redundant comment.

views/views_image_templ.go (2)

12-23: LGTM! Clean integration of new functionality.

The new imports are appropriate for the added features, and the integration of renderMoreInfo in the Image function follows the existing patterns.

Also applies to: 68-71


311-313: LGTM! Consistent variable naming improvements.

The variable naming changes for child components improve code readability while maintaining the existing patterns.

Also applies to: 344-346, 379-381, 475-477, 519-521, 572-574, 655-657, 702-704, 749-751, 796-798

README.md (1)

Line range hint 1-983: Documentation is comprehensive and well-structured

The README provides clear, detailed instructions and is well-organised with appropriate sections, examples, and visual aids. The installation steps, configuration options, and usage guidelines are thoroughly documented.

frontend/src/css/image-more-info.css Outdated Show resolved Hide resolved
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

🧹 Outside diff range and nitpick comments (1)
.github/workflows/go-test.yml (1)

25-26: Enhance error handling and caching

The template generation steps could benefit from improved error handling and caching.

+      - name: Cache templ binary
+        uses: actions/cache@v3
+        with:
+          path: ~/go/bin/templ
+          key: ${{ runner.os }}-templ-${{ hashFiles('go.sum') }}
+
       - name: Run tests
         env:
           CI: true
         run: |
-          go install github.com/a-h/templ/cmd/templ@latest
-          templ generate
+          if ! command -v templ &> /dev/null; then
+            echo "Installing templ..."
+            go install github.com/a-h/templ/cmd/[email protected]
+          fi
+          echo "Generating templates..."
+          templ generate || { echo "Template generation failed"; exit 1; }
           mkdir -p test-results
           go test -v ./... > test-results/test.log
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4d5cb2a and 57ba92a.

📒 Files selected for processing (10)
  • .github/workflows/go-test.yml (1 hunks)
  • .gitignore (1 hunks)
  • views/views_clock_templ.go (0 hunks)
  • views/views_error_templ.go (0 hunks)
  • views/views_home_templ.go (0 hunks)
  • views/views_image-frame_templ.go (0 hunks)
  • views/views_image-metadata_templ.go (0 hunks)
  • views/views_image_templ.go (0 hunks)
  • views/views_menu_templ.go (0 hunks)
  • views/views_weather_templ.go (0 hunks)
💤 Files with no reviewable changes (8)
  • views/views_clock_templ.go
  • views/views_error_templ.go
  • views/views_home_templ.go
  • views/views_image-frame_templ.go
  • views/views_image-metadata_templ.go
  • views/views_image_templ.go
  • views/views_menu_templ.go
  • views/views_weather_templ.go
✅ Files skipped from review due to trivial changes (1)
  • .gitignore

@@ -22,6 +22,8 @@ jobs:
env:
CI: true
run: |
go install github.com/a-h/templ/cmd/templ@latest
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider pinning the templ version for CI stability

Using @latest in CI environments can lead to non-deterministic builds if breaking changes are introduced. Consider pinning to a specific version.

-go install github.com/a-h/templ/cmd/templ@latest
+go install github.com/a-h/templ/cmd/[email protected]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
go install github.com/a-h/templ/cmd/templ@latest
go install github.com/a-h/templ/cmd/templ@v0.2.513

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 57ba92a and eddd48e.

📒 Files selected for processing (2)
  • .github/workflows/go-test.yml (1 hunks)
  • Dockerfile (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/go-test.yml
🔇 Additional comments (2)
Dockerfile (2)

16-16: LGTM: Proper build configuration

The build command correctly utilises build arguments and includes appropriate flags for a production build.


1-1: ⚠️ Potential issue

Incorrect Go version specified

The base image golang:1.23.3-alpine references a non-existent version of Go. The latest stable version is 1.22.0 as of February 2024.

Apply this correction:

-FROM --platform=$BUILDPLATFORM golang:1.23.3-alpine AS build
+FROM --platform=$BUILDPLATFORM golang:1.22.0-alpine AS build

Likely invalid or redundant comment.

Dockerfile Show resolved Hide resolved
Dockerfile Show resolved Hide resolved
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

🧹 Outside diff range and nitpick comments (2)
frontend/src/css/more-info-overlay.css (2)

1-6: Consider accessibility and text selection improvements

A few suggestions to enhance the base styles:

  1. Instead of display: none, consider using the hidden attribute or visibility: hidden for better accessibility.
  2. Rather than enabling text selection for all children, consider being more specific about which elements should be selectable.
 #more-info {
-    display: none;
+    visibility: hidden;
     * {
-        user-select: text;
+        user-select: none;
     }
+    p, h3, .selectable {
+        user-select: text;
+    }
 }

77-82: Consider responsive padding

The button group layout is good, but consider using relative units or clamp() for the padding to ensure it scales well across different viewport sizes.

 .more-info--button-group {
     display: flex;
     gap: 1rem;
     flex-wrap: wrap;
-    padding-top: 1rem;
+    padding-top: clamp(0.5rem, 2vw, 1rem);
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between eddd48e and fb279d3.

📒 Files selected for processing (6)
  • .dockerignore (1 hunks)
  • custom.example.css (5 hunks)
  • frontend/public/assets/css/kiosk.css (9 hunks)
  • frontend/src/css/kiosk.css (1 hunks)
  • frontend/src/css/more-info-overlay.css (1 hunks)
  • taskfile.yml (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • .dockerignore
  • taskfile.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/css/kiosk.css
🧰 Additional context used
📓 Path-based instructions (2)
custom.example.css (1)

Pattern custom.example.css: ignore this file

frontend/public/assets/css/kiosk.css (1)

Pattern frontend/public/**: exclude

🪛 Biome (1.9.4)
custom.example.css

[error] 43-43: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 77-77: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 78-78: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 79-79: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 96-96: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 156-156: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 165-165: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

🔇 Additional comments (4)
frontend/src/css/more-info-overlay.css (1)

67-75: LGTM! Clean and effective layout adaptation

The landscape layout implementation is well-structured and follows flexbox best practices.

custom.example.css (1)

Line range hint 1-200: Skipping review of this file

As per the coding guidelines and your explicit request in the past review comments, this file will be ignored.

🧰 Tools
🪛 Biome (1.9.4)

[error] 62-62: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 63-63: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 64-64: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 66-66: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 67-67: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 68-68: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 69-69: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 70-70: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 71-71: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 72-72: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 73-73: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 74-74: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 75-75: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 76-76: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 77-77: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 78-78: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 79-79: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 81-81: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)


[error] 82-82: An empty block isn't allowed.

Consider removing the empty block or adding styles inside it.

(lint/suspicious/noEmptyBlock)

frontend/public/assets/css/kiosk.css (2)

3-5: LGTM! Well-structured colour variables.

The addition of semantic colour variables improves maintainability and ensures consistency across the UI.


1272-1272: LGTM! Improved navigation styling and interactions.

The changes enhance the navigation component with:

  • Consistent z-index layering
  • Better hover states with colour feedback
  • Standardised icon sizing
  • Improved spacing

Also applies to: 1289-1289, 1323-1327, 1339-1340, 1361-1364

frontend/src/css/more-info-overlay.css Show resolved Hide resolved
frontend/src/css/more-info-overlay.css Show resolved Hide resolved
frontend/public/assets/css/kiosk.css Show resolved Hide resolved
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

🧹 Outside diff range and nitpick comments (5)
taskfile.frontend.yml (1)

1-28: Consider adding watch tasks for development

The taskfile could benefit from watch tasks for development purposes, allowing for automatic rebuilding of CSS and JS during development.

Consider adding these tasks:

+  frontend-dev:
+    dir: ./frontend
+    cmds:
+      - pnpm dev
+
+  frontend-watch-css:
+    dir: ./frontend
+    cmds:
+      - pnpm watch:css
+
+  frontend-watch-js:
+    dir: ./frontend
+    cmds:
+      - pnpm watch:js
taskfile.docker.yml (2)

5-8: Consider optimising the Docker build configuration

The --no-cache flag forces rebuilding all layers every time, which could significantly slow down your build process. Consider:

  • Removing --no-cache to utilise layer caching
  • Making the repository name configurable via variables
  • Adding .dockerignore verification
  docker-image:
    deps: [build]
    cmds:
-     - docker build --no-cache --build-arg VERSION={{.VERSION}} --load -t damongolding/immich-kiosk:{{.VERSION}} -t damongolding/immich-kiosk:latest .
+     - docker build --build-arg VERSION={{.VERSION}} --load -t {{.DOCKER_REPO}}/immich-kiosk:{{.VERSION}} -t {{.DOCKER_REPO}}/immich-kiosk:latest .

20-23: Review development image strategy

The current development image strategy could be improved:

  • Consider using build stages for development
  • Implement proper versioning for development tags
  • Add development-specific health checks
  docker-dev-push:
    deps: [build]
    cmds:
-     - docker build --build-arg VERSION={{.VERSION}}-DEVELOPMENT --platform linux/amd64,linux/arm64 --push -t damongolding/immich-kiosk-development:{{.VERSION}} -t damongolding/immich-kiosk-development:latest .
+     - docker build --target development --build-arg VERSION={{.VERSION}}-dev --platform linux/amd64,linux/arm64 --push -t {{.DOCKER_REPO}}/immich-kiosk:{{.VERSION}}-dev -t {{.DOCKER_REPO}}/immich-kiosk:dev .
taskfile.yml (1)

5-12: Good modularisation of taskfiles

The separation of frontend and Docker tasks into their own taskfiles with flatten: true improves maintainability and organisation. This is a positive architectural change.

Consider documenting the purpose of each taskfile in the repository's README to help other contributors understand the new structure.

README.md (1)

684-689: Consider capitalising the 'i' key reference for clarity.

The keyboard shortcuts table is well-structured, but the lowercase 'i' in "i Key" might be less clear than "I Key" for users.

| _ Spacebar    | Play/Pause and Toggle Menu                               |
| → Right Arrow | Next Image(s)                                            |
| ← Left Arrow  | Previous Image(s)                                        |
-| i Key         | Play/Pause and Toggle Menu and display more info overlay |
+| I Key         | Play/Pause and Toggle Menu and display more info overlay |
🧰 Tools
🪛 LanguageTool

[uncategorized] ~689-~689: Did you mean “I”?
Context: ... | | i Key | Play/Pause and Toggle Men...

(I_LOWERCASE_PREMIUM)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between fb279d3 and f448363.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (5)
  • README.md (3 hunks)
  • go.mod (1 hunks)
  • taskfile.docker.yml (1 hunks)
  • taskfile.frontend.yml (1 hunks)
  • taskfile.yml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • go.mod
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~689-~689: Did you mean “I”?
Context: ... | | i Key | Play/Pause and Toggle Men...

(I_LOWERCASE_PREMIUM)

🔇 Additional comments (7)
taskfile.frontend.yml (2)

10-14: 🛠️ Refactor suggestion

Consider adding frontend-build as a dependency

The frontend-build task exists but isn't included in the main frontend task dependencies. This might lead to running tests against unbundled code.

Apply this diff to include the build step:

   frontend:
-    deps: [frontend-test, frontend-css, frontend-js]
+    deps: [frontend-build, frontend-test, frontend-css, frontend-js]
     dir: ./frontend
     cmds:
       - pnpm lint

Likely invalid or redundant comment.


15-28: Verify the existence of required npm scripts

The tasks reference several pnpm scripts (test, css, js) that must exist in package.json. Let's ensure these are properly defined.

✅ Verification successful

Let me gather more specific information about the package.json scripts.


All required npm scripts are properly defined

The taskfile's referenced scripts (test, css, js) are all properly defined in the frontend's package.json. Each script has a valid implementation:

  • test: Runs TypeScript type checking
  • css: Bundles CSS with esbuild and processes with PostCSS
  • js: Bundles TypeScript with esbuild
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all referenced npm scripts exist in package.json

# Check if all required scripts exist
REQUIRED_SCRIPTS=("test" "css" "js" "lint" "build")
echo "Checking for required scripts in package.json:"
for script in "${REQUIRED_SCRIPTS[@]}"; do
    echo "Checking for '$script' script..."
    if ! cat ./frontend/package.json | jq -e ".scripts.$script" >/dev/null; then
        echo "Warning: '$script' script not found"
    fi
done

Length of output: 990


Script:

#!/bin/bash
# Let's see the actual content of the scripts section in package.json
cat ./frontend/package.json | jq '.scripts'

Length of output: 620

taskfile.docker.yml (2)

1-3: LGTM: Task file version and structure

The version "3" specification and overall structure follow Taskfile conventions correctly.


15-18: Enhance multi-platform build security and efficiency

Consider these improvements for the production image push:

  • Add authentication verification
  • Implement build caching for CI/CD efficiency
  • Add platform-specific tests before pushing
✅ Verification successful

Let me check if there are any existing authentication mechanisms or CI/CD configurations in the repository.


Let me check the contents of the Docker-related CI/CD workflow to understand the existing build and push process.


Docker build configuration is already well-secured and optimised

The review comment's concerns are already addressed in the CI/CD pipeline:

  • Authentication is properly implemented using Docker Hub secrets
  • Multi-platform builds are handled via Docker Buildx
  • The build and push process is automated and secured within GitHub Actions

The local taskfile.docker.yml is meant for development purposes, and it's appropriate to keep it simple as production builds are handled by the CI/CD pipeline.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify Docker Hub authentication status
docker info 2>&1 | grep -q "Username:"
if [ $? -ne 0 ]; then
    echo "Warning: Not authenticated to Docker Hub"
fi

Length of output: 142


Script:

#!/bin/bash
# Check for CI/CD configurations
fd -e yml -e yaml . .github/workflows/
echo "=== Docker-related files ==="
fd -e dockerfile -e yml -e yaml . | grep -i docker
echo "=== Authentication patterns in CI/CD ==="
rg -i "docker.*login|docker.*auth" .

Length of output: 473


Script:

#!/bin/bash
echo "=== Docker Release Workflow ==="
cat .github/workflows/docker-release.yml

echo -e "\n=== Docker Compose Configuration ==="
cat docker-compose.yaml

Length of output: 2073

taskfile.yml (1)

3-3: Version bump looks appropriate

The increment from 0.14.0-beta.1 to 0.14.0-beta.2 follows semantic versioning conventions for pre-release versions.

README.md (2)

766-772: LGTM! Clear and well-structured webhooks events documentation.

The webhooks events table provides clear descriptions for each event type and maintains consistent formatting.


973-1030: Excellent addition of comprehensive contributing guidelines!

The new contributing section is well-structured and provides:

  • Clear prerequisites and setup instructions
  • Step-by-step contribution process
  • Coding standards and best practices
  • Helpful resources and support channels

Comment on lines 4 to 9
frontend:
deps: [frontend-test, frontend-css, frontend-js]
dir: ./frontend
cmds:
- pnpm lint

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Linting should indeed run before tests in the build pipeline

The package.json scripts reveal that the linting is only checking a single file (./public/assets/js/kiosk.js), whilst the build process runs tests, CSS, and JS tasks. The current task order in taskfile.frontend.yml should be adjusted for two reasons:

  • Linting should run before tests to catch syntax and style issues early
  • The linting scope appears insufficient as it only checks the output JS file, not the source TypeScript files

Suggested changes:

  • Move the lint task to run before the test dependency
  • Expand the lint script in package.json to include TypeScript source files in src/ts
🔗 Analysis chain

Verify the frontend task dependencies

The main frontend task runs the linter after running tests, CSS, and JS tasks. Consider whether the linting should run before the tests to catch basic issues earlier in the pipeline.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if there's a separate lint configuration and verify the build order in package.json

# Check for lint configuration
fd -t f "^\.?lint" ./frontend
fd -t f "^\.?eslint" ./frontend

# Check package.json scripts
cat ./frontend/package.json | jq '.scripts'

Length of output: 715

Comment on lines 10 to 13
docker-buildx:
cmds:
- docker buildx create --name mybuilder --use
- docker buildx install
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for buildx setup

The buildx setup should handle existing builder instances and verify installation success.

  docker-buildx:
    cmds:
+     - docker buildx ls | grep -q mybuilder || \
      - docker buildx create --name mybuilder --use
      - docker buildx install
+     - docker buildx inspect mybuilder --bootstrap
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
docker-buildx:
cmds:
- docker buildx create --name mybuilder --use
- docker buildx install
docker-buildx:
cmds:
- docker buildx ls | grep -q mybuilder || \
- docker buildx create --name mybuilder --use
- docker buildx install
- docker buildx inspect mybuilder --bootstrap

taskfile.yml Outdated
Comment on lines 52 to 58
# Maintenance tasks
install:
deps: [update-templ]
cmds:
- docker build --build-arg VERSION={{.VERSION}}-DEVELOPMENT --platform linux/amd64,linux/arm64 --push -t damongolding/immich-kiosk-development:{{.VERSION}} -t damongolding/immich-kiosk-development:latest .
- go install github.com/golangci/golangci-lint/cmd/[email protected]
- go install github.com/psampaz/go-mod-outdated@latest
- go mod tidy
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Pin go-mod-outdated to the latest stable version v0.9.0

The verification confirms that:

  • golangci-lint is correctly pinned to the latest stable version v1.62.0
  • go-mod-outdated has a stable release v0.9.0 available, which should be used instead of @latest

Suggested change:

-      - go install github.com/psampaz/go-mod-outdated@latest
+      - go install github.com/psampaz/[email protected]
🔗 Analysis chain

Verify Go package versions

The new install task includes specific versions of Go packages. Whilst the inclusion of golangci-lint at v1.62.0 is good, go-mod-outdated lacks version pinning.

Let's check if there are any known issues with these versions:

Consider pinning the version of go-mod-outdated to ensure consistent behaviour across different environments:

-      - go install github.com/psampaz/go-mod-outdated@latest
+      - go install github.com/psampaz/[email protected]
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the specified Go package versions for security and compatibility

# Check latest golangci-lint version
curl -s https://api.github.com/repos/golangci/golangci-lint/releases/latest | jq -r '.tag_name'

# Check if go-mod-outdated has any releases that should be pinned
curl -s https://api.github.com/repos/psampaz/go-mod-outdated/releases | jq -r '.[0].tag_name'

Length of output: 206

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 and nitpick comments (3)
frontend/src/ts/menu.ts (3)

11-11: Consider adding explicit type annotation

Whilst TypeScript can infer the boolean type, adding an explicit type annotation would improve code clarity and maintainability.

-let imageOverlayVisible = false;
+let imageOverlayVisible: boolean = false;

31-35: Add error handling and return type annotation

Consider adding error handling and improving type safety:

-function showImageOverlay() {
+function showImageOverlay(): void {
+  if (!document.body) return;
   if (!document.body.classList.contains("polling-paused")) return;
   document.body.classList.add("more-info");
   imageOverlayVisible = true;
 }

37-44: Add return type annotations and error handling to remaining functions

The hideImageOverlay and toggleImageOverlay functions would benefit from similar improvements:

-function hideImageOverlay() {
+function hideImageOverlay(): void {
+  if (!document.body) return;
   document.body.classList.remove("more-info");
   imageOverlayVisible = false;
 }

-function toggleImageOverlay() {
+function toggleImageOverlay(): void {
   imageOverlayVisible ? hideImageOverlay() : showImageOverlay();
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f448363 and 3ff9104.

📒 Files selected for processing (2)
  • frontend/src/ts/menu.ts (3 hunks)
  • views/views_image.templ (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • views/views_image.templ
🔇 Additional comments (2)
frontend/src/ts/menu.ts (2)

63-65: Export modifications look good

The new overlay control functions are appropriately exported for use in other modules.


31-44: Consider documenting the overlay-polling relationship

The overlay functionality is tightly coupled with the polling state through the "polling-paused" class check. Consider:

  1. Adding JSDoc comments to explain this relationship
  2. Verifying that all CSS classes referenced exist in the related CSS files
✅ Verification successful

The overlay-polling relationship is well-implemented and documented

The codebase shows clear implementation of the overlay-polling relationship:

  • The polling-paused class is used consistently across CSS files for styling overlays
  • The more-info class is properly defined in multiple stylesheets with clear visual effects
  • The relationship between polling state and overlays is handled in both the menu and polling modules
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify CSS classes exist in stylesheets
rg -l "polling-paused|more-info" "frontend/src/css/"

Length of output: 216


Script:

#!/bin/bash
# Check the actual usage of these classes in CSS files
rg "\.polling-paused|\.more-info" "frontend/src/css/" -A 2

Length of output: 2355


Script:

#!/bin/bash
# Check for any existing documentation or related polling functionality
rg "polling.*pause|pause.*polling" -A 3

Length of output: 96977

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

🧹 Outside diff range and nitpick comments (3)
taskfile.frontend.yml (1)

20-33: Consider adding status checks for asset tasks

The CSS and JS tasks might benefit from status checks to ensure they complete successfully. Additionally, consider adding descriptions to document each task's purpose.

Apply this diff to enhance task documentation and error handling:

  frontend-css:
    dir: ./frontend
+   desc: Compile and minify CSS assets
    cmds:
      - pnpm css
+     - echo "CSS compilation completed"

  frontend-js:
    dir: ./frontend
+   desc: Bundle and transpile JavaScript assets
    cmds:
      - pnpm js
+     - echo "JS compilation completed"
taskfile.yml (1)

5-12: Well-structured task modularisation

Good architectural decision to split tasks into separate files. The flatten: true option ensures a clean task namespace whilst maintaining modularity.

Consider documenting the task structure in the repository's README to help other contributors understand the task organisation.

frontend/src/ts/menu.ts (1)

Line range hint 13-30: Consider enhancing error handling

While the type annotations are good additions, the error handling could be improved:

  1. Consider throwing an Error instead of logging to console
  2. Add error boundaries or fallback behaviour
 function disableImageNavigationButtons(): void {
   if (!nextImageMenuButton || !prevImageMenuButton) {
-    console.error("Navigation buttons not initialized");
-    return;
+    throw new Error("Navigation buttons not initialized");
   }
   htmx.addClass(nextImageMenuButton, "disabled");
   htmx.addClass(prevImageMenuButton, "disabled");
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3ff9104 and 7f36ce4.

📒 Files selected for processing (3)
  • frontend/src/ts/menu.ts (4 hunks)
  • taskfile.frontend.yml (1 hunks)
  • taskfile.yml (2 hunks)
🔇 Additional comments (7)
taskfile.frontend.yml (2)

1-3: LGTM! Well-structured task file.

The file follows the standard Taskfile format with proper version specification.


4-9: ⚠️ Potential issue

Linting should run before tests

The current task order runs linting after all other tasks, which could lead to running tests on code that doesn't meet the project's style guidelines. Consider moving the lint command to a separate task and making it a dependency of the test task.

Apply this diff to improve the task order:

  frontend:
-   deps: [frontend-test, frontend-css, frontend-js]
+   deps: [frontend-lint, frontend-test, frontend-css, frontend-js]
    dir: ./frontend
+   cmds: []
+
+ frontend-lint:
+   dir: ./frontend
    cmds:
      - pnpm lint
taskfile.yml (2)

3-3: LGTM: Version bump follows semantic versioning

The version increment from beta.1 to beta.2 is appropriate for a beta release cycle.


52-58: Well-structured install task with appropriate dependencies

The install task is well-organised with proper dependencies. However, the previously identified issue regarding version pinning for go-mod-outdated remains valid.

frontend/src/ts/menu.ts (3)

11-11: LGTM: Well-typed state variable

The boolean state variable is properly typed and initialised with a sensible default value.


67-69: LGTM: Clean export additions

The new overlay control functions are properly exported, maintaining the module's public API structure.


31-45: Verify integration with polling and keyboard events

Let's confirm that the overlay functions are properly integrated with the polling system and keyboard events.

✅ Verification successful

Let me check the actual integration points in these files to verify the proper usage.


Image overlay functions are properly integrated

The integration points show correct usage:

  • polling.ts correctly imports and calls hideImageOverlay when polling state changes
  • kiosk.ts properly integrates toggleImageOverlay with click events and polling state transitions
  • The functions maintain synchronisation between polling state and overlay visibility
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check integration points in polling and keyboard event handlers
echo "Checking polling integration..."
rg -l "hideImageOverlay" --type ts

echo "\nChecking keyboard event handlers..."
rg -l "toggleImageOverlay.*keypress|keydown|keyup" --type ts

Length of output: 331


Script:

#!/bin/bash
# Check how hideImageOverlay is used in polling.ts
echo "Integration in polling.ts:"
rg "hideImageOverlay" frontend/src/ts/polling.ts -B 2 -A 2

echo "\nKeyboard event handling in kiosk.ts:"
rg "toggleImageOverlay" frontend/src/ts/kiosk.ts -B 2 -A 2

Length of output: 1089

taskfile.frontend.yml Outdated Show resolved Hide resolved
Comment on lines 31 to 45
function showImageOverlay(): void {
if (!document.body) return;
if (!document.body.classList.contains("polling-paused")) return;
document.body.classList.add("more-info");
imageOverlayVisible = true;
}

function hideImageOverlay(): void {
document.body.classList.remove("more-info");
imageOverlayVisible = false;
}

function toggleImageOverlay(): void {
imageOverlayVisible ? hideImageOverlay() : showImageOverlay();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add consistent null checks across overlay functions

While showImageOverlay includes a null check for document.body, this check is missing in hideImageOverlay. Let's maintain consistency.

 function hideImageOverlay(): void {
+  if (!document.body) return;
   document.body.classList.remove("more-info");
   imageOverlayVisible = false;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function showImageOverlay(): void {
if (!document.body) return;
if (!document.body.classList.contains("polling-paused")) return;
document.body.classList.add("more-info");
imageOverlayVisible = true;
}
function hideImageOverlay(): void {
document.body.classList.remove("more-info");
imageOverlayVisible = false;
}
function toggleImageOverlay(): void {
imageOverlayVisible ? hideImageOverlay() : showImageOverlay();
}
function showImageOverlay(): void {
if (!document.body) return;
if (!document.body.classList.contains("polling-paused")) return;
document.body.classList.add("more-info");
imageOverlayVisible = true;
}
function hideImageOverlay(): void {
if (!document.body) return;
document.body.classList.remove("more-info");
imageOverlayVisible = false;
}
function toggleImageOverlay(): void {
imageOverlayVisible ? hideImageOverlay() : showImageOverlay();
}

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 and nitpick comments (2)
frontend/src/ts/menu.ts (2)

Line range hint 13-29: Consider adding type guards for better type safety.

The error handling is good, but we could improve type safety by using type guards instead of type assertions.

Consider this refactoring:

 function enableImageNavigationButtons(): void {
   if (!nextImageMenuButton || !prevImageMenuButton) {
     console.error("Navigation buttons not initialized");
     return;
   }
-  htmx.removeClass(nextImageMenuButton as Element, "disabled");
-  htmx.removeClass(prevImageMenuButton as Element, "disabled");
+  if (nextImageMenuButton instanceof Element && prevImageMenuButton instanceof Element) {
+    htmx.removeClass(nextImageMenuButton, "disabled");
+    htmx.removeClass(prevImageMenuButton, "disabled");
+  }
 }

31-46: Consider adding debouncing for overlay toggles.

The overlay functions are well-implemented, but rapid toggling could lead to visual glitches or performance issues.

Consider implementing debouncing:

import { debounce } from 'lodash';

const debouncedToggle = debounce(() => {
  imageOverlayVisible ? hideImageOverlay() : showImageOverlay();
}, 250);

function toggleImageOverlay(): void {
  debouncedToggle();
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7f36ce4 and 7085966.

📒 Files selected for processing (4)
  • frontend/src/ts/menu.ts (4 hunks)
  • taskfile.docker.yml (1 hunks)
  • taskfile.frontend.yml (1 hunks)
  • taskfile.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • taskfile.docker.yml
  • taskfile.frontend.yml
🔇 Additional comments (8)
taskfile.yml (6)

3-12: LGTM! Well-structured task organisation

The version bump and new includes section provide a clean separation of concerns between main, frontend and Docker tasks.


17-26: LGTM! Clear task descriptions and appropriate debug configurations

The development tasks are well-documented with clear descriptions and proper debug flag settings.


30-41: LGTM! Well-defined backend tasks

Each task has a clear purpose and follows the single responsibility principle.


46-57: LGTM! Robust build configuration

The build tasks are well-configured with:

  • Static builds (CGO_ENABLED=0)
  • Proper version injection
  • Appropriate dependencies

65-65: Pin go-mod-outdated version

The previous review comment about pinning go-mod-outdated to v0.9.0 is still valid.


59-77: LGTM! Well-structured maintenance tasks

The maintenance tasks provide good coverage for development setup and dependency management.

frontend/src/ts/menu.ts (2)

11-11: LGTM! Well-typed variable declaration.

The variable declaration follows TypeScript best practices with proper type annotation and initialisation.


68-70: Verify the usage patterns of newly exported functions.

Let's ensure these newly exported overlay functions are being used consistently across the application.

@damongolding damongolding merged commit 7619027 into task/release Nov 22, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant