Skip to content

Message Templates v2#122

Merged
soliktomasz merged 3 commits into
mainfrom
codex/issue-115-message-templates-v2
May 31, 2026
Merged

Message Templates v2#122
soliktomasz merged 3 commits into
mainfrom
codex/issue-115-message-templates-v2

Conversation

@soliktomasz
Copy link
Copy Markdown
Owner

@soliktomasz soliktomasz commented May 31, 2026

Summary

  • Add parameterized saved message templates with all-field {{Token}} replacement and missing-value validation before send.
  • Add saved template metadata for categories/tags, quick search, duplication, and update-loaded-template flow.
  • Wire template controls into the send/load/save dialogs and cover token/model/view-model behavior with tests.

Validation

  • dotnet build
  • dotnet test

Summary by CodeRabbit

  • New Features

    • Template messaging with token extraction/substitution across all message fields (including custom properties).
    • Persisted template metadata: category, tags, and token values; duplicate and update templates.
    • UI: category/tags inputs, template search/filtering, duplicate/update actions, and editable template-parameter panel.
  • Tests

    • Added extensive tests for template engine, model duplication/metadata, and view-model workflows (save, load, send, filter).

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 31, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2ae2d6cd-4b16-489d-bea0-4fb1dfb2155c

📥 Commits

Reviewing files that changed from the base of the PR and between fa2b9c6 and c38d378.

📒 Files selected for processing (1)
  • BusLane/Converters/StringToBoolConverter.cs
✅ Files skipped from review due to trivial changes (1)
  • BusLane/Converters/StringToBoolConverter.cs

📝 Walkthrough

Walkthrough

Adds template-token support, template metadata (category/tags), a MessageTemplateEngine, SendMessageViewModel integration (save/load/duplicate/update/search, token editors, persistence), dialog UI updates, a StringToBoolConverter, and unit tests for models, engine, and view-model flows.

Changes

Message Templating Feature

Layer / File(s) Summary
Template Data Model and Contract
BusLane/Models/SavedMessage.cs
SavedMessage gains Category, Tags, ensured TokenValues/CustomProperties; Duplicate() deep-copies template metadata; CustomProperty implements INotifyPropertyChanged; TemplateTokenValue added.
Template Engine Implementation
BusLane/Services/Templates/MessageTemplateEngine.cs
Adds ExtractTokenNames, FindMissingTokenValues, and Apply to scan templatable fields (including custom properties) for {{token}}, detect missing/blank values, and apply case-insensitive replacements with null-safety.
ViewModel Init and State
BusLane/ViewModels/SendMessageViewModel.cs
Constructor accepts optional savedMessagesPath; adds observable template UI state (SaveMessageCategory, SaveMessageTags, TemplateSearchQuery, dialog flags, ActiveTemplate), TemplateTokenValues, FilteredSavedMessages, and HasActiveTemplate.
ViewModel Send Workflow
BusLane/ViewModels/SendMessageViewModel.cs
SendAsync now builds a SavedMessage from form state, validates required template values (sets ErrorMessage if missing), applies template substitutions, and sends the resolved message (body, content type, custom properties, scheduling/TTL).
ViewModel Persistence, Save/Load/Duplicate/Update Commands
BusLane/ViewModels/SendMessageViewModel.cs
SaveMessage persists Category, parsed Tags, and TokenValues; LoadMessage sets ActiveTemplate and token editors; DuplicateSavedMessage and UpdateActiveTemplate implemented; persistence uses instance _savedMessagesPath and AppPaths.CreateSecureFile; helpers for token refresh, tag parsing, and template-aware search added; ClearForm clears template state.
Dialog UI: Save & Compose
BusLane/Views/Dialogs/SaveMessageDialog.axaml, BusLane/Views/Dialogs/SendMessageDialog.axaml
Save dialog adds Category and Tags inputs bound to ViewModel; Compose tab renders TemplateTokenValues as editable parameter inputs when tokens exist.
Dialog UI: Search, Load, Duplicate, Update
BusLane/Views/Dialogs/LoadMessageDialog.axaml, BusLane/Views/Dialogs/SendMessageDialog.axaml
Add TemplateSearchQuery textbox; switch template lists to FilteredSavedMessages; item template shows Category and Tags.Count; add Duplicate action button and Update toolbar button when active template is present.
UI Converter
BusLane/Converters/StringToBoolConverter.cs
Adds one-way StringToBoolConverter.Instance that returns true for non-empty strings and throws on ConvertBack.
Unit Tests: Models, Engine, ViewModel
BusLane.Tests/Models/ModelTests.cs, BusLane.Tests/Services/Templates/MessageTemplateEngineTests.cs, BusLane.Tests/ViewModels/SendMessageViewModelTests.cs
SavedMessage tests updated for defaults and Duplicate behavior; MessageTemplateEngineTests cover extraction, missing detection, and Apply; SendMessageViewModelTests cover save/load/filter/send/duplicate/update flows and interaction with IServiceBusOperations.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Dialog
  participant ViewModel as SendMessageViewModel
  participant Engine as MessageTemplateEngine
  participant ServiceBus

  User->>Dialog: Load saved template
  Dialog->>ViewModel: LoadMessageCommand(activeTemplate)
  ViewModel->>Engine: ExtractTokenNames(activeTemplate)
  Engine-->>ViewModel: token list
  ViewModel->>Dialog: Render TemplateTokenValues
  User->>Dialog: Enter token values
  Dialog->>ViewModel: SendAsync()
  ViewModel->>Engine: FindMissingTokenValues(message, values)
  Engine-->>ViewModel: missing tokens (or empty)
  alt no missing
    ViewModel->>Engine: Apply(message, values)
    Engine-->>ViewModel: resolved message
    ViewModel->>ServiceBus: SendMessageAsync(resolved message)
    ServiceBus-->>ViewModel: send result
    ViewModel->>Dialog: Close + status
  else missing tokens
    ViewModel-->>Dialog: Show ErrorMessage (missing tokens)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Poem

A rabbit tweaked templates late at night,
Tokens trimmed and tags put right,
Duplicates copy without a fuss—
Hop, replace, and send; rejoice for us! 🐇✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Message Templates v2' is vague and generic, using a version suffix without clearly describing the main change or feature addition. Consider a more descriptive title such as 'Add parameterized message templates with token substitution and metadata' to better convey the primary change.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/issue-115-message-templates-v2

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@soliktomasz soliktomasz changed the title [codex] Message Templates v2 Message Templates v2 May 31, 2026
@soliktomasz soliktomasz marked this pull request as ready for review May 31, 2026 08:21
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

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

Caution

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

⚠️ Outside diff range comments (4)
BusLane/Views/Dialogs/LoadMessageDialog.axaml (1)

84-86: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Empty-state vs. filtered list mismatch (same as SendMessageDialog).

The ListBox now binds to FilteredSavedMessages (Line 100), but this empty-state border is still driven by SavedMessages.Count. A search that filters everything out shows neither rows nor the empty state. Bind to the filtered collection so the empty/no-results feedback stays correct.

🔧 Proposed fix
                 <Border DockPanel.Dock="Top"
                         Classes="empty-state"
-                            IsVisible="{Binding !SendMessageViewModel.SavedMessages.Count}"
+                            IsVisible="{Binding !SendMessageViewModel.FilteredSavedMessages.Count}"
                         Margin="16">
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/Views/Dialogs/LoadMessageDialog.axaml` around lines 84 - 86, The
empty-state Border's visibility is still driven by
SendMessageViewModel.SavedMessages.Count while the ListBox uses
FilteredSavedMessages; update the Border's IsVisible binding to use the filtered
collection (e.g. bind to SendMessageViewModel.FilteredSavedMessages.Count or a
boolean exposed for "HasFilteredItems") so the empty/no-results UI matches the
ListBox contents (look for the Border with Classes="empty-state" and the ListBox
bound to FilteredSavedMessages).
BusLane/Views/Dialogs/SendMessageDialog.axaml (1)

123-127: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Empty-state no longer matches the filtered list.

The list switched to FilteredSavedMessages (Line 85), but this "No saved templates yet" placeholder is still gated on SavedMessages.Count. When a user types a query that matches nothing, the ItemsControl renders empty and the placeholder stays hidden, leaving a blank flyout with no feedback. Bind the placeholder to the filtered collection instead.

🔧 Proposed fix
                                                     <TextBlock Text="No saved templates yet"
                                                                Classes="caption"
                                                                HorizontalAlignment="Center"
                                                                Margin="0,12"
-                                                                IsVisible="{Binding !SendMessageViewModel.SavedMessages.Count}"/>
+                                                                IsVisible="{Binding !SendMessageViewModel.FilteredSavedMessages.Count}"/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/Views/Dialogs/SendMessageDialog.axaml` around lines 123 - 127, The
empty-state TextBlock is still bound to SavedMessages.Count so it doesn't show
when the filtered list is empty; change its IsVisible binding to use the
filtered collection (e.g. bind IsVisible to
"!SendMessageViewModel.FilteredSavedMessages.Count") so the "No saved templates
yet" placeholder appears when FilteredSavedMessages is empty; update the
TextBlock in SendMessageDialog.axaml that currently references
SavedMessages.Count to reference FilteredSavedMessages.Count instead.
BusLane/ViewModels/SendMessageViewModel.cs (2)

243-249: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear the active template when deleting it.

If the removed item is ActiveTemplate, HasActiveTemplate stays true and UpdateActiveTemplate can still mutate that detached object, then report success even though it is no longer in SavedMessages.

Suggested fix
 private void DeleteSavedMessage(SavedMessage message)
 {
+    var isActiveTemplate = ActiveTemplate?.Id == message.Id;
+
     SavedMessages.Remove(message);
+    if (isActiveTemplate)
+    {
+        TemplateTokenValues.Clear();
+        ActiveTemplate = null;
+    }
+
     OnPropertyChanged(nameof(FilteredSavedMessages));
     PersistSavedMessages();
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/ViewModels/SendMessageViewModel.cs` around lines 243 - 249, The
DeleteSavedMessage method currently removes the message but doesn't clear
ActiveTemplate, leaving HasActiveTemplate true and allowing UpdateActiveTemplate
to mutate a removed object; modify DeleteSavedMessage (in SendMessageViewModel)
so that if the removed SavedMessage equals ActiveTemplate you set ActiveTemplate
to null (or call UpdateActiveTemplate(null)/clear the active template via its
setter), raise PropertyChanged for HasActiveTemplate and FilteredSavedMessages
as needed, then call PersistSavedMessages; this ensures the active template is
cleared before persisting and prevents operations on a detached object.

549-555: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Surface persistence failures instead of swallowing them.

SaveMessage, DeleteSavedMessage, DuplicateSavedMessage, and UpdateActiveTemplate all assume this write succeeds and immediately update the UI as if disk state is durable. If CreateSecureFile fails, the in-memory collection diverges from disk and the user only discovers the loss after restart.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/ViewModels/SendMessageViewModel.cs` around lines 549 - 555,
PersistSavedMessages currently swallows exceptions from
AppPaths.CreateSecureFile causing in-memory SavedMessages (and callers
SaveMessage, DeleteSavedMessage, DuplicateSavedMessage, UpdateActiveTemplate) to
diverge from disk; change PersistSavedMessages to propagate failures (either by
throwing the caught exception or returning a failure result) and ensure callers
handle that result by rolling back the in-memory change and surfacing an error
to the UI/log. Specifically, update PersistSavedMessages to not catch-and-ignore
exceptions from Serialize or AppPaths.CreateSecureFile (or to return
bool/Result), and then modify SaveMessage, DeleteSavedMessage,
DuplicateSavedMessage, and UpdateActiveTemplate to detect persistence failure
and revert SavedMessages and any UI state changes (and notify the user via the
existing error reporting mechanism) so disk/write errors are visible and
memory/disk stay consistent.
🧹 Nitpick comments (1)
BusLane/Models/SavedMessage.cs (1)

25-47: ⚡ Quick win

Add XML doc comments to new public API surface.

SavedMessage.Duplicate(...) (Line 25) and TemplateTokenValue (Line 56) are public and currently undocumented; please add XML docs for these public members.

As per coding guidelines, "Use XML doc comments for public classes, methods, and key regions".

Also applies to: 56-60

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/Models/SavedMessage.cs` around lines 25 - 47, Add XML documentation
for the new public API members: add a summary, param and returns tags to
SavedMessage.Duplicate(string? name = null) explaining that it creates and
returns a copy of the SavedMessage with an optional new name (describe that Name
defaults to "{Name} Copy" when name is null), and add XML docs for
TemplateTokenValue (describe what the type/property represents and any
usage/constraints). Ensure the XML comments are placed immediately above the
method declaration for Duplicate and above the TemplateTokenValue declaration
and include <summary>, <param> for the name parameter, and <returns> for
Duplicate; for TemplateTokenValue include at least a <summary> and any relevant
remarks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@BusLane/Services/Templates/MessageTemplateEngine.cs`:
- Around line 28-32: FindMissingTokenValues flags tokens as missing using
values.TryGetValue which respects the dictionary's comparer; change the check to
perform a case-insensitive lookup so casing matches how Apply replaces tokens.
In FindMissingTokenValues, instead of TryGetValue(token, out var value), locate
the matching entry with a case-insensitive comparison (e.g., find
values.Keys/entries where String.Equals(key, token,
StringComparison.OrdinalIgnoreCase)), then inspect that entry's value for
null/whitespace; keep using ExtractTokenNames and ensure behavior matches
Apply's case-insensitive replacement logic.

In `@BusLane/ViewModels/SendMessageViewModel.cs`:
- Around line 230-231: The TemplateTokenValues are only refreshed in
LoadMessage, so placeholders added/edited in the compose form are not shown and
SendAsync can fail; update the code to recompute tokens after the form is edited
by calling RefreshTemplateTokenValues(...) with the up-to-date message returned
by BuildSavedMessageFromForm() whenever templated fields or custom properties
change (e.g. replace the existing ActiveTemplate assignment lines using
ActiveTemplate = message; RefreshTemplateTokenValues(message); and add
equivalent calls in the form-change handlers), and when merging preserve
previously entered token values where keys match so user-entered values are
retained; apply the same change pattern to the other affected block around the
614-621 section (use the same function names: LoadMessage,
BuildSavedMessageFromForm, RefreshTemplateTokenValues, TemplateTokenValues,
SendAsync).

In `@BusLane/Views/Dialogs/LoadMessageDialog.axaml`:
- Line 124: The StackPanel's IsVisible is binding a string property Category
directly (IsVisible="{Binding Category}"), which requires a explicit string→bool
conversion; add a converter (e.g., implement IValueConverter named
StringToBoolConverter or IsNullOrEmptyToBoolConverter that returns false for
null/empty and true otherwise), register it as a XAML resource, and update the
StackPanel IsVisible binding to use that converter (IsVisible="{Binding
Category, Converter={StaticResource StringToBoolConverter}}") so empty or
non-boolean strings correctly map to false/true.

---

Outside diff comments:
In `@BusLane/ViewModels/SendMessageViewModel.cs`:
- Around line 243-249: The DeleteSavedMessage method currently removes the
message but doesn't clear ActiveTemplate, leaving HasActiveTemplate true and
allowing UpdateActiveTemplate to mutate a removed object; modify
DeleteSavedMessage (in SendMessageViewModel) so that if the removed SavedMessage
equals ActiveTemplate you set ActiveTemplate to null (or call
UpdateActiveTemplate(null)/clear the active template via its setter), raise
PropertyChanged for HasActiveTemplate and FilteredSavedMessages as needed, then
call PersistSavedMessages; this ensures the active template is cleared before
persisting and prevents operations on a detached object.
- Around line 549-555: PersistSavedMessages currently swallows exceptions from
AppPaths.CreateSecureFile causing in-memory SavedMessages (and callers
SaveMessage, DeleteSavedMessage, DuplicateSavedMessage, UpdateActiveTemplate) to
diverge from disk; change PersistSavedMessages to propagate failures (either by
throwing the caught exception or returning a failure result) and ensure callers
handle that result by rolling back the in-memory change and surfacing an error
to the UI/log. Specifically, update PersistSavedMessages to not catch-and-ignore
exceptions from Serialize or AppPaths.CreateSecureFile (or to return
bool/Result), and then modify SaveMessage, DeleteSavedMessage,
DuplicateSavedMessage, and UpdateActiveTemplate to detect persistence failure
and revert SavedMessages and any UI state changes (and notify the user via the
existing error reporting mechanism) so disk/write errors are visible and
memory/disk stay consistent.

In `@BusLane/Views/Dialogs/LoadMessageDialog.axaml`:
- Around line 84-86: The empty-state Border's visibility is still driven by
SendMessageViewModel.SavedMessages.Count while the ListBox uses
FilteredSavedMessages; update the Border's IsVisible binding to use the filtered
collection (e.g. bind to SendMessageViewModel.FilteredSavedMessages.Count or a
boolean exposed for "HasFilteredItems") so the empty/no-results UI matches the
ListBox contents (look for the Border with Classes="empty-state" and the ListBox
bound to FilteredSavedMessages).

In `@BusLane/Views/Dialogs/SendMessageDialog.axaml`:
- Around line 123-127: The empty-state TextBlock is still bound to
SavedMessages.Count so it doesn't show when the filtered list is empty; change
its IsVisible binding to use the filtered collection (e.g. bind IsVisible to
"!SendMessageViewModel.FilteredSavedMessages.Count") so the "No saved templates
yet" placeholder appears when FilteredSavedMessages is empty; update the
TextBlock in SendMessageDialog.axaml that currently references
SavedMessages.Count to reference FilteredSavedMessages.Count instead.

---

Nitpick comments:
In `@BusLane/Models/SavedMessage.cs`:
- Around line 25-47: Add XML documentation for the new public API members: add a
summary, param and returns tags to SavedMessage.Duplicate(string? name = null)
explaining that it creates and returns a copy of the SavedMessage with an
optional new name (describe that Name defaults to "{Name} Copy" when name is
null), and add XML docs for TemplateTokenValue (describe what the type/property
represents and any usage/constraints). Ensure the XML comments are placed
immediately above the method declaration for Duplicate and above the
TemplateTokenValue declaration and include <summary>, <param> for the name
parameter, and <returns> for Duplicate; for TemplateTokenValue include at least
a <summary> and any relevant remarks.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 32a63c5f-99a7-4778-8248-eb5b0c725a58

📥 Commits

Reviewing files that changed from the base of the PR and between bafc0d9 and ce1b058.

📒 Files selected for processing (9)
  • BusLane.Tests/Models/ModelTests.cs
  • BusLane.Tests/Services/Templates/MessageTemplateEngineTests.cs
  • BusLane.Tests/ViewModels/SendMessageViewModelTests.cs
  • BusLane/Models/SavedMessage.cs
  • BusLane/Services/Templates/MessageTemplateEngine.cs
  • BusLane/ViewModels/SendMessageViewModel.cs
  • BusLane/Views/Dialogs/LoadMessageDialog.axaml
  • BusLane/Views/Dialogs/SaveMessageDialog.axaml
  • BusLane/Views/Dialogs/SendMessageDialog.axaml

Comment thread BusLane/Services/Templates/MessageTemplateEngine.cs
Comment thread BusLane/ViewModels/SendMessageViewModel.cs
Comment thread BusLane/Views/Dialogs/LoadMessageDialog.axaml Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 31, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 4 file(s) based on 3 unresolved review comments.

Files modified:

  • BusLane/Models/SavedMessage.cs
  • BusLane/Services/Templates/MessageTemplateEngine.cs
  • BusLane/ViewModels/SendMessageViewModel.cs
  • BusLane/Views/Dialogs/LoadMessageDialog.axaml

Commit: fa2b9c6a5a523a4a19e6417da90a99b3b1bbd510

The changes have been pushed to the codex/issue-115-message-templates-v2 branch.

Time taken: 3m 51s

Fixed 4 file(s) based on 3 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Copy link
Copy Markdown
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.

Caution

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

⚠️ Outside diff range comments (1)
BusLane/Models/SavedMessage.cs (1)

5-5: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Make Id property init-only to prevent mutation.

The Id property is auto-generated on initialization but allows modification after creation, which could lead to data integrity issues. Mark it as init-only.

🔒 Proposed fix
-    public string Id { get; set; } = Guid.NewGuid().ToString();
+    public string Id { get; init; } = Guid.NewGuid().ToString();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/Models/SavedMessage.cs` at line 5, The Id property on SavedMessage is
currently mutable (public string Id { get; set; }) and should be init-only to
prevent post-construction mutation; change the property declaration to use an
init accessor (public string Id { get; init; } = Guid.NewGuid().ToString();) and
update any code that assigns to SavedMessage.Id after construction to instead
set it at object creation or remove such assignments.
🧹 Nitpick comments (4)
BusLane/Models/SavedMessage.cs (4)

25-47: ⚡ Quick win

Add XML doc comments for public method.

The Duplicate method is a public API and should have XML documentation describing its behavior and parameters. As per coding guidelines, "Use XML doc comments for public classes, methods, and key regions."

📝 Proposed documentation
+    /// <summary>
+    /// Creates a duplicate of the current SavedMessage with a new Id and CreatedAt timestamp.
+    /// </summary>
+    /// <param name="name">Optional custom name for the duplicate. Defaults to "{Name} Copy" if not specified.</param>
+    /// <returns>A new SavedMessage instance with copied properties and collections.</returns>
     public SavedMessage Duplicate(string? name = null)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/Models/SavedMessage.cs` around lines 25 - 47, Add XML documentation
for the public method SavedMessage.Duplicate: include a summary describing that
it creates and returns a shallow copy of the current SavedMessage with an
optional new name, document the parameter "name" (nullable) explaining that if
null the new name is "{Name} Copy", and document the return value as a new
SavedMessage instance with copied properties (mention Tags, TokenValues,
CustomProperties are copied into new collections). Place the XML comments
immediately above the Duplicate method declaration.

50-50: ⚡ Quick win

Add XML doc comments for public class.

Public classes should have XML documentation comments. As per coding guidelines, "Use XML doc comments for public classes, methods, and key regions."

📝 Proposed documentation
+/// <summary>
+/// Represents a custom property key-value pair with property change notification support for data binding.
+/// </summary>
 public class CustomProperty : System.ComponentModel.INotifyPropertyChanged
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/Models/SavedMessage.cs` at line 50, Add XML documentation for the
public class CustomProperty (which implements
System.ComponentModel.INotifyPropertyChanged): add a <summary> describing the
class responsibility/purpose and note that it implements INotifyPropertyChanged,
and optionally include a <remarks> describing usage or thread-safety and a
<seealso> or <seealso cref="System.ComponentModel.INotifyPropertyChanged"/>
reference; ensure the XML doc sits immediately above the public class
declaration for CustomProperty.

84-88: ⚡ Quick win

Consider using a record type for immutable data model.

TemplateTokenValue appears to be a simple data container. According to the coding guidelines, "Use records with primary constructors for immutable data models." Converting to a record provides structural equality and clearer intent.

♻️ Proposed refactor to record type
-public class TemplateTokenValue
-{
-    public string Name { get; set; } = "";
-    public string Value { get; set; } = "";
-}
+/// <summary>
+/// Represents a template token name-value pair for token replacement in message templates.
+/// </summary>
+public record TemplateTokenValue
+{
+    public required string Name { get; init; }
+    public required string Value { get; init; }
+}

Or use primary constructor syntax:

-public class TemplateTokenValue
-{
-    public string Name { get; set; } = "";
-    public string Value { get; set; } = "";
-}
+/// <summary>
+/// Represents a template token name-value pair for token replacement in message templates.
+/// </summary>
+public record TemplateTokenValue(string Name, string Value);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/Models/SavedMessage.cs` around lines 84 - 88, The TemplateTokenValue
class is a simple data container and should be converted to an immutable record:
replace the class TemplateTokenValue (with mutable properties Name and Value)
with a record using a primary constructor that takes string Name and string
Value so you get immutable properties, structural equality, and clearer intent;
update any call sites that relied on property setters to construct new instances
instead of mutating existing ones.

3-3: ⚡ Quick win

Add XML doc comments for public class.

Public classes should have XML documentation comments describing their purpose. As per coding guidelines, "Use XML doc comments for public classes, methods, and key regions."

📝 Proposed documentation
+/// <summary>
+/// Represents a saved Service Bus message template with metadata, properties, and token support.
+/// </summary>
 public class SavedMessage
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@BusLane/Models/SavedMessage.cs` at line 3, Add an XML documentation comment
above the public class SavedMessage that explains the purpose of the class
(e.g., what it represents and how it is used); include at minimum a <summary>
tag describing the class, and optionally <remarks> or <param>/<returns> for any
public members within SavedMessage to follow the project's XML doc guideline.
Ensure the comment sits immediately before the declaration "public class
SavedMessage" and follows the project's style (triple-slash /// XML comments).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@BusLane/Models/SavedMessage.cs`:
- Line 5: The Id property on SavedMessage is currently mutable (public string Id
{ get; set; }) and should be init-only to prevent post-construction mutation;
change the property declaration to use an init accessor (public string Id { get;
init; } = Guid.NewGuid().ToString();) and update any code that assigns to
SavedMessage.Id after construction to instead set it at object creation or
remove such assignments.

---

Nitpick comments:
In `@BusLane/Models/SavedMessage.cs`:
- Around line 25-47: Add XML documentation for the public method
SavedMessage.Duplicate: include a summary describing that it creates and returns
a shallow copy of the current SavedMessage with an optional new name, document
the parameter "name" (nullable) explaining that if null the new name is "{Name}
Copy", and document the return value as a new SavedMessage instance with copied
properties (mention Tags, TokenValues, CustomProperties are copied into new
collections). Place the XML comments immediately above the Duplicate method
declaration.
- Line 50: Add XML documentation for the public class CustomProperty (which
implements System.ComponentModel.INotifyPropertyChanged): add a <summary>
describing the class responsibility/purpose and note that it implements
INotifyPropertyChanged, and optionally include a <remarks> describing usage or
thread-safety and a <seealso> or <seealso
cref="System.ComponentModel.INotifyPropertyChanged"/> reference; ensure the XML
doc sits immediately above the public class declaration for CustomProperty.
- Around line 84-88: The TemplateTokenValue class is a simple data container and
should be converted to an immutable record: replace the class TemplateTokenValue
(with mutable properties Name and Value) with a record using a primary
constructor that takes string Name and string Value so you get immutable
properties, structural equality, and clearer intent; update any call sites that
relied on property setters to construct new instances instead of mutating
existing ones.
- Line 3: Add an XML documentation comment above the public class SavedMessage
that explains the purpose of the class (e.g., what it represents and how it is
used); include at minimum a <summary> tag describing the class, and optionally
<remarks> or <param>/<returns> for any public members within SavedMessage to
follow the project's XML doc guideline. Ensure the comment sits immediately
before the declaration "public class SavedMessage" and follows the project's
style (triple-slash /// XML comments).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 46037ea9-00d8-46a6-999e-65455cbc03da

📥 Commits

Reviewing files that changed from the base of the PR and between ce1b058 and fa2b9c6.

📒 Files selected for processing (4)
  • BusLane/Models/SavedMessage.cs
  • BusLane/Services/Templates/MessageTemplateEngine.cs
  • BusLane/ViewModels/SendMessageViewModel.cs
  • BusLane/Views/Dialogs/LoadMessageDialog.axaml
🚧 Files skipped from review as they are similar to previous changes (3)
  • BusLane/Views/Dialogs/LoadMessageDialog.axaml
  • BusLane/Services/Templates/MessageTemplateEngine.cs
  • BusLane/ViewModels/SendMessageViewModel.cs

@soliktomasz soliktomasz merged commit ab3f4a4 into main May 31, 2026
4 checks passed
@soliktomasz soliktomasz deleted the codex/issue-115-message-templates-v2 branch May 31, 2026 08:48
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