Skip to content

Feature/posts#421

Merged
NielsPilgaard merged 61 commits into
mainfrom
feature/posts
Aug 29, 2025
Merged

Feature/posts#421
NielsPilgaard merged 61 commits into
mainfrom
feature/posts

Conversation

@NielsPilgaard

Copy link
Copy Markdown
Owner

No description provided.

@coderabbitai

coderabbitai Bot commented Aug 30, 2024

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@NielsPilgaard has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 34 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 319e1d7 and 8e7b8f5.

📒 Files selected for processing (2)
  • .github/workflows/website_frontend_ci.yml (1 hunks)
  • src/web/Jordnaer/Pages/Groups/Members.razor (2 hunks)

Walkthrough

Adds Posts feature: new EF entities, migrations, services, DI registrations, Blazor components, and a posts page with search. Updates configs (feature flag, logging). Removes Shared.Infrastructure project, refactors Serilog namespace. Drops IGroupService interface and aligns DI/usages. Introduces string sanitization helpers and applies them. Upgrades multiple dependencies and workflows.

Changes

Cohort / File(s) Summary
Posts feature (services, DI, UI)
src/web/Jordnaer/Features/Posts/PostService.cs, src/web/Jordnaer/Features/Posts/WebApplicationExtensions.cs, src/web/Jordnaer/Features/Posts/CreatePostComponent.razor, src/web/Jordnaer/Features/Posts/PostCardComponent.razor, src/web/Jordnaer/Pages/Posts/Posts.razor, src/web/Jordnaer/Program.cs, src/web/Jordnaer/_Imports.razor
Introduces PostService and DI extension; adds create/display components and posts page; wires services via Program; adds using directives.
Post search feature
src/web/Jordnaer/Features/PostSearch/PostSearchService.cs, src/web/Jordnaer/Features/PostSearch/WebApplicationExtensions.cs, src/web/Jordnaer/Program.cs, src/web/Jordnaer/_Imports.razor
Adds PostSearchService with filtering, error handling, DI extension; registers in Program and imports.
Database: entities and migrations
src/shared/Jordnaer.Shared/Database/Post.cs, src/web/Jordnaer/Migrations/20250220204935_Add_Posts_And_GroupPosts*.cs, src/web/Jordnaer/Migrations/20250220210616_Add_ZipCodeIndex_On_Post*.cs, src/web/Jordnaer/Migrations/JordnaerDbContextModelSnapshot.cs, src/web/Jordnaer/Migrations/migration_script.sql, src/web/Jordnaer/add-migration.ps1, src/web/Jordnaer/Migrations/drop_all_tables.sql
Adds Post entity; creates tables GroupPosts, Posts, PostCategory; adds ZipCode index; updates model snapshot and SQL script; adds migration script helper; extends drop script.
Group service refactor (interface removal) and consumers
src/web/Jordnaer/Features/Groups/GroupService.cs, src/web/Jordnaer/Features/Groups/WebApplicationBuilderExtensions.cs, src/web/Jordnaer/Pages/Groups/CreateGroup.razor, src/web/Jordnaer/Pages/Groups/EditGroup.razor, src/web/Jordnaer/Pages/Groups/GroupDetails.razor, src/web/Jordnaer/Pages/Groups/MyGroups.razor, src/web/Jordnaer/Pages/Groups/Members.razor
Removes IGroupService; registers and injects concrete GroupService; Members page gains cell-edit workflow, permissions logic, and helper methods.
Sanitization utilities and usage
src/web/Jordnaer/Extensions/StringExtensions.cs, src/web/Jordnaer/Features/Groups/GroupMemberListComponent.razor, src/web/Jordnaer/Features/Groups/GroupSummaryCard.razor, src/web/Jordnaer/Features/Profile/MarkdownRenderer.cs
Adds string sanitization helpers; applies Sanitize() to links/text in group components; exposes EmptyMarkupString as internal.
Serilog and infrastructure reorg
src/web/Jordnaer/Extensions/SerilogExtensions.cs, src/web/Jordnaer/Jordnaer.csproj, src/shared/Jordnaer.Shared.Infrastructure/Jordnaer.Shared.Infrastructure.csproj (removed), Jordnaer.sln
Moves SerilogExtensions namespace to Jordnaer.Extensions; removes Shared.Infrastructure project and reference; updates solution structure.
Config updates
src/web/Jordnaer/appsettings.Development.json, src/web/Jordnaer/appsettings.json
Enables FeatureManagement.Posts; removes DataForsyningen section; adds Serilog override for MudBlazor.
Search services comments
src/web/Jordnaer/Features/GroupSearch/GroupSearchService.cs, src/web/Jordnaer/Features/UserSearch/UserSearchService.cs
Adds TODO comments for try-catch/error handling; no logic changes.
UI header/nav changes
src/web/Jordnaer/Pages/Shared/TopBar.razor, src/web/Jordnaer/Pages/Profile/MyProfile.razor, src/web/Jordnaer/Features/Profile/DeleteUserComponent.razor, src/web/Jordnaer/wwwroot/css/app.css
Adds Posts nav button behind feature flag; removes Logout from top bar; adds logout button on profile page; adjusts delete button variant; adds bold datagrid header CSS.
Minor feature text/log tweaks
src/web/Jordnaer/Features/Chat/ChatNotificationService.cs, src/web/Jordnaer/Features/DeleteUser/DeleteUserService.cs
Adds TODO comment; updates log message wording about base URI source.
Dependency/version bumps
src/web/Jordnaer/Jordnaer.csproj, src/shared/Jordnaer.Shared/Jordnaer.Shared.csproj, benchmarks/Jordnaer.Benchmarks/Jordnaer.Benchmarks.csproj, tests/web/Jordnaer.Tests/Jordnaer.Tests.csproj, tests/web/Jordnaer.E2E.Tests/Jordnaer.E2E.Tests.csproj, .github/workflows/website_frontend_ci.yml
Upgrades multiple NuGet packages across projects; adds logging/feature mgmt packages to web; updates Playwright versions (code and CI).
E2E login selector updates
tests/web/Jordnaer.E2E.Tests/Infrastructure/BrowserExtensions.cs
Adjusts placeholder texts and centralizes exact-match options for Playwright selectors.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant UI as Posts.razor
  participant CPS as CreatePostComponent
  participant PS as PostService
  participant DB as JordnaerDbContext

  rect rgb(238,245,255)
  note right of UI: Search posts
  U->>UI: Submit PostSearchForm
  UI->>PSrch: GetPostsAsync(filter)
  activate PSrch
  PSrch->>DB: Query Posts with filters<br/>+ pagination
  DB-->>PSrch: Posts, totalCount
  PSrch-->>UI: PostSearchResult
  deactivate PSrch
  UI-->>U: Render results
  end

  rect rgb(240,255,240)
  note right of CPS: Create post
  U->>CPS: Click Create
  CPS->>PS: CreatePostAsync(post)
  activate PS
  PS->>DB: Add post + categories
  DB-->>PS: Saved
  PS-->>CPS: Success
  deactivate PS
  CPS-->>U: Snackbar success
  end
Loading
sequenceDiagram
  autonumber
  actor Admin as Group Owner/Moderator
  participant Members as Members.razor
  participant GS as GroupService
  participant DB as JordnaerDbContext

  Admin->>Members: Edit cell (permission/ownership)
  Members->>GS: UpdateMembership(item)
  GS->>DB: Save changes
  DB-->>GS: OK
  GS-->>Members: OK
  Members-->>Admin: Snackbar: saved
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested labels

dependencies, .NET

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/posts

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit 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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Outside diff range, codebase verification and nitpick comments (2)
src/shared/Jordnaer.Shared/Extensions/PostExtensions.cs (1)

3-23: Well-implemented extension method for data transformation.

The ToPostDto method is a clean and effective way to transform Post objects into PostDto instances. It properly utilizes properties and handles transformations with LINQ, which is idiomatic in C#.

Consider evaluating the performance of the LINQ query in Categories transformation, especially if the Categories collection can be large. It might be beneficial to optimize this part if performance issues arise.

src/shared/Jordnaer.Shared/Posts/PostDto.cs (1)

5-21: Well-structured DTO class with appropriate validations.

The PostDto class is well-defined with necessary validations using data annotations, ensuring that the data conforms to expected formats and constraints. This is crucial for maintaining data integrity when transferring between layers or services.

Consider adding XML documentation comments to the properties and the class itself to improve code maintainability and provide better context for other developers.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between bb9c3e1 and 8b0ca9d.

Files selected for processing (16)
  • src/shared/Jordnaer.Shared/Database/GroupCategory.cs (1 hunks)
  • src/shared/Jordnaer.Shared/Database/GroupPost.cs (1 hunks)
  • src/shared/Jordnaer.Shared/Database/Post.cs (1 hunks)
  • src/shared/Jordnaer.Shared/Database/PostCategory.cs (1 hunks)
  • src/shared/Jordnaer.Shared/Extensions/PostExtensions.cs (1 hunks)
  • src/shared/Jordnaer.Shared/Posts/PostDto.cs (1 hunks)
  • src/shared/Jordnaer.Shared/Posts/PostSearchFilter.cs (1 hunks)
  • src/shared/Jordnaer.Shared/Posts/PostSearchResult.cs (1 hunks)
  • src/web/Jordnaer/Database/JordnaerDbContext.cs (2 hunks)
  • src/web/Jordnaer/Features/Metrics/JordnaerMetrics.cs (1 hunks)
  • src/web/Jordnaer/Features/PostSearch/PostSearchService.cs (1 hunks)
  • src/web/Jordnaer/Features/Posts/PostService.cs (1 hunks)
  • src/web/Jordnaer/Features/UserSearch/UserSearchService.cs (5 hunks)
  • src/web/Jordnaer/Pages/Shared/TopBar.razor (1 hunks)
  • src/web/Jordnaer/appsettings.Development.json (1 hunks)
  • src/web/Jordnaer/appsettings.json (1 hunks)
Files skipped from review due to trivial changes (1)
  • src/shared/Jordnaer.Shared/Database/GroupCategory.cs
Additional comments not posted (25)
src/shared/Jordnaer.Shared/Posts/PostSearchResult.cs (1)

3-7: Well-structured class for search results.

The PostSearchResult class is well-designed to encapsulate search results, with a list of PostDto and a TotalCount property. The initialization of Posts with an empty list is a good practice, ensuring that the property is never null.

src/shared/Jordnaer.Shared/Database/PostCategory.cs (1)

3-8: Appropriate use of required properties for database integrity.

The PostCategory class effectively represents a many-to-many relationship between posts and categories. The use of required for both PostId and CategoryId ensures that these fields are always initialized, which is crucial for maintaining database integrity.

src/web/Jordnaer/appsettings.Development.json (1)

1-21: Well-configured feature flags and logging settings.

The configuration in appsettings.Development.json is well-structured, providing clear management of feature flags and detailed logging settings. This setup will facilitate easy toggling of features and effective monitoring and debugging through the specified logging levels.

src/web/Jordnaer/appsettings.json (2)

15-15: Approved change in logging level.

The change from "Debug" to "Information" for the default logging level is a good practice for production environments as it reduces log verbosity and can help in managing log storage and processing overhead effectively.

Consider verifying the impact of this change on existing logging to ensure no critical information is missed.


21-21: Approved change in MudBlazor logging level.

Changing the logging level for "MudBlazor" from "Information" to "Warning" is likely aimed at reducing log clutter and focusing on more significant issues. This is generally a good practice, especially if "MudBlazor" logs are verbose.

Monitor the logs after this change to ensure that no important information is being omitted.

src/shared/Jordnaer.Shared/Database/Post.cs (1)

6-27: Review of the Post class

The Post class is well-structured with appropriate use of data annotations for validation and database configuration. Here are some specific observations:

  • ID Configuration: The use of [Key] and [DatabaseGenerated(DatabaseGeneratedOption.None)] on Id suggests that IDs are expected to be provided by the application rather than generated by the database. This is an important design decision that should be documented.
  • Validation: The StringLength and Required attributes on Text are used effectively to enforce content rules.
  • Default Values: The initialization of CreatedUtc to DateTimeOffset.UtcNow is a good practice to ensure that the creation time is always set.
  • Nullable Properties: ZipCode and City are nullable, which is appropriate if these are optional details for a post.
  • Relationships: The use of ForeignKey attributes on UserProfileId and the initialization of UserProfile and Categories are correctly implemented to manage relationships and collections.

Overall, the class is implemented correctly with attention to detail in managing data integrity and relationships.

src/shared/Jordnaer.Shared/Database/GroupPost.cs (1)

6-30: Review of the GroupPost class

The GroupPost class is similar to the Post class but includes additional handling for group-related properties. Here are some specific observations:

  • ID and Validation: The configuration and validation for Id and Text are consistent with the Post class, which is good for consistency across entity definitions.
  • Group Relationship: The addition of GroupId and Group with the ForeignKey attribute is correctly implemented to link posts to specific groups.
  • Default Values and Nullable Properties: Similar to the Post class, default values and nullable properties are handled appropriately.

This class effectively extends the functionality of the Post class to accommodate group-specific features while maintaining consistency in design and implementation.

src/web/Jordnaer/Pages/Shared/TopBar.razor (1)

6-18: Enhancements to the TopBar.razor

The modifications to the TopBar.razor file introduce dynamic feature management and improve the layout for better user experience. Here are some specific observations:

  • Feature Flag Integration: The introduction of the <Feature> component to conditionally render the posts button based on FeatureFlags.Posts is a smart use of feature flags to control UI elements dynamically.
  • Layout Adjustment: The reorganization of the <AuthorizeView> components to accommodate the new feature button helps in maintaining a clean and user-friendly navigation bar.

These changes are well-thought-out and align with the objectives of enhancing functionality and user experience.

src/shared/Jordnaer.Shared/Posts/PostSearchFilter.cs (1)

5-22: Well-structured class for post search filtering.

The PostSearchFilter class is well-designed with appropriate properties and validation attributes to handle various aspects of post search filtering. The use of default values for arrays and pagination settings is a good practice to avoid null issues.

src/web/Jordnaer/Features/PostSearch/PostSearchService.cs (2)

9-12: Interface Design Approved

The IPostSearchService interface is well-defined, providing a clear contract for implementing classes.


15-17: Class Constructor Review

The constructor correctly uses dependency injection for IDbContextFactory<JordnaerDbContext> and IZipCodeService, ensuring that the class is testable and modular.

src/web/Jordnaer/Features/Metrics/JordnaerMetrics.cs (2)

43-44: Approved: Addition of PostSearchesCounter.

The new counter for tracking post searches is correctly initialized and follows the established pattern for metric counters in the application.


45-46: Approved: Addition of PostsCreatedCounter.

The new counter for tracking the creation of posts is correctly initialized and follows the established pattern for metric counters in the application.

src/web/Jordnaer/Features/Posts/PostService.cs (3)

22-34: Approved: Implementation of GetPostAsync.

The method is well-implemented with proper asynchronous handling and use of LINQ for querying. The use of OneOf for the return type is appropriate for handling scenarios where the post might not be found.


37-55: Approved: Implementation of CreatePostAsync.

The method efficiently checks for the existence of a post using AsNoTracking before adding a new one. The error handling and asynchronous commit of changes are appropriately implemented.


58-73: Verify: Use of ExecuteDeleteAsync in DeletePostAsync.

The method is generally well-implemented, but the use of ExecuteDeleteAsync is not standard in EF Core. Please verify if this is a custom implementation or extension method and ensure it is correctly implemented.

src/web/Jordnaer/Database/JordnaerDbContext.cs (4)

14-14: Verify: Simplification of Chats DbSet type.

The change from DbSet<Shared.Chat> to DbSet<Chat> suggests a refactoring of the Chat entity. Please verify that all references to this DbSet are correctly updated to reflect the new type.


23-23: Approved: Addition of Posts DbSet.

The addition of the Posts DbSet is consistent with the expansion of the application's functionality. Please ensure that the Post entity is correctly configured in the OnModelCreating method.


24-24: Approved: Addition of GroupPosts DbSet.

The addition of the GroupPosts DbSet is consistent with the expansion of the application's functionality. Please ensure that the GroupPost entity is correctly configured in the OnModelCreating method.


28-43: Approved: Updates in OnModelCreating for Post and GroupPost.

The new configurations for Post and GroupPost entities are correctly defined, establishing necessary relationships with other entities. Please conduct a thorough verification to ensure these configurations do not introduce any unintended consequences or conflicts with existing configurations.

src/web/Jordnaer/Features/UserSearch/UserSearchService.cs (5)

28-28: Clarification on Pagination Logic

The comment added to the Take(11) method call provides a clear explanation for why 11 users are fetched instead of 10. This is a good practice as it enhances code readability and understanding, especially for those unfamiliar with the pagination logic.


122-122: Visibility Change: ApplyCategoryFilter

The change from private to internal for ApplyCategoryFilter is approved, assuming it is intended to facilitate testing or reuse within the assembly. As with any visibility change, verify that it does not expose more than necessary.

Verification successful

Visibility Change Verified: ApplyCategoryFilter

The change from private to internal for the ApplyCategoryFilter method is appropriate. The method is used within the assembly, primarily in test files and other service files, which aligns with the intended scope of an internal method. There are no indications of unintended exposure.

  • References found in test files and other service files within the assembly.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the `ApplyCategoryFilter` method is not exposed beyond intended use within the assembly.

# Test: Search for references to `ApplyCategoryFilter` outside expected files. Expect: No occurrences outside expected scope.
rg --type cs --glob '!UserSearchService.cs' 'ApplyCategoryFilter'

Length of output: 1951


133-133: Visibility Change: ApplyNameFilter

The visibility change for ApplyNameFilter from private to internal is approved. This change likely aims to facilitate testing or reuse. Ensure that it does not lead to unintended exposure of functionality.

Verification successful

Visibility Change Verified: ApplyNameFilter

The change in visibility for the ApplyNameFilter method in UserSearchService.cs from private to internal does not expose it beyond its intended use. The references found are for a different method with the same name in a different context. The change is safe and approved.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the `ApplyNameFilter` method is not exposed beyond intended use within the assembly.

# Test: Search for references to `ApplyNameFilter` outside expected files. Expect: No occurrences outside expected scope.
rg --type cs --glob '!UserSearchService.cs' 'ApplyNameFilter'

Length of output: 1073


Line range hint 94-114: Visibility Change: ApplyLocationFilterAsync

Changing the access modifier from private to internal for ApplyLocationFilterAsync allows broader access within the assembly. This can facilitate testing and reuse in other components. However, ensure that this change does not unintentionally expose internal details that should remain encapsulated.

Verification successful

Visibility Change Verified: ApplyLocationFilterAsync

The change in visibility from private to internal for the ApplyLocationFilterAsync method is consistent with its usage across multiple services within the same assembly. This change facilitates code reuse and maintainability without exposing the method beyond the intended scope.

  • Files using ApplyLocationFilterAsync:
    • src/web/Jordnaer/Features/PostSearch/PostSearchService.cs
    • src/web/Jordnaer/Features/GroupSearch/GroupSearchService.cs

This confirms that the change is appropriate and aligns with the intended design.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the `ApplyLocationFilterAsync` method is not exposed beyond intended use within the assembly.

# Test: Search for references to `ApplyLocationFilterAsync` outside expected files. Expect: No occurrences outside expected scope.
rg --type cs --glob '!UserSearchService.cs' 'ApplyLocationFilterAsync'

Length of output: 671


144-144: Visibility Change: ApplyChildFilters

The change from private to internal for ApplyChildFilters is approved, assuming it is intended to facilitate testing or reuse within the assembly. Verify that this change does not expose more functionality than intended.

Verification successful

Visibility Change Verified: ApplyChildFilters

The change from private to internal for ApplyChildFilters does not expose the method beyond its intended scope, as there are no external references. This change is appropriate for internal reuse or testing purposes. No further action is needed.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the `ApplyChildFilters` method is not exposed beyond intended use within the assembly.

# Test: Search for references to `ApplyChildFilters` outside expected files. Expect: No occurrences outside expected scope.
rg --type cs --glob '!UserSearchService.cs' 'ApplyChildFilters'

Length of output: 63


Script:

#!/bin/bash
# Re-run the search for references to `ApplyChildFilters` outside the `UserSearchService.cs` file to verify the previous result.
rg --type cs --glob '!src/web/Jordnaer/Features/UserSearch/UserSearchService.cs' 'ApplyChildFilters'

Length of output: 100

Comment thread src/shared/Jordnaer.Shared/Posts/PostSearchFilter.cs
Comment thread src/shared/Jordnaer.Shared/Posts/PostSearchFilter.cs
Comment thread src/web/Jordnaer/Features/PostSearch/PostSearchService.cs Outdated
Comment thread src/web/Jordnaer/Features/PostSearch/PostSearchService.cs
Comment thread src/web/Jordnaer/Features/PostSearch/PostSearchService.cs
Comment thread src/web/Jordnaer/Features/PostSearch/PostSearchService.cs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Outside diff range, codebase verification and nitpick comments (1)
src/web/Jordnaer/Features/GroupSearch/GroupSearchService.cs (1)

Line range hint 9-36: Well-structured method, but consider immediate error handling improvements.

The GetGroupsAsync method is well-implemented with clear logic for filtering and paginating groups. It efficiently uses asynchronous operations and Entity Framework capabilities. However, as noted in the TODO comment, adding error handling would significantly improve the method's robustness and fault tolerance.

Consider implementing the error handling improvements sooner rather than later to prevent potential issues in production environments.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 8b0ca9d and 7797602.

Files selected for processing (3)
  • src/web/Jordnaer/Features/GroupSearch/GroupSearchService.cs (1 hunks)
  • src/web/Jordnaer/Features/PostSearch/PostSearchService.cs (1 hunks)
  • src/web/Jordnaer/Features/UserSearch/UserSearchService.cs (6 hunks)
Files skipped from review as they are similar to previous changes (2)
  • src/web/Jordnaer/Features/PostSearch/PostSearchService.cs
  • src/web/Jordnaer/Features/UserSearch/UserSearchService.cs

Comment thread src/web/Jordnaer/Features/GroupSearch/GroupSearchService.cs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 7797602 and 1bf2dc8.

Files selected for processing (6)
  • src/web/Jordnaer/Features/GroupPosts/PostService.cs (1 hunks)
  • src/web/Jordnaer/Features/Posts/CreatePostComponent.razor (1 hunks)
  • src/web/Jordnaer/Features/Posts/PostSearchForm.razor (1 hunks)
  • src/web/Jordnaer/Features/Posts/PostSearchResultComponent.razor (1 hunks)
  • src/web/Jordnaer/Pages/Posts/Posts.razor (1 hunks)
  • src/web/Jordnaer/_Imports.razor (1 hunks)
Additional context used
GitHub Check: test
src/web/Jordnaer/Features/Posts/CreatePostComponent.razor

[warning] 25-25:
Possible null reference assignment.

src/web/Jordnaer/Pages/Posts/Posts.razor

[warning] 17-17:
Component 'PostSearchForm' expects a value for the parameter 'FilterChanged', but a value may not have been provided.

src/web/Jordnaer/Features/Posts/PostSearchForm.razor

[warning] 56-56:
The field 'PostSearchForm._recentlyClearedForm' is assigned but its value is never used

Additional comments not posted (13)
src/web/Jordnaer/Features/Posts/CreatePostComponent.razor (2)

1-6: Injections are appropriate for the component's functionality.

The injected services (IPostService, IPostSearchService, NavigationManager, IJSRuntime, ISnackbar) are essential for the functionality of the component, which includes creating posts and interacting with the user interface.


8-12: Component structure and bindings are correctly implemented.

The use of MudBlazor components (MudPaper, MudText, MudTextField, MudButton) provides a consistent and user-friendly interface. The binding of newPostContent to the MudTextField is correctly implemented, allowing for dynamic data handling in the component.

src/web/Jordnaer/Features/Posts/PostSearchResultComponent.razor (2)

5-25: Component structure for displaying posts is well-implemented.

The use of MudGrid, MudItem, and MudCard components to display each post ensures a clean and responsive layout. The pagination implemented with MudPagination is crucial for handling large sets of results and is appropriately configured with dynamic properties.


27-35: Parameter handling and pagination logic are correctly implemented.

The use of [Parameter, EditorRequired] attributes ensures that essential data is provided to the component. The SelectedPageChanged event is properly configured to handle pagination, which is crucial for user interactions with search results.

src/web/Jordnaer/_Imports.razor (1)

23-25: Addition of namespaces enhances feature accessibility.

The inclusion of @using Jordnaer.Features.Posts, @using Jordnaer.Features.PostSearch, and @using Jordnaer.Features.GroupPosts is appropriate and aligns with the PR objectives to enhance the application's post functionalities. This change facilitates easier access to these features across the application.

src/web/Jordnaer/Pages/Posts/Posts.razor (4)

1-4: Proper setup of page directive and services.

The @page directive and dependency injections are correctly implemented, ensuring the necessary services are available for the page.


8-9: Good use of metadata for SEO and user experience.

The MetadataComponent is properly configured with a title and description, enhancing the page's SEO and providing clear information to users.


19-32: Well-implemented conditional rendering for search results.

The logic correctly handles scenarios where no search has been performed or no results are found, providing clear feedback to the user.


34-40: Appropriate use of components for ads and search results.

The SponsorAd and PostSearchResultComponent are correctly implemented, enhancing the page's functionality and user engagement.

src/web/Jordnaer/Features/GroupPosts/PostService.cs (3)

23-35: Ensure proper handling of NotFound type.

The method implementation looks correct. However, ensure that the NotFound type returned when a post is not found is properly handled in the calling code to provide appropriate user feedback or logging.


38-56: Verify language consistency in error messages.

The method is well-implemented and efficiently checks for duplicate posts before attempting to create a new one. However, the error message "Opslaget eksisterer allerede" is in Danish. Please verify that this aligns with the language consistency across the application or if multilingual support is intended.


59-74: Verify the use of ExecuteDeleteAsync.

The method implementation for deleting a post appears correct. However, ExecuteDeleteAsync is used, which is not a standard Entity Framework method. Please ensure that this method is part of a reliable extension or has been properly implemented and tested in your project.

src/web/Jordnaer/Features/Posts/PostSearchForm.razor (1)

1-2: Well-configured UI and dependency injections.

The dependency injections for NavigationManager and IJSRuntime are correctly set up, which are essential for navigation and JavaScript interactions in Blazor applications. The UI layout using MudBlazor components is well-structured and should provide a good user experience.

Also applies to: 4-41

Comment thread src/web/Jordnaer/Features/Posts/CreatePostComponent.razor Outdated
Comment thread src/web/Jordnaer/Pages/Posts/Posts.razor
Comment thread src/web/Jordnaer/Pages/Posts/Posts.razor
Comment thread src/web/Jordnaer/Features/GroupPosts/PostService.cs
Comment thread src/web/Jordnaer/Features/Posts/PostSearchForm.razor

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 1bf2dc8 and f8851b9.

Files selected for processing (5)
  • src/shared/Jordnaer.Shared/Database/Post.cs (1 hunks)
  • src/web/Jordnaer/Features/Posts/CreatePostComponent.razor (1 hunks)
  • src/web/Jordnaer/Features/Posts/PostCardComponent.razor (1 hunks)
  • src/web/Jordnaer/Features/Posts/PostSearchForm.razor (1 hunks)
  • src/web/Jordnaer/Features/Posts/PostSearchResultComponent.razor (1 hunks)
Files skipped from review as they are similar to previous changes (3)
  • src/shared/Jordnaer.Shared/Database/Post.cs
  • src/web/Jordnaer/Features/Posts/PostSearchForm.razor
  • src/web/Jordnaer/Features/Posts/PostSearchResultComponent.razor
Additional context used
GitHub Check: test
src/web/Jordnaer/Features/Posts/CreatePostComponent.razor

[failure] 31-31:
The type of component 'MudCheckBox' cannot be inferred based on the values provided. Consider specifying the type arguments directly using the following attributes: 'T'.

Additional comments not posted (1)
src/web/Jordnaer/Features/Posts/PostCardComponent.razor (1)

1-22: LGTM!

The PostCardComponent is well-implemented and follows best practices:

  • It uses MudBlazor components for consistent styling.
  • It handles null checks for optional properties like ZipCode and City.
  • The Post parameter is marked as required, ensuring that the component always receives a valid PostDto object.

The code changes are approved.

Comment thread src/web/Jordnaer/Features/Posts/CreatePostComponent.razor Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between f8851b9 and db5b46a.

Files selected for processing (1)
  • src/web/Jordnaer/Features/Posts/CreatePostComponent.razor (1 hunks)
Additional context used
GitHub Check: test
src/web/Jordnaer/Features/Posts/CreatePostComponent.razor

[warning] 1-1:
Illegal Parameter 'Checked' on 'MudCheckBox' using 'V7IgnoreCase' source location '(574,24)-(582,25)' (https://mudblazor.com/features/analyzers)


[warning] 1-1:
Illegal Attribute 'CheckedChanged' on 'MudCheckBox' using pattern 'LowerCase' source location '(583,24)-(583,246)' (https://mudblazor.com/features/analyzers)

Additional comments not posted (3)
src/web/Jordnaer/Features/Posts/CreatePostComponent.razor (3)

69-73: The null reference issue has been addressed.

The code has been updated to check for null on _userProfile before accessing its properties. The previous comment about adding a null check for CurrentUser is no longer valid.


31-31: The type parameter issue has been addressed.

The code has been updated to set the type parameter T to bool for the MudCheckBox component. The previous comment about setting the type parameter is no longer valid.


62-95: The CreatePost method looks good!

The method is well-structured and follows best practices such as:

  • Checking for empty input and returning early.
  • Checking for null user profile and displaying a message.
  • Setting the post properties before creating the post.
  • Handling the result of creating the post and displaying appropriate messages.

No issues or improvements identified. Good job!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between db5b46a and 17aa5e7.

Files selected for processing (3)
  • src/web/Jordnaer/Features/Posts/CreatePostComponent.razor (1 hunks)
  • src/web/Jordnaer/Features/Posts/PostCardComponent.razor (1 hunks)
  • src/web/Jordnaer/Features/Posts/PostSearchForm.razor (1 hunks)
Files skipped from review as they are similar to previous changes (3)
  • src/web/Jordnaer/Features/Posts/CreatePostComponent.razor
  • src/web/Jordnaer/Features/Posts/PostCardComponent.razor
  • src/web/Jordnaer/Features/Posts/PostSearchForm.razor

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
src/web/Jordnaer/Features/GroupSearch/GroupSearchService.cs (1)

38-38: Consider comprehensive error handling strategy

While the TODO suggests adding try-catch, a more comprehensive error handling strategy should be considered:

  1. Database operation failures
  2. ZipCode service failures
  3. Memory pressure from large result sets
  4. Request timeouts
  5. Input validation

Consider implementing:

  • Result/Either pattern for error handling
  • Circuit breaker for external service calls
  • Pagination limits
  • Request timeouts
  • Input validation

Example implementation structure:

public record GroupSearchError(string Message, Exception? Exception = null);
public record GroupSearchResult<T>(T Data, GroupSearchError? Error = null);

public async Task<GroupSearchResult<List<GroupSlim>>> GetGroupsAsync(
    GroupSearchFilter filter,
    CancellationToken cancellationToken = default)
{
    try 
    {
        Guard.Against.Null(filter);
        Guard.Against.NegativeOrZero(filter.PageSize);
        Guard.Against.Negative(filter.PageNumber);

        // ... existing logic ...
    }
    catch (DbException ex)
    {
        return new(null, new GroupSearchError("Database error occurred", ex));
    }
    catch (OperationCanceledException)
    {
        return new(null, new GroupSearchError("Request was cancelled"));
    }
    catch (Exception ex)
    {
        return new(null, new GroupSearchError("An unexpected error occurred", ex));
    }
}
src/web/Jordnaer/Program.cs (1)

85-86: Consider adding Posts caching strategy

Similar to the existing UserSearchResultCache and GroupSearchResultCache, consider implementing a caching mechanism for post search results to improve performance.

Example implementation:

builder.Services.AddScoped<PostSearchResultCache>();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8a40302 and 14031d3.

📒 Files selected for processing (5)
  • src/web/Jordnaer/Features/GroupSearch/GroupSearchService.cs (1 hunks)
  • src/web/Jordnaer/Features/UserSearch/UserSearchService.cs (1 hunks)
  • src/web/Jordnaer/Program.cs (2 hunks)
  • src/web/Jordnaer/appsettings.Development.json (2 hunks)
  • src/web/Jordnaer/appsettings.json (1 hunks)
🔇 Additional comments (7)
src/web/Jordnaer/appsettings.json (2)

20-21: LGTM! Good logging configuration.

Setting MudBlazor's minimum log level to Warning aligns well with other third-party components and helps reduce noise in the logs.


Line range hint 4-11: Verify Posts feature flag configuration.

Given that this PR is titled "Feature/posts", should the Posts feature flag be enabled by default? Currently, it's set to false.

✅ Verification successful

The Posts feature flag configuration is correctly set

The Posts feature flag is enabled (true) in appsettings.Development.json while being disabled (false) in the base appsettings.json. This is a common and correct configuration pattern where features are disabled by default in the base configuration but can be enabled in specific environments like development.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for Posts feature usage across the codebase

# Look for Posts feature flag checks
rg -A 2 "Posts.*feature" 

# Look for feature management configuration in development settings
cat src/web/Jordnaer/appsettings.Development.json

Length of output: 546

src/web/Jordnaer/Features/UserSearch/UserSearchService.cs (1)

63-64: ⚠️ Potential issue

Address memory and performance concerns with a comprehensive solution

The TODOs highlight two critical issues:

  1. High memory usage (60+MB)
  2. Need for error handling

Consider these improvements:

  1. Replace EF Core with Dapper for this specific query:
public async Task<UserSearchResult> GetUsersAsync(UserSearchFilter filter, CancellationToken cancellationToken)
{
    const string sql = @"
        SELECT u.ProfilePictureUrl, u.UserName, u.FirstName, u.LastName,
               u.ZipCode, u.City,
               c.Name as CategoryName,
               ch.FirstName as ChildFirstName, ch.LastName as ChildLastName,
               ch.Gender, ch.DateOfBirth, ch.Age
        FROM UserProfiles u
        LEFT JOIN UserCategories uc ON u.Id = uc.UserId
        LEFT JOIN Categories c ON uc.CategoryId = c.Id
        LEFT JOIN ChildProfiles ch ON u.Id = ch.UserId
        WHERE @Skip < @Take
        ORDER BY u.CreatedUtc
        OFFSET @Skip ROWS
        FETCH NEXT @Take ROWS ONLY";

    using var connection = new SqlConnection(_connectionString);
    var userDictionary = new Dictionary<string, UserDto>();
    
    await connection.QueryAsync<UserDto, CategoryDto, ChildDto, UserDto>(
        sql,
        (user, category, child) =>
        {
            if (!userDictionary.TryGetValue(user.UserName, out var userEntry))
            {
                userEntry = user;
                userEntry.Categories = new List<string>();
                userEntry.Children = new List<ChildDto>();
                userDictionary.Add(user.UserName, userEntry);
            }
            
            if (category != null && !userEntry.Categories.Contains(category.Name))
                userEntry.Categories.Add(category.Name);
                
            if (child != null && !userEntry.Children.Any(c => c.FirstName == child.FirstName))
                userEntry.Children.Add(child);
                
            return userEntry;
        },
        new { Skip = (filter.PageNumber - 1) * filter.PageSize, Take = filter.PageSize },
        splitOn: "CategoryName,ChildFirstName"
    );
    
    return new UserSearchResult 
    { 
        Users = userDictionary.Values.ToList(),
        TotalCount = await GetTotalCountAsync(filter)
    };
}
  1. Implement proper error handling as suggested in the GroupSearchService review.

Let's verify the impact of the current implementation:

src/web/Jordnaer/appsettings.Development.json (2)

5-5: LGTM: Posts feature flag enabled

The feature flag change aligns with the PR objective to introduce Posts functionality.


Line range hint 1-21: Verify impact of DataForsyningen removal

The AI summary indicates that the "DataForsyningen" section was removed. Let's verify if this removal impacts any existing functionality.

src/web/Jordnaer/Program.cs (2)

24-25: LGTM: Feature imports added

The new using statements for Posts features are properly organized with other feature imports.


85-86: Verify Posts feature dependencies

The service registrations look good, but let's verify if all required dependencies for the Posts feature are properly configured.

✅ Verification successful

Let me gather more information about the Post-related services and their implementations.


Let me check for the Post entity and related models to ensure all dependencies are properly configured.


Based on the comprehensive analysis of the codebase, I can now provide the final response:

Posts feature dependencies are properly configured

The Posts feature has all required dependencies properly set up:

  • Database configuration is complete with Post and GroupPost entities and their relationships
  • Service registrations for both IPostService and IPostSearchService are correctly configured
  • Entity model includes necessary navigation properties and validations
  • Search functionality includes proper filtering and pagination support
  • Proper DTOs and mapping extensions are in place
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check Posts feature implementation
ast-grep --pattern 'public interface IPostService'
ast-grep --pattern 'public interface IPostSearchService'

# Check for any required database configurations
rg -l "Posts" --type cs | xargs rg "DbSet|IEntity|Migration"

Length of output: 2841


Script:

#!/bin/bash
# Check for Post service implementations and usages
rg -l "PostService" --type cs | xargs cat

# Check for Post-related models and their properties
rg -l "Post[\.cs|\.cs]" --type cs | xargs cat

# Check for any Post-related configurations or mappings
rg -l "Post" --type cs | xargs rg "Configure|CreateMap|builder\.Services"

Length of output: 34749


Script:

#!/bin/bash
# Check Post entity and related models
rg -l "class Post" --type cs | xargs cat

# Check for any Post-related migrations
rg -l "Migration" --type cs | xargs rg "Post"

# Check for any Post-related mappings or configurations
rg -l "IEntityTypeConfiguration|OnModelCreating" --type cs | xargs rg "Post"

Length of output: 10782

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (7)
src/web/Jordnaer/Pages/Groups/Members.razor (4)

3-5: Concrete DI reduces testability; confirm intentional interface removal.

Injecting GroupService directly couples the page to the implementation. If the interface removal is permanent across the solution, ignore; otherwise prefer an abstraction for mocking. Also ensure CurrentUser is always resolved on this [Authorize] page.


15-16: Cell edit on row-click: verify UX doesn’t cause accidental edits.

EditMode=Cell with EditTrigger=OnRowClick can open editors when users click to select rows or press action buttons. Consider EditTrigger.OnCellClick or disabling row edit when clicking action cells.


132-133: Sorting by dictionary key risks KeyNotFound on new enum values.

Use a safe lookup with fallback.

Apply:

-        _memberships = _memberships.OrderBy(x => SortOrder[x.MembershipStatus]).ToList();
+        _memberships = _memberships
+            .OrderBy(x => SortOrder.TryGetValue(x.MembershipStatus, out var order) ? order : int.MaxValue)
+            .ToList();

142-145: Propagate save result to cell editors; optionally refresh on failure.

Make SaveChangesAsync return a boolean and refresh data on failure to keep UI consistent.

Apply:

-    private async Task SaveCellChangesAsync(CellContext<GroupMembershipDto> context)
-    {
-        await SaveChangesAsync(context.Item);
-    }
+    private async Task SaveCellChangesAsync(CellContext<GroupMembershipDto> context)
+    {
+        var ok = await SaveChangesAsync(context.Item);
+        if (!ok)
+        {
+            // Minimal recovery; consider a targeted refresh API if available
+            _memberships = await GroupService.GetGroupMembershipsAsync(GroupName);
+            _memberships = _memberships
+                .OrderBy(x => SortOrder.TryGetValue(x.MembershipStatus, out var order) ? order : int.MaxValue)
+                .ToList();
+            StateHasChanged();
+        }
+    }
tests/web/Jordnaer.E2E.Tests/Jordnaer.E2E.Tests.csproj (1)

34-34: Relax overly strict FluentAssertions pin.

Exact pin [7.0.0] blocks patch fixes. Use a safe range to receive non-breaking patches.

Apply:

-    <PackageReference Include="FluentAssertions" Version="[7.0.0]" />
+    <PackageReference Include="FluentAssertions" Version="[7.0.0,7.1.0)" />
src/web/Jordnaer/Jordnaer.csproj (2)

13-14: Pre-release instrumentation in production.

HealthChecks.OpenTelemetry.Instrumentation is pinned to a -dev prerelease. Prefer a stable release to reduce supply-chain and stability risks.

Would you like me to propose a stable version once confirmed?


48-48: Make JetBrains.Annotations compile-only.

Prevent leaking annotations transitively and reduce closure size by marking as PrivateAssets.

-    <PackageReference Include="JetBrains.Annotations" Version="2025.2.1" />
+    <PackageReference Include="JetBrains.Annotations" Version="2025.2.1" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 09ce194 and 48a380b.

📒 Files selected for processing (5)
  • src/shared/Jordnaer.Shared/Jordnaer.Shared.csproj (1 hunks)
  • src/web/Jordnaer/Jordnaer.csproj (1 hunks)
  • src/web/Jordnaer/Pages/Groups/Members.razor (3 hunks)
  • tests/web/Jordnaer.E2E.Tests/Jordnaer.E2E.Tests.csproj (1 hunks)
  • tests/web/Jordnaer.Tests/Jordnaer.Tests.csproj (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/web/Jordnaer.Tests/Jordnaer.Tests.csproj
  • src/shared/Jordnaer.Shared/Jordnaer.Shared.csproj
🔇 Additional comments (8)
src/web/Jordnaer/Pages/Groups/Members.razor (2)

28-28: Enum display improvements look good.

ToDisplayName() is appropriate for user-facing text.

Also applies to: 43-43


49-110: Hide destructive actions for owners and gate by permissions
Wrap the “Fjern medlem” button in

@if (context.Item.OwnershipLevel != OwnershipLevel.Owner)
{
    <MudButton >Fjern medlem</MudButton>
}

(ensure your model actually exposes an OwnershipLevel.Owner value) and consider introducing a CanManageMembers flag to wrap every action button—even though the server must still enforce these checks.

src/web/Jordnaer/Jordnaer.csproj (6)

25-28: EF Core Tools correctly isolated.

PrivateAssets/IncludeAssets are set; avoids tool leakage into consumers. LGTM.


3-7: Confirm no preview-only syntax before removing LangVersion preview
The regex search returned no matches for preview-specific constructs; please manually verify that no C# preview features are used, then remove <LangVersion>preview</LangVersion> to avoid CI/SDK coupling issues.


33-37: Mediator 3.x upgrade – verify compatibility
Confirm that after updating to Mediator.Abstractions/SourceGenerator 3.0.1 (Jordnaer.csproj lines 33–37) all handler signatures (e.g. the INotificationHandler.Handle method in ExternalProfilePictureDownloader.cs) and the source-generated mediator code still compile and run as expected.


31-31: Verify SecurityHeaders integration
Upgrading NetEscapades.AspNetCore.SecurityHeaders to v1.1.0 introduces breaking changes. Found usage at Program.cs:107—ensure AddFrameOptionsDeny(), AddXssProtectionBlock(), and AddContentTypeOptionsNoSniff() still compile and enforce the expected headers.


57-58: No residual Jordnaer.Shared.Infrastructure references found – safe to remove the project reference.


42-44: No action needed: CodeBeam.MudBlazor.Extensions v8.2.4 supports MudBlazor >= 8.0.0, including 8.11.0 (nuget.org)

Comment thread src/web/Jordnaer/Pages/Groups/Members.razor Outdated
Comment thread src/web/Jordnaer/Pages/Groups/Members.razor Outdated
Comment thread src/web/Jordnaer/Pages/Groups/Members.razor Outdated
Comment thread src/web/Jordnaer/Pages/Groups/Members.razor
Comment thread src/web/Jordnaer/Pages/Groups/Members.razor Outdated
Comment thread tests/web/Jordnaer.E2E.Tests/Jordnaer.E2E.Tests.csproj Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/web/Jordnaer/Pages/Shared/TopBar.razor (1)

8-10: Feature-gated Posts button — verify flag wiring and route

Looks good. Ensure FeatureFlags.Posts is defined in configuration and that /posts is registered.

If Posts requires auth, consider wrapping the button in an Authorized view for clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 48a380b and 9988770.

📒 Files selected for processing (3)
  • src/web/Jordnaer/Features/Profile/DeleteUserComponent.razor (1 hunks)
  • src/web/Jordnaer/Pages/Profile/MyProfile.razor (1 hunks)
  • src/web/Jordnaer/Pages/Shared/TopBar.razor (1 hunks)
🔇 Additional comments (5)
src/web/Jordnaer/Features/Profile/DeleteUserComponent.razor (1)

7-13: UI: Switching to Outlined for the destructive trigger is reasonable

Makes the primary delete action less visually dominant while still clearly marked in red with a warning icon. No functional impact.

src/web/Jordnaer/Pages/Profile/MyProfile.razor (1)

124-129: I’ve added a grep to inspect the Logout.cshtml for an existing POST form. Awaiting output.

src/web/Jordnaer/Pages/Shared/TopBar.razor (3)

6-6: Minor formatting change

No behavioral impact.


12-17: Chat link within Authorized block

Reordering is fine; preserves auth scoping.


18-20: Whitespace/structure tweaks

No functional change.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/web/Jordnaer/Pages/Groups/Members.razor (1)

144-150: Sorting via dictionary index can throw on new/unknown enum values.

SortOrder[x.MembershipStatus] will throw if a new MembershipStatus is introduced. Use a safe fallback.

Apply the TryGetValue-based ordering in OnInitializedAsync (see next comment).

♻️ Duplicate comments (3)
src/web/Jordnaer/Pages/Groups/Members.razor (3)

166-181: Owner removal guard + UI rollback: LGTM.

Prevents demoting/removing owner and restores previous state on failure.


27-44: Owner/self guardrails implemented; also revert UI on failed save for ownership edits.

Great that edits are blocked for self and owners. Ensure the select reverts on persistence failure.

-ValueChanged="@(async (OwnershipLevel newValue) => { context.Item.OwnershipLevel = newValue; await SaveCellChangesAsync(context); })"
+ValueChanged="@(async (OwnershipLevel newValue) =>
+{
+    var prev = context.Item.OwnershipLevel;
+    context.Item.OwnershipLevel = newValue;
+    var ok = await SaveCellChangesAsync(context);
+    if (!ok) context.Item.OwnershipLevel = prev;
+})"

49-68: Permission guardrails mirrored; add same revert-on-failure pattern.

Apply the same optimistic-UI rollback to permission edits.

-ValueChanged="@(async (PermissionLevel newValue) => { context.Item.PermissionLevel = newValue; await SaveCellChangesAsync(context); })"
+ValueChanged="@(async (PermissionLevel newValue) =>
+{
+    var prev = context.Item.PermissionLevel;
+    context.Item.PermissionLevel = newValue;
+    var ok = await SaveCellChangesAsync(context);
+    if (!ok) context.Item.PermissionLevel = prev;
+})"
🧹 Nitpick comments (6)
src/web/Jordnaer/wwwroot/css/app.css (1)

106-110: Scope the utility class to the datagrid and align with theme/typography; add line-height for header stability

  • Reduce bleed and increase specificity by scoping to the datagrid container.
  • Prefer relative letter-spacing so it scales with font size; add line-height to avoid header jitter/overflow with sort/filter icons.
  • Consider using your theme/typography utilities instead of hardcoded size/weight for consistency.

Please confirm this class is applied via the column header class hooks and that header height/icon alignment remains consistent at common breakpoints.

-.mud-datagrid-header-bold {
-    font-weight: 800;
-    font-size: 1.2rem;
-    letter-spacing: 0.5px;
-}
+.mud-datagrid .mud-datagrid-header-bold {
+    font-weight: 800; /* or a theme token/utility */
+    font-size: 1.2rem; /* align with your typography scale */
+    letter-spacing: 0.03em; /* scales with font size */
+    line-height: 1.2; /* keeps row compact/aligned */
+}
src/web/Jordnaer/Pages/Groups/Members.razor (5)

3-6: DI changes look good; consider adding logging and dialogs.

Concrete GroupService + CurrentUser injection LGTM. Add ILogger (for exception logging) and IDialogService (for confirms) to support later suggestions.

 @inject GroupService GroupService
 @inject ISnackbar Snackbar
 @inject CurrentUser CurrentUser
+@inject ILogger<Members> Logger
+@inject IDialogService DialogService

12-15: Danish compound nouns/phrasing.

Minor UX polish: use compound forms.

-<MudText Typo="Typo.h4" Class="mb-4">Medlems oversigt for gruppen '@GroupName'</MudText>
+<MudText Typo="Typo.h4" Class="mb-4">Medlemsoversigt for gruppen '@GroupName'</MudText>

-<PropertyColumn Property="x => x.OwnershipLevel" Title="Ejerskabs Niveau" HeaderStyle="@HeaderStyles">
+<PropertyColumn Property="x => x.OwnershipLevel" Title="Ejerskabsniveau" HeaderStyle="@HeaderStyles">

-<PropertyColumn Property="x => x.PermissionLevel" Title="Adgangs Niveau" HeaderStyle="@HeaderStyles">
+<PropertyColumn Property="x => x.PermissionLevel" Title="Adgangsniveau" HeaderStyle="@HeaderStyles">

-<PropertyColumn Property="x => x.MembershipStatus" Title="Medlemskabs Status" HeaderStyle="@HeaderStyles">
+<PropertyColumn Property="x => x.MembershipStatus" Title="Medlemskabsstatus" HeaderStyle="@HeaderStyles">

Also applies to: 24-24, 47-47, 71-71


71-103: Clarify status label for “PendingApprovalFromUser”.

Make it explicit that approval is pending from the user.

-    case MembershipStatus.PendingApprovalFromUser:
-        <span class="text-warning">Afventer godkendelse</span>
+    case MembershipStatus.PendingApprovalFromUser:
+        <span class="text-warning">Afventer brugerens godkendelse</span>

104-139: Confirm destructive actions and guard against double clicks.

Show a confirmation before remove/reject and prevent rapid re-clicks.

-<MudButton Color="Color.Error" Variant="Variant.Filled" Size="Size.Small" Class="ml-2"
-           OnClick="@(async () => await ChangeMembershipStatusAsync(context.Item, MembershipStatus.Rejected))">
+<MudButton Color="Color.Error" Variant="Variant.Filled" Size="Size.Small" Class="ml-2"
+           OnClick="@(async () =>
+           {
+               var confirm = await DialogService.ShowMessageBox(
+                   "Fjern medlem",
+                   $"Fjern {context.Item.UserDisplayName} fra gruppen?",
+                   yesText: "Fjern", cancelText: "Annuller");
+               if (confirm == true)
+                   await ChangeMembershipStatusAsync(context.Item, MembershipStatus.Rejected);
+           })">

Optionally track an in-flight set (HashSet busyIds) to disable buttons while saving.


184-200: Improve messaging and log exceptions.

Avoid English possessive in Danish and log caught exceptions.

-            updateResult.Switch(
-                success => { Snackbar.Add($"{item.UserDisplayName}'s medlemskab blev opdateret.", Severity.Success); updateSuccessful = true; },
+            updateResult.Switch(
+                success => { Snackbar.Add($"Medlemskab for {item.UserDisplayName} blev opdateret.", Severity.Success); updateSuccessful = true; },
                 error => Snackbar.Add(error.Value, Severity.Error));
@@
-        catch (Exception)
+        catch (Exception ex)
         {
+            Logger?.LogError(ex, "Fejl under opdatering af medlemskab for UserProfileId={UserProfileId}", item.UserProfileId);
             Snackbar.Add("Der skete en fejl under opdatering. Prøv igen.", Severity.Error);
             return false;
         }

Note: Requires @inject ILogger<Members> Logger (added above).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9988770 and 3ce112b.

📒 Files selected for processing (2)
  • src/web/Jordnaer/Pages/Groups/Members.razor (2 hunks)
  • src/web/Jordnaer/wwwroot/css/app.css (1 hunks)
🔇 Additional comments (1)
src/web/Jordnaer/Pages/Groups/Members.razor (1)

19-22: Grid config: LGTM.

Cell editing with row-click trigger and loading/borders reads well.

Comment thread src/web/Jordnaer/Pages/Groups/Members.razor
Comment thread src/web/Jordnaer/Pages/Groups/Members.razor
Comment thread src/web/Jordnaer/Pages/Groups/Members.razor Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
tests/web/Jordnaer.E2E.Tests/Jordnaer.E2E.Tests.csproj (1)

23-23: Ensure CI installs Playwright 1.54 browsers before E2E.

Align runners with Microsoft.Playwright.NUnit 1.54.0 and add an install step (with-deps on Linux). Repeating prior guidance for visibility.

Run to confirm your workflows have an install step and version alignment:

#!/bin/bash
# Check for browser install steps
rg -n -C2 -g ".github/workflows/**" -P '(playwright\s+install|dotnet\s+playwright\s+install)'

# Check explicit versioning
rg -n -g ".github/workflows/**" -P 'PLAYWRIGHT_VERSION|Microsoft\.Playwright(\.NUnit)?\s*[:=]\s*1\.54'
🧹 Nitpick comments (3)
tests/web/Jordnaer.E2E.Tests/Jordnaer.E2E.Tests.csproj (2)

30-33: Add coverage collection in CI to leverage coverlet.collector.

Ensure your workflow invokes: dotnet test --collect:"XPlat Code Coverage" (or a .runsettings with DataCollector).


34-34: Nit: avoid exact pin and hide FA from transitive closure.

Pinning to [7.0.0] is rigid and missing PrivateAssets. Suggest:

-    <PackageReference Include="FluentAssertions" Version="[7.0.0]" />
+    <PackageReference Include="FluentAssertions" Version="7.0.0">
+      <PrivateAssets>all</PrivateAssets>
+    </PackageReference>
.github/workflows/website_frontend_ci.yml (1)

42-47: Optional: add artifact retention to control storage costs

Default retention is long; consider a shorter period for screenshots to reduce storage.

       uses: actions/upload-artifact@v4
       with:
         name: screenshots
         path: "${{ env.WORKING_DIRECTORY }}/bin/Debug/screenshots"
+        retention-days: 7
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3ce112b and 319e1d7.

📒 Files selected for processing (4)
  • .github/workflows/website_frontend_ci.yml (1 hunks)
  • src/shared/Jordnaer.Shared/Extensions/EnumExtensions.cs (1 hunks)
  • src/web/Jordnaer/_Imports.razor (2 hunks)
  • tests/web/Jordnaer.E2E.Tests/Jordnaer.E2E.Tests.csproj (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/shared/Jordnaer.Shared/Extensions/EnumExtensions.cs
🧰 Additional context used
🪛 actionlint (1.7.7)
.github/workflows/website_frontend_ci.yml

21-21: context "env" is not allowed here. available contexts are "github", "inputs", "matrix", "needs", "strategy", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)

🔇 Additional comments (7)
tests/web/Jordnaer.E2E.Tests/Jordnaer.E2E.Tests.csproj (4)

3-11: Project props look good for a test project.

Targeting net9.0, test flags, and NoWarn entries are fine.


14-17: GitHubActionsTestLogger config is correct.

PrivateAssets/IncludeAssets are appropriate.


18-22: Config packages upgraded consistently to 9.0.8.

No issues spotted.


24-29: NUnit + Adapter versions are compatible.

4.4.0 with adapter 5.1.0 and Test SDK 17.14.1 is a sane combo.

.github/workflows/website_frontend_ci.yml (1)

39-40: Verify secret names exist exactly as referenced

Secrets are name-sensitive and typically uppercase with underscores. Please confirm the repository/environment secrets match these identifiers or rename the references.

Would you like a quick script to list available repo and environment secrets to double-check naming?

src/web/Jordnaer/_Imports.razor (2)

36-36: Global Shared.Extensions import: verify no ambiguous extension methods with Jordnaer.Extensions

With both Jordnaer.Extensions (Line 9) and Jordnaer.Shared.Extensions (Line 36) in global scope, overlapping extension method names could cause ambiguous call errors. If you hit CS0121, either qualify the call with the static class or scope one of these imports to the affected pages/components.


22-24: Global @using directives safe: no .razor component collisions detected
Only the Posts feature contains .razor files (4); PostSearch and GroupPosts have none, and no duplicate basenames were found across the three namespaces.
Optional: alias namespaces (e.g. @using Posts = Jordnaer.Features.Posts) if future component-name collisions arise.

Comment thread .github/workflows/website_frontend_ci.yml Outdated
Comment thread .github/workflows/website_frontend_ci.yml Outdated
@NielsPilgaard NielsPilgaard merged commit 0b9bdf0 into main Aug 29, 2025
2 checks passed
@NielsPilgaard NielsPilgaard deleted the feature/posts branch August 29, 2025 21:16
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Jordnaer Community Website Aug 29, 2025
@NielsPilgaard

Copy link
Copy Markdown
Owner Author

The posts feature is not done, but I don't want to stay on this branch forever 😂

This was referenced Dec 22, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant