Skip to content

Pin feature#124

Merged
soliktomasz merged 2 commits into
mainfrom
issue-123-pinning
Jun 1, 2026
Merged

Pin feature#124
soliktomasz merged 2 commits into
mainfrom
issue-123-pinning

Conversation

@soliktomasz
Copy link
Copy Markdown
Owner

@soliktomasz soliktomasz commented Jun 1, 2026

This pull request introduces support for pinning Service Bus entities (queues, topics, subscriptions) to workspaces, allowing users to persist and quickly access their favorite entities across sessions. The changes include a new PinnedEntity model, updates to the preferences service for storing pinned entities, enhancements to the navigation state for pin management, and comprehensive tests to ensure correct behavior.

Pinning Feature Implementation:

  • Added a new PinnedEntity record and PinnedEntityType enum in PinnedEntity.cs to represent pinned entities and their types.
  • Updated the IPreferencesService interface and its implementations (PreferencesService, DummyPreferencesService, and test stubs) to include a PinnedEntitiesJson property for persisting pinned entities. [1] [2] [3] [4] [5] [6] [7]

Navigation State Enhancements:

  • Refactored NavigationState to support pinning logic, including storing all pins, filtering entities to show pinned items first, and scoping pins to the current workspace. Added public APIs for toggling pins, checking pin status, and exposing pinned entities for UI binding. [1] [2] [3] [4] [5] [6]
  • Modified ConnectionTabViewModel to initialize NavigationState with the preferences service and set the pin scope when connecting to a workspace or Azure namespace. [1] [2] [3]

Testing and Verification:

  • Added comprehensive unit tests for pinning behavior, including pin add/remove, workspace scoping, pin persistence, and ordering of pinned entities.
  • Added tests to verify that pinning controls are exposed in the entity tree views and that the preferences service correctly round-trips pinned entities. [1] [2] [3]

These changes collectively enable robust pinning functionality for Service Bus entities, improve user productivity, and ensure reliable persistence and retrieval of pinned items across sessions.

Summary by CodeRabbit

Release Notes

  • New Features
    • Pin and save your favorite Azure Service Bus entities (queues, topics, subscriptions) to a dedicated "Pinned" section for quick access across sessions
    • Pinned entities are organized by workspace and appear first in filtered lists

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.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

Warning

Review limit reached

@soliktomasz, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 41 minutes and 38 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 54b459eb-e8f0-44ee-88f0-9706ec1eb736

📥 Commits

Reviewing files that changed from the base of the PR and between d2c1780 and 482d5cb.

📒 Files selected for processing (4)
  • BusLane.Tests/Models/PinnedEntityTests.cs
  • BusLane.Tests/ViewModels/Core/NavigationStatePinningTests.cs
  • BusLane/Models/PinnedEntity.cs
  • BusLane/ViewModels/Core/NavigationState.cs
📝 Walkthrough

Walkthrough

This PR introduces an entity pinning feature allowing users to pin Azure Service Bus queues, topics, and subscriptions within a workspace scope. Pinned entities persist to preferences, reorder filtered lists, and appear in a dedicated UI section with toggle and selection commands.

Changes

Entity Pinning Feature

Layer / File(s) Summary
PinnedEntity data contract
BusLane/Models/PinnedEntity.cs
PinnedEntity record captures workspace id, entity type, name, and optional topic name for subscriptions. Computed DisplayName formats subscriptions as TopicName/Name. PinnedEntityType enum includes Queue, Topic, Subscription with JSON string serialization.
Preferences persistence for pinned entities
BusLane/Services/Abstractions/IPreferencesService.cs, BusLane/Services/Infrastructure/PreferencesService.cs
IPreferencesService gains PinnedEntitiesJson property. PreferencesService loads and saves this JSON string, defaulting to "[]" when absent, and extends the PreferencesData schema.
NavigationState pinning logic
BusLane/ViewModels/Core/NavigationState.cs
Core pinning: new constructor overload accepts IPreferencesService, tracks _allPinnedEntities and _pinScopeId, and exposes PinnedEntities collection and computed HasPinnedEntities/IsSelectedEntityPinned properties. FilteredQueues and FilteredTopics order pinned items first. Public API: SetPinScope() (resets scope and reloads pins), TogglePin() (add/remove with persistence), IsPinned() (check membership). Helpers: OrderPinnedFirst, CreatePin, LoadAllPinnedEntities, PersistPins, ReloadScopedPins.
ConnectionTabViewModel preferences integration
BusLane/ViewModels/Core/ConnectionTabViewModel.cs
Constructor now assigns _preferencesService and threads it into NavigationState and MessageOperationsViewModel. Connection flows set pin scope via connection.Id or ns.Id. DummyPreferencesService gains PinnedEntitiesJson property.
MainWindowViewModel pin commands and wiring
BusLane/ViewModels/MainWindowViewModel.cs
Navigation constructor receives preferencesService. SelectNamespaceAsync calls SetPinScope(ns.Id). New relay commands: ToggleSelectedEntityPinCommand, ToggleEntityPinCommand, SelectPinnedEntityCommand with type-based routing for queues, topics, and subscriptions (resolving pinned subs by locating topic and subscription).
Entity tree XAML pinning controls
BusLane/Views/Controls/EntityTreeView.axaml, BusLane/Views/Controls/AzureEntityTreeView.axaml
Header grid expanded by one column; new pin-toggle icon button added. New "Pinned" section renders conditionally when HasPinnedEntities is true, showing pinned count and PinnedEntities list with selection and unpin buttons.
NavigationState pinning test suite
BusLane.Tests/ViewModels/Core/NavigationStatePinningTests.cs
Five core tests: TogglePin_Queue_AddsScopedPinAndPersistsJson, TogglePin_PinnedQueue_RemovesScopedPinAndPersistsJson, FilteredQueues_PutsPinnedQueuesFirst, SetPinScope_LoadsOnlyPinsForCurrentWorkspace, TogglePin_Subscription_UsesTopicNameInIdentity. Includes in-file TestPreferencesService stub.
Integration and contract tests
BusLane.Tests/Services/Infrastructure/PreferencesServiceTests.cs, BusLane.Tests/ViewModels/Core/ConnectionTabViewModelTests.cs, BusLane.Tests/ViewModels/MainWindowViewModelTests.cs, BusLane.Tests/Views/EntityTreeViewTests.cs
SaveAndReload_ShouldRoundTripPinnedEntitiesJson verifies preferences persistence. ConnectWithConnectionStringAsync_LoadsPinsAfterEntityLoad ensures pins load after connection. EntityTreeViews_ExposePinningControls validates XAML command names. Test helper TestPreferencesService updated with PinnedEntitiesJson.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A bunny's workspace now stays neat,
With pins that make quick access sweet,
Queue, topic, subscription too,
Pinned first in every filtered view,
Hopping faster through your fleet! 🌟

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.52% 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 'Pin feature' is vague and non-descriptive; it lacks specificity about what pinning capability was implemented and does not convey meaningful information about the primary change. Use a more descriptive title that specifies the pinning functionality being added, such as 'Add entity pinning feature for Azure Service Bus' or 'Implement pinned entities management in navigation'.
✅ 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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-123-pinning

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.

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

🧹 Nitpick comments (2)
BusLane/Models/PinnedEntity.cs (1)

8-19: ⚡ Quick win

Consider adding validation to enforce TopicName requirements by entity type.

The record allows invalid states: a Subscription without a TopicName, or a Queue/Topic with a TopicName set. While DisplayName handles the null case defensively, validating at construction time would prevent inconsistent data.

🛡️ Proposed validation using init-only properties
 public record PinnedEntity(
     string WorkspaceId,
     PinnedEntityType Type,
     string Name,
     string? TopicName)
 {
+    public PinnedEntity(string WorkspaceId, PinnedEntityType Type, string Name, string? TopicName)
+        : this(WorkspaceId, Type, Name, TopicName)
+    {
+        if (Type == PinnedEntityType.Subscription && string.IsNullOrWhiteSpace(TopicName))
+            throw new ArgumentException("TopicName is required for Subscription entities.", nameof(TopicName));
+        
+        if (Type != PinnedEntityType.Subscription && !string.IsNullOrWhiteSpace(TopicName))
+            throw new ArgumentException("TopicName should only be set for Subscription entities.", nameof(TopicName));
+    }
+
     public string DisplayName => Type == PinnedEntityType.Subscription && !string.IsNullOrWhiteSpace(TopicName)
         ? $"{TopicName}/{Name}"
         : Name;
🤖 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/PinnedEntity.cs` around lines 8 - 19, The PinnedEntity record
allows inconsistent states (Subscription missing TopicName, or Queue/Topic
having TopicName) — add validation in the record's constructor/body to enforce
rules: when Type == PinnedEntityType.Subscription require non-empty TopicName;
when Type != PinnedEntityType.Subscription require TopicName be null or empty;
implement this by converting the positional record to include a validation block
(a compact constructor or explicit parameter checks) inside PinnedEntity
(referencing the Type and TopicName parameters) and throw
ArgumentException/ArgumentNullException with clear messages if validation fails;
keep DisplayName and TypeLabel unchanged.
BusLane/ViewModels/Core/NavigationState.cs (1)

98-103: ⚡ Quick win

Document the new public pinning API.

The added public constructor and pinning methods are missing XML doc comments, unlike the rest of the public surface in this file.

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

Also applies to: 204-236

🤖 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/Core/NavigationState.cs` around lines 98 - 103, The new
public API lacks XML documentation: add XML doc comments for the public
NavigationState(IPreferencesService? preferencesService) constructor (and the
parameter), the parameterless NavigationState() constructor, and all newly added
public pinning methods referenced around the pinning section (methods that
manage pin/unpin state); include <summary> for purpose, <param> describing the
preferencesService (nullable behavior), and any <returns> or <remarks> as
appropriate so the public surface matches existing documentation style in this
file. Ensure the comments match the existing XML doc format used elsewhere in
NavigationState and cover threading/side-effect notes if present.
🤖 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/ViewModels/Core/NavigationState.cs`:
- Around line 218-229: TogglePin currently mutates _allPinnedEntities before
calling PersistPins()/Save, so a persistence failure leaves in-memory state
inconsistent; modify TogglePin to make the operation atomic by either (a)
performing the persistence first and only mutating _allPinnedEntities and
calling ReloadScopedPins() on success, or (b) wrapping the current mutation +
PersistPins() in try/catch and rolling back the in-memory change to
_allPinnedEntities if PersistPins() throws; ensure references to
_allPinnedEntities, PersistPins(), ReloadScopedPins(), and the TogglePin method
are used so the fix is applied in both occurrences (around lines shown and the
second block at 298-306).
- Line 37: PinnedEntities is currently a public mutable ObservableCollection
which allows external callers to modify it and cause state/persistence desync;
change the public API to expose a ReadOnlyObservableCollection<PinnedEntity>
(e.g., public ReadOnlyObservableCollection<PinnedEntity> PinnedEntities) backed
by a private ObservableCollection<PinnedEntity> (e.g., _pinnedEntities) that
only this class mutates. Update TogglePin, PersistPins, and ReloadScopedPins to
operate on _allPinnedEntities and the private _pinnedEntities (raising
collection changes) and ensure PinnedEntitiesJson is only updated via
PersistPins so external code cannot mutate the public collection directly.

---

Nitpick comments:
In `@BusLane/Models/PinnedEntity.cs`:
- Around line 8-19: The PinnedEntity record allows inconsistent states
(Subscription missing TopicName, or Queue/Topic having TopicName) — add
validation in the record's constructor/body to enforce rules: when Type ==
PinnedEntityType.Subscription require non-empty TopicName; when Type !=
PinnedEntityType.Subscription require TopicName be null or empty; implement this
by converting the positional record to include a validation block (a compact
constructor or explicit parameter checks) inside PinnedEntity (referencing the
Type and TopicName parameters) and throw ArgumentException/ArgumentNullException
with clear messages if validation fails; keep DisplayName and TypeLabel
unchanged.

In `@BusLane/ViewModels/Core/NavigationState.cs`:
- Around line 98-103: The new public API lacks XML documentation: add XML doc
comments for the public NavigationState(IPreferencesService? preferencesService)
constructor (and the parameter), the parameterless NavigationState()
constructor, and all newly added public pinning methods referenced around the
pinning section (methods that manage pin/unpin state); include <summary> for
purpose, <param> describing the preferencesService (nullable behavior), and any
<returns> or <remarks> as appropriate so the public surface matches existing
documentation style in this file. Ensure the comments match the existing XML doc
format used elsewhere in NavigationState and cover threading/side-effect notes
if present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 49d114a7-6b16-4252-9d7b-e1e46a404275

📥 Commits

Reviewing files that changed from the base of the PR and between ab3f4a4 and d2c1780.

📒 Files selected for processing (13)
  • BusLane.Tests/Services/Infrastructure/PreferencesServiceTests.cs
  • BusLane.Tests/ViewModels/Core/ConnectionTabViewModelTests.cs
  • BusLane.Tests/ViewModels/Core/NavigationStatePinningTests.cs
  • BusLane.Tests/ViewModels/MainWindowViewModelTests.cs
  • BusLane.Tests/Views/EntityTreeViewTests.cs
  • BusLane/Models/PinnedEntity.cs
  • BusLane/Services/Abstractions/IPreferencesService.cs
  • BusLane/Services/Infrastructure/PreferencesService.cs
  • BusLane/ViewModels/Core/ConnectionTabViewModel.cs
  • BusLane/ViewModels/Core/NavigationState.cs
  • BusLane/ViewModels/MainWindowViewModel.cs
  • BusLane/Views/Controls/AzureEntityTreeView.axaml
  • BusLane/Views/Controls/EntityTreeView.axaml

Comment thread BusLane/ViewModels/Core/NavigationState.cs Outdated
Comment thread BusLane/ViewModels/Core/NavigationState.cs Outdated
@soliktomasz soliktomasz merged commit 8e46785 into main Jun 1, 2026
4 checks passed
@soliktomasz soliktomasz deleted the issue-123-pinning branch June 1, 2026 09:17
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.

1 participant