-
-
Notifications
You must be signed in to change notification settings - Fork 87
feat: Added templates for blog post editor #481
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
Conversation
There was a problem hiding this 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
BlogPostTemplatedomain 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.
| public static BlogPostTemplate Create(string name, string title, string shortDescription, string content) | ||
| { | ||
| return new BlogPostTemplate | ||
| { | ||
| Name = name, | ||
| Title = title, | ||
| ShortDescription = shortDescription, | ||
| Content = content | ||
| }; | ||
| } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| public void Update(string name, string title, string shortDescription, string content) | ||
| { | ||
| Name = name; | ||
| Title = title; | ||
| ShortDescription = shortDescription; | ||
| Content = content; | ||
| } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| maxLength: 256, | ||
| nullable: true, | ||
| oldClrType: typeof(string), | ||
| oldType: "nvarchar(256)", |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| oldType: "nvarchar(256)", | |
| oldType: "TEXT", |
| { | ||
| model.Title = template.Title; | ||
| model.ShortDescription = template.ShortDescription; | ||
| model.Content = template.Content; |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| model.Content = template.Content; | |
| model.Content = template.Content; | |
| model.IsDirty = true; |
| 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; | ||
| } | ||
| } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| private async Task HandleFocusOut(FocusEventArgs args) | ||
| { | ||
| await Task.Delay(150); | ||
| isOpen = false; | ||
| await InvokeAsync(StateHasChanged); |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
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.
| 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; |
No description provided.