Skip to content

Conversation

@linkdotnet
Copy link
Owner

No description provided.

Copilot AI review requested due to automatic review settings January 9, 2026 21:48
@linkdotnet linkdotnet merged commit a1936cb into master Jan 9, 2026
7 checks passed
@linkdotnet linkdotnet deleted the feat/templates branch January 9, 2026 21:51
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request adds a template management feature for the blog post editor, allowing users to save, load, and manage reusable blog post templates (title, short description, and content).

Key changes:

  • Introduces a new BlogPostTemplate domain entity with Create and Update methods
  • Adds database migration and Entity Framework configuration for template persistence
  • Implements an interactive dialog component (AddTemplateDialog) with autocomplete and keyboard navigation
  • Integrates template functionality into the blog post editor UI with dropdown menu access

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/LinkDotNet.Blog.Domain/BlogPostTemplate.cs New domain entity for blog post templates with factory method
src/LinkDotNet.Blog.Infrastructure/Persistence/Sql/Mapping/BlogPostTemplateConfiguration.cs Entity Framework configuration for BlogPostTemplate
src/LinkDotNet.Blog.Infrastructure/Persistence/Sql/BlogDbContext.cs Adds BlogPostTemplates DbSet to database context
src/LinkDotNet.Blog.Infrastructure/Migrations/20260109211327_AddBlogPostTemplate.cs Database migration creating BlogPostTemplates table
src/LinkDotNet.Blog.Infrastructure/Migrations/20260109211327_AddBlogPostTemplate.Designer.cs Auto-generated migration metadata
src/LinkDotNet.Blog.Infrastructure/Migrations/BlogDbContextModelSnapshot.cs Updated snapshot reflecting new table and EF Core 9 changes
src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/CreateNewBlogPost.razor Integrates template functionality with save/load operations
src/LinkDotNet.Blog.Web/Features/Admin/BlogPostEditor/Components/AddTemplateDialog.razor New dialog component for template management with autocomplete
tests/LinkDotNet.Blog.UnitTests/Web/Features/Admin/BlogPostEditor/Components/CreateNewBlogPostTests.cs Unit tests for template update and delete operations
tests/LinkDotNet.Blog.IntegrationTests/Web/Features/Admin/BlogPostEditor/CreateNewBlogPostPageTests.cs Integration test for template loading functionality
tests/LinkDotNet.Blog.IntegrationTests/Web/Features/Admin/BlogPostEditor/UpdateBlogPostPageTests.cs Updates tests to include template repository dependency
Files not reviewed (1)
  • src/LinkDotNet.Blog.Infrastructure/Migrations/20260109211327_AddBlogPostTemplate.Designer.cs: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +15 to +24
public static BlogPostTemplate Create(string name, string title, string shortDescription, string content)
{
return new BlogPostTemplate
{
Name = name,
Title = title,
ShortDescription = shortDescription,
Content = content
};
}
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The Create method lacks input validation. Based on the ShortCode entity pattern in this codebase (which includes ArgumentException.ThrowIfNullOrWhiteSpace for name validation), this method should validate that the name parameter is not null or whitespace before creating the entity. Without validation, invalid entities can be created and persisted to the database.

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +32
public void Update(string name, string title, string shortDescription, string content)
{
Name = name;
Title = title;
ShortDescription = shortDescription;
Content = content;
}
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The Update method lacks input validation. Following the pattern from ShortCode.Update in this codebase, this method should validate that the name parameter is not null or whitespace. Without validation, existing entities can be updated with invalid data.

Copilot uses AI. Check for mistakes.
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(256)",
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The Down migration incorrectly attempts to revert the AuthorName column type from TEXT back to nvarchar(256). However, based on the prior migration (20250830110439_AddAuthorNameInBlogPost.cs), the original type was nvarchar(256) which is SQL Server-specific, but this migration uses TEXT which is SQLite-specific. The Down method should revert to TEXT (not nvarchar) since the current database schema uses TEXT. This mismatch will cause the migration rollback to fail.

Suggested change
oldType: "nvarchar(256)",
oldType: "TEXT",

Copilot uses AI. Check for mistakes.
{
model.Title = template.Title;
model.ShortDescription = template.ShortDescription;
model.Content = template.Content;
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The LoadTemplate method does not mark the model as dirty after loading template values. When a template is loaded, it modifies the Title, ShortDescription, and Content properties of the model, which represents unsaved changes. The model should be marked as dirty to trigger the unsaved changes warning and navigation lock, similar to how user input changes are handled.

Suggested change
model.Content = template.Content;
model.Content = template.Content;
model.IsDirty = true;

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +33
using System;

namespace LinkDotNet.Blog.Domain;

public sealed class BlogPostTemplate : Entity
{
public string Name { get; private set; } = default!;

public string Title { get; private set; } = default!;

public string ShortDescription { get; private set; } = default!;

public string Content { get; private set; } = default!;

public static BlogPostTemplate Create(string name, string title, string shortDescription, string content)
{
return new BlogPostTemplate
{
Name = name,
Title = title,
ShortDescription = shortDescription,
Content = content
};
}

public void Update(string name, string title, string shortDescription, string content)
{
Name = name;
Title = title;
ShortDescription = shortDescription;
Content = content;
}
}
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

Missing test coverage for the BlogPostTemplate domain entity. Other domain entities in this codebase have corresponding unit tests (e.g., SkillTests.cs, TalkTests.cs, BlogPostTests.cs), but there are no tests for BlogPostTemplate's Create and Update methods. Tests should be added to verify the entity's behavior, especially if validation is added to these methods.

Copilot uses AI. Check for mistakes.
Comment on lines +135 to +139
private async Task HandleFocusOut(FocusEventArgs args)
{
await Task.Delay(150);
isOpen = false;
await InvokeAsync(StateHasChanged);
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The HandleFocusOut method uses a hardcoded 150ms delay to handle race conditions with click events. This is a fragile approach that may not work reliably across different devices or browsers. A more robust solution would be to use the relatedTarget from FocusEventArgs to check if focus moved to an element within the dropdown, or use proper event handling with mousedown instead of click to avoid the race condition entirely.

Suggested change
private async Task HandleFocusOut(FocusEventArgs args)
{
await Task.Delay(150);
isOpen = false;
await InvokeAsync(StateHasChanged);
private Task HandleFocusOut(FocusEventArgs args)
{
isOpen = false;
StateHasChanged();
return Task.CompletedTask;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants