This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
---
source_files:
- DataPRO/Modules/Groups/GroupList/Model/ChannelSetting.cs
generated_at: "2026-04-16T04:47:17.887032+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "51a43b8567809d4b"
---
# Model
1. **Purpose**
This module file (`ChannelSetting.cs`) is a placeholder or stub within the `GroupList.Model` namespace and currently contains no implementation. As written, it serves no functional purpose in the system—it declares no types, properties, methods, or logic—and appears to be an incomplete or scaffolding file awaiting future development.
2. **Public Interface**
No public types, functions, classes, or methods are defined in this file. The namespace `GroupList.Model` and the file itself are empty aside from the `using` directive.
3. **Invariants**
No invariants can be determined, as no logic or state is present.
4. **Dependencies**
- **Imports**: The file imports `DTS.Common.Interface.Channels`, indicating a *potential* future dependency on channel-related abstractions defined in that namespace (e.g., interfaces like `IChannel`, `ChannelType`, etc.). However, no types from this namespace are currently used.
- **No internal dependencies**: No other modules, namespaces, or types within the codebase are referenced.
5. **Gotchas**
- **Empty file**: The file is functionally inert; any assumptions about its role (e.g., modeling channel settings for groups) are speculative.
- **Misleading namespace**: The `GroupList.Model` namespace suggests this file may eventually model channel-related configuration for groups, but no such contract exists yet.
- **No validation or safety guarantees**: Since no code exists, no correctness properties, thread-safety, or lifecycle rules apply.
- **Potential tech debt**: If this file was intended to be a model for channel settings but remains unimplemented, it may indicate pending work or incomplete refactoring.
None identified beyond what is evident from the empty structure.

View File

@@ -0,0 +1,65 @@
---
source_files:
- DataPRO/Modules/Groups/GroupList/Properties/Settings.Designer.cs
- DataPRO/Modules/Groups/GroupList/Properties/AssemblyInfo.cs
generated_at: "2026-04-16T04:47:23.586422+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "1fd4dfff93afcd30"
---
# Properties
## Documentation Page: `GroupList.Properties.Settings`
---
### 1. **Purpose**
This module defines the application settings class (`Settings`) for the `GroupList` module within the DataPRO system. It provides a strongly-typed, thread-safe accessor (`Default`) to application-level configuration values stored in the standard .NET configuration system (e.g., `app.config`). As a generated class, its purpose is to abstract access to user- or application-scoped settings, though **no settings properties are defined in the provided source**—they are presumably declared in the corresponding `.settings` file (not included here) and auto-generated into this class.
---
### 2. **Public Interface**
The following members are explicitly defined in the provided source:
- **`public static Settings Default { get; }`**
A static property returning the singleton instance of the `Settings` class. The instance is created via `ApplicationSettingsBase.Synchronized(...)`, ensuring thread-safe access to settings values.
- *Type*: `Settings` (a subclass of `System.Configuration.ApplicationSettingsBase`)
- *Behavior*: Returns the same instance on every call (singleton pattern). Values are loaded from configuration at first access.
> **Note**: No additional public properties, methods, or fields are visible in the provided source. Any settings (e.g., `string GroupFilter`, `int MaxGroups`) would be auto-generated by the Visual Studio Settings Designer and are *not present in this file*.
---
### 3. **Invariants**
- The `Settings` class is **sealed** and **partial**, with auto-generation metadata (`CompilerGeneratedAttribute`, `GeneratedCodeAttribute`).
- The `Default` instance is **synchronized** using `ApplicationSettingsBase.Synchronized(...)`, implying thread-safe reads/writes to settings values.
- The class inherits from `ApplicationSettingsBase`, so it adheres to standard .NET settings semantics:
- Settings are persisted per-user (user-scoped) and/or per-application (application-scoped), depending on their `UserScopedSetting` or `ApplicationScopedSetting` attributes (not visible here).
- No explicit validation or invariants are enforced in the provided code.
---
### 4. **Dependencies**
**Dependencies *of* this module**:
- `System.Configuration` (via `ApplicationSettingsBase`)
- `System.Runtime.CompilerServices` (for `CompilerGeneratedAttribute`)
- `System.CodeDom.Compiler` (for `GeneratedCodeAttribute`)
**Dependencies *on* this module**:
- Not inferable from this file alone. However, any consumer of `GroupList.Properties.Settings.Default` would depend on this module.
- The assembly `GroupList` (as per `AssemblyInfo.cs`) is the containing assembly for this class.
---
### 5. **Gotchas**
- **No settings are defined in this file** — the `Settings` class is empty *in the provided source*. Actual settings (e.g., `public string SomeSetting { get; set; }`) must be declared in the `.settings` designer file (e.g., `Settings.settings`) and regenerated into this class.
- **Do not manually edit this file** — the auto-generated header explicitly warns: *"Changes to this file may cause incorrect behavior and will be lost if the code is regenerated."*
- The `defaultInstance` is initialized synchronously via `Synchronized(...)`, but **no default values are set here** — defaults come from the `Settings.settings` designer or `app.config`.
- The assembly GUID (`95d3c318-8333-4d0b-b508-21d654404443`) and version (`1.0.0.0`) suggest this is an early or placeholder version; verify versioning strategy if upgrading or refactoring.
- **None identified from source alone** — beyond the above, behavior is standard for .NET `ApplicationSettingsBase` subclasses.
---
> **Recommendation for Developers**:
> To inspect or modify settings, open the `Settings.settings` file in Visual Studio (if present in the project). This will regenerate `Settings.Designer.cs`. Always verify the actual settings schema in the designer or `app.config` before relying on specific property names or values.

View File

@@ -0,0 +1,84 @@
---
source_files:
- DataPRO/Modules/Groups/GroupList/Resources/TranslateExtension.cs
- DataPRO/Modules/Groups/GroupList/Resources/StringResources.Designer.cs
generated_at: "2026-04-16T04:47:13.405699+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "30656f2a830a5a31"
---
# Resources
## Documentation: `TranslateExtension` Markup Extension
---
### 1. **Purpose**
This module provides a WPF `MarkupExtension` (`TranslateExtension`) to enable declarative, data-bound localization of UI strings directly in XAML. It allows developers to reference localized string resources by key (e.g., `{local:Translate Name}`) and automatically retrieve the appropriate localized value at runtime from the `StringResources` resource class. Its role is to bridge XAML markup with the applications resource management system, supporting multi-language UI without requiring code-behind or manual string lookups.
---
### 2. **Public Interface**
#### `TranslateExtension` class
- **Namespace**: `GroupList`
- **Base class**: `System.Windows.Markup.MarkupExtension`
- **Attributes**:
- `[MarkupExtensionReturnType(typeof(string))]` — Indicates the extension returns a `string`.
##### Constructor
- **`TranslateExtension(string key)`**
Initializes a new instance with the specified resource key. The key is stored in the private readonly field `_key`.
- *Parameter*: `key` — The string key used to look up a localized resource (e.g., `"Name"`, `"Description"`).
- *Behavior*: Validates `key` is non-null/non-empty at *runtime* during `ProvideValue` (not in constructor).
##### Overridden Method
- **`public override object ProvideValue(IServiceProvider serviceProvider)`**
Returns the localized string for `_key`, or a fallback value if the key is missing or lookup fails.
- *Behavior*:
- If `_key` is `null` or empty → returns `"#stringnotfound#"`.
- Otherwise, calls `StringResources.ResourceManager.GetString(_key)`.
- If the result is non-null → returns the localized string.
- If the result is `null` → returns `"#stringnotfound# " + _key` (e.g., `"#stringnotfound# MissingKey"`).
- *Note*: The `serviceProvider` parameter is unused in the implementation.
---
### 3. **Invariants**
- **Resource key must be a valid string resource name** (e.g., `"Name"`, `"Channels"`). Invalid keys (e.g., `"UnknownKey"`) will not throw but will return the fallback string `"#stringnotfound# UnknownKey"`.
- **Case sensitivity**: Resource keys are case-sensitive (e.g., `"name"``"Name"`).
- **No runtime exceptions** are thrown for missing keys; the extension gracefully degrades to the `NotFound` prefix.
- **Thread-safety**: Relies on `StringResources.ResourceManager`, which is thread-safe per .NET documentation (uses lazy initialization and locking internally).
- **XAML-only usage**: Intended for use in XAML markup only; not designed for programmatic invocation outside markup extension context.
---
### 4. **Dependencies**
#### Dependencies *on* this module:
- **WPF framework**: Requires `System.Windows.Markup` and `System.Windows` (for `MarkupExtension`).
- **`StringResources` class**:
- Defined in `GroupList.Resources` namespace.
- Auto-generated from `.resx` files (not shown here, but implied by `StringResources.Designer.cs`).
- Provides the underlying `ResourceManager` and strongly-typed properties (e.g., `StringResources.Name`).
- **No external third-party dependencies** beyond .NET Framework 4.0+ (per runtime version in `StringResources.Designer.cs`).
#### Dependencies *of* this module:
- None beyond standard WPF/.NET Framework types.
- **Consumers**: Any XAML file in the `GroupList` module (e.g., `GroupList/Resources/TranslateExtension.cs` is likely used in `*.xaml` files in the same module) to localize UI elements.
---
### 5. **Gotchas**
- **No compile-time safety for keys**: Using an incorrect key (e.g., `"Nam"` instead of `"Name"`) will not cause a compile error—only a runtime fallback string (`#stringnotfound# Nam`).
- **No culture switching support in extension itself**: While `StringResources.Culture` can be set globally (e.g., via `Thread.CurrentThread.CurrentUICulture`), the extension does not expose or manage culture selection.
- **Hardcoded fallback string**: The `"#stringnotfound#"` prefix is fixed and may be visible to end-users if keys are missing.
- **No validation of key format**: Keys like `""` (empty string) or `" "` (whitespace) are treated as invalid and return `NotFound`, but no explicit error logging occurs.
- **Auto-generated resource class**: `StringResources.Designer.cs` is auto-generated; manual edits will be overwritten. Resource keys must match entries in the corresponding `.resx` file (not visible here).
- **No support for parameterized strings**: The extension only supports simple key-based lookups (e.g., `"{local:Translate Name}"`). It cannot handle format strings like `"{0} is {1}"` (e.g., `String.Format`-style substitution).
None identified beyond the above.

View File

@@ -0,0 +1,71 @@
---
source_files:
- DataPRO/Modules/Groups/GroupList/View/GroupListView.xaml.cs
generated_at: "2026-04-16T04:47:32.695881+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "b80e86a41868129e"
---
# View
### **Purpose**
This module implements the WPF UI view (`GroupListView`) for displaying a list of groups in a tabular format using a `ListView` with `GridView`. It serves as the concrete implementation of the `IGroupListView` interface, bridging user interactions (sorting, filtering, double-clicking) with the corresponding `IGroupListViewModel` logic. Its role is to render group data and translate UI events into view model commands, adhering to the MVVM pattern.
---
### **Public Interface**
The class itself is public and implements `IGroupListView` (interface defined elsewhere), but no explicit public methods are declared in this file. All behavior is exposed via event handlers wired in XAML (not shown). The following private methods handle UI events:
- **`ListViewHeader_Click(object sender, RoutedEventArgs e)`**
Handles clicks on standard `GridViewColumnHeader` elements. Extracts the `Tag` (column identifier) and `DataContext` (view model), then invokes `viewModel.Sort(columnTag, true)` to sort ascending.
- **`GridViewColumnHeaderSearchable_OnSearch(object sender, RoutedEventArgs e)`**
Handles search input events on a custom `GridViewColumnHeaderSearchable` control. Extracts the `searchTerm` from `e.OriginalSource` and the `columnTag` from the senders `Tag`, then calls `vm.Filter(columnTag, searchTerm)`.
- **`GridViewColumnHeader_OnClick(object sender, RoutedEventArgs e)`**
Handles clicks on `GridViewColumnHeaderSearchable` controls (fallback to standard headers). Attempts to extract `columnTag` from the sender or via `Utils.FindChild`, then calls `vm?.Sort(columnTag, true)`.
- **`MouseDoubleClick(object sender, MouseButtonEventArgs e)`**
Handles double-clicks on the `ListView`. Determines the clicked item index using `GetCurrentIndex`, and if valid, invokes `vm.MouseDoubleClick(index)` on the view model.
- **`GetCurrentIndex(GetPositionDelegate getPosition, ListView lv)`** *(private static)*
Iterates over `ListView` items, checks if the mouse position (via delegate) is within the bounds of each `ListViewItem`, and returns the zero-based index of the first matching item, or `-1` if none.
- **`GetListViewItem(int index, ListView lv)`** *(private static)*
Retrieves the `ListViewItem` container for a given item index using `ItemContainerGenerator.ContainerFromIndex`.
- **`IsMouseOverTarget(Visual target, GetPositionDelegate getPosition)`** *(private static)*
Computes the visual bounds of a `Visual` and checks if the mouse position (from the delegate) lies within those bounds.
---
### **Invariants**
- The `DataContext` of `GroupListView` **must** be an instance implementing `IGroupListViewModel`; otherwise, casting in event handlers (`(IGroupListViewModel)DataContext`) will fail at runtime.
- Column identifiers (`Tag` properties on `GridViewColumnHeader` or `GridViewColumnHeaderSearchable`) **must** be non-null and consistent with expected keys used by `IGroupListViewModel.Sort` and `IGroupListViewModel.Filter`.
- The `ListView` must contain items compatible with the view models data source; `GetCurrentIndex` assumes `lv.Items.Count` is stable during iteration (no concurrent modifications).
- Double-click events only trigger `MouseDoubleClick` on the view model if the mouse is over a valid, generated `ListViewItem`.
---
### **Dependencies**
**Imports/References (from source):**
- `DTS.Common.Interface.Groups.GroupTemplateList` (namespace, likely contains `IGroupListView` and related interfaces)
- `DTS.Common.Interface.Groups.GroupList` (contains `IGroupListViewModel`)
- `DTS.Common.Controls` (contains `GridViewColumnHeaderSearchable`)
- `DTS.Common.Utils` (contains `Utils.FindChild<T>`)
- Standard WPF namespaces (`System.Windows.*`)
**Depended upon by:**
- XAML file `GroupListView.xaml` (not provided, but implied by `InitializeComponent()` and event bindings).
- Likely consumed by a DI container or view factory that resolves `IGroupListView` and sets its `DataContext` to an `IGroupListViewModel` implementation.
---
### **Gotchas**
- **Ambiguous event routing**: `ListViewHeader_Click` and `GridViewColumnHeader_OnClick` both handle header clicks but for different header types. If a `GridViewColumnHeaderSearchable` is clicked, `GridViewColumnHeader_OnClick` runs, but `ListViewHeader_Click` may also fire depending on XAML event wiring—risk of duplicate sorting/filtering if not coordinated.
- **Unsafe cast in `ListViewHeader_Click`**: Assumes `colHeader.DataContext` is `IGroupListViewModel`; if the view is reused or bound incorrectly, this throws `InvalidCastException`.
- **Fallback logic in `GridViewColumnHeader_OnClick`**: Uses `Utils.FindChild<GridViewColumnHeaderSearchable>` to extract `Tag` if the sender is not already a `GridViewColumnHeaderSearchable`. This implies tight coupling to a specific visual tree structure and may break if the control template changes.
- **Mouse position calculation**: `GetCurrentIndex` uses `VisualTreeHelper.GetDescendantBounds`, which may be expensive or inaccurate if items are virtualized (e.g., with `VirtualizingStackPanel`).
- **No null-safety for `vm`**: In `MouseDoubleClick`, `vm?.Sort(...)` uses null-conditional, but `vm.MouseDoubleClick(index)` does not—risk of `NullReferenceException` if `DataContext` is unset.
- **Search term source**: `GridViewColumnHeaderSearchable_OnSearch` casts `e.OriginalSource` to `string` for `searchTerm`, implying the event args `OriginalSource` *is* the search string—this is non-standard and highly dependent on how `GridViewColumnHeaderSearchable` raises the event.

View File

@@ -0,0 +1,149 @@
---
source_files:
- DataPRO/Modules/Groups/GroupList/ViewModel/GroupListViewModel.cs
generated_at: "2026-04-16T04:47:12.822358+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "efb48e4bf6e2c1c7"
---
# ViewModel
## Documentation: `GroupListViewModel`
---
### 1. Purpose
`GroupListViewModel` is the core view model for the Group List UI module. It manages the display, filtering, sorting, selection, and lifecycle of `IGroup` entities within the application. It acts as the intermediary between the `IGroupListView` view and the underlying group data model (`Group`), handling user interactions (e.g., double-click to edit, filtering/sorting), coordinating background operations (e.g., loading test setup lists), and publishing/subscribing to domain events via `IEventAggregator`. It supports both single- and multi-select group operations and integrates with the Prism region management and Unity DI container.
---
### 2. Public Interface
#### Constructors
- **`GroupListViewModel(IGroupListView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer)`**
Initializes the view model. Sets up the view binding, event subscriptions (e.g., `RaiseNotification`, `BusyIndicatorChangeNotification`), and initializes `SelectedGroupItems` as an `ObservableCollection<IGroup>`.
#### Public Methods
- **`void ClearAllFilters()`**
Clears all per-field filter terms stored in `_filterByField`.
- **`void MouseDoubleClick(int index)`**
If a single group is selected and `index` is valid, publishes a `GroupListEditGroupEvent` with the selected groups `Id`.
- **`void Filter(string term)`**
Sets `CurrentSearchTerm` to `term`, then re-applies sorting (which triggers filtering and re-sorting of `Groups`).
- **`IGroup GetGroup(int? id, bool updateTags = true)`**
Returns the group with the given `id` (if `id >= 0`). If `updateTags` is `true`, updates the global tag cache before fetching. Returns a new empty `Group()` if not found.
- **`IGroup GetGroup(string displayName)`**
Returns the *non-embedded* group matching `displayName`, preferring non-embedded over embedded groups (for backward compatibility with pre-2.0 group types). Returns `null` if none found.
- **`IGroup[] GetGroups(int[] ids)`**
Returns an array of groups whose `Id`s are in `ids`, preserving order only in that groups *not* in `ids` are removed (i.e., order is not guaranteed to match `ids` order).
- **`IGroup[] GetAllGroups()`**
Returns *all* groups (via `Group.GetAllGroups()`), unfiltered and unsorted.
- **`void DeleteGroups(int[] ids)`**
Deletes groups with given `ids`. For each group, nullifies `StaticGroupId` on all related embedded groups, deletes the group, updates `AllGroups`, and re-applies filters. Publishes errors via `PageErrorEvent`.
- **`IGroup CreateGroup()`**
Returns a new unsaved `Group(true)` (likely a new transient instance).
- **`IGroup CreateGroup(SqlDataReader, List<string>, List<int>)`**
Constructs a `Group` from a data reader and hardware/test setup lists.
- **`IGroup CreateGroup(IGroupDbRecord, List<string>, List<int>)`**
Constructs a `Group` from a database record and hardware/test setup lists.
- **`IGroup CreateGroup(List<string>)`**
Constructs a new `Group` with the given `includedHardwareStringList`.
- **`void Filter(object tag, string term)`**
Parses `tag` as a `GroupFields` enum value; if successful, stores `term` in `_filterByField[tag]`, sets `_sortField`, and calls `Filter(term)`.
- **`void OnSetActive(object page, bool groupTile, object o)`**
Sets `Page`, filters `AllGroups` to groups compatible with the current users role/tags, and either calls `GetTestSetupListsAsync()` (if `groupTile == true`) or `Sort()`.
- **`private void GetTestSetupListsAsync()`**
Runs asynchronously: sets app status to busy, iterates over `AllGroups` in parallel to call `g.SetTestSetupLists()`, then re-sorts on the UI thread.
- **`void Unset()`**
Clears `AllGroups`, `Groups`, filters, and publishes `ListViewStatusEvent` with status `Unloaded`.
- **`void Sort(object o, bool bColumnClick)`**
Sorts `AllGroups` by `GroupFields` (parsed from `o`), applies `CurrentSearchTerm` and per-field filters (`GroupFilter`), and sets `Groups`. Updates sort direction on column click.
- **`void Cleanup()` / `Task CleanupAsync()` / `void Initialize()` / `Task InitializeAsync()` / `void Activated()`**
No-op stubs; likely required by Prism or custom interfaces but not implemented.
#### Public Properties
- **`IGroupListView View`** Bound view instance.
- **`InteractionRequest<Notification> NotificationRequest`** For displaying notification popups.
- **`InteractionRequest<Confirmation> ConfirmationRequest`** For confirmation dialogs.
- **`event PropertyChangedEventHandler PropertyChanged`** Implements `INotifyPropertyChanged`.
- **`ObservableCollection<IGroup> SelectedGroupItems`** Tracks selected groups; raises `GroupListGroupSelectedEvent` on change.
- **`IGroup[] Groups`** Currently displayed (filtered + sorted) groups.
- **`bool IsBusy`** Bound to busy indicator; updated via `OnBusyIndicatorNotification`.
- **`bool IsMenuIncluded` / `bool IsNavigationIncluded`** UI toggle flags.
- **`string ListViewId`** `"GroupListView"`; used for event scoping.
- **`int SelectedGroupIndex`** Index of selected group in `Groups`; default `-1`.
#### Private Properties (used in logic)
- **`_filterByField: Dictionary<GroupFields, string>`** Per-field filter terms.
- **`CurrentSearchTerm: string`** Global search term.
- **`_sortField: GroupFields`** Current sort field (default `LastModified`).
- **`_sortAscending: bool`** Sort direction (default `false` = descending).
- **`_comparer: GroupComparer`** Comparison logic for sorting.
---
### 3. Invariants
- `Groups` is always a filtered and sorted subset of `AllGroups`.
- `AllGroups` is always filtered by user role and tag compatibility (via `currentUser.TagCompatible(@group.TagIDs)`).
- `SelectedGroupItems` is an `ObservableCollection`; changes trigger `GroupListGroupSelectedEvent`.
- `_filterByField` stores per-field filter terms; `CurrentSearchTerm` is a global term applied in `Sort`.
- `Groups` is sorted by `_sortField` in `_sortAscending` order using `GroupComparer`.
- `IsBusy` is updated via `BusyIndicatorChangeNotification` event (thread-safe subscription on `PublisherThread`).
- `SelectedGroupItems.CollectionChanged` handler skips updates during flagged "updating" states (via `DTS.Common.Enums.SelectedItemsStatus.GetUpdating`).
---
### 4. Dependencies
#### Imports / Dependencies Used
- **Prism**: `IEventAggregator`, `IRegionManager`, `Unity`, `Prism.Events`, `Prism.Regions`, `Prism.Interactivity`.
- **DTS Common Libraries**:
- `DTS.Common.Events.*` (e.g., `RaiseNotification`, `BusyIndicatorChangeNotification`, `PageErrorEvent`, `AppStatusEvent`, `ProgressBarEvent`, `ListViewStatusEvent`, `GroupListEditGroupEvent`, `GroupListGroupSelectedEvent`)
- `DTS.Common.Interface.Groups.*` (`IGroup`, `IGroupListView`, `IGroupListViewModel`)
- `DTS.Common.Enums.Groups.GroupList.*` (`GroupFields`, `ListViewStatusArg`)
- `DTS.Common.Storage.*` (`DbOperations`)
- `DTS.Slice.Users.User`
- `DTS.Common.Classes.Tags.TagsInstance`
- **.NET**: `System.ComponentModel`, `System.Collections.ObjectModel`, `System.Threading.Tasks`, `System.Linq`, `System.Collections.Specialized`, `System.Windows`, `System.Data.SqlClient.SqlDataReader`.
#### Dependencies on This Module
- `GroupListViewModel` is exported via MEF (`[PartCreationPolicy(CreationPolicy.Shared)]`) and likely consumed by DI container resolution for `IGroupListViewModel`.
- `IGroupListView` must be provided at construction (likely via Prism view injection).
- Other modules subscribe to events it publishes: `GroupListEditGroupEvent`, `GroupListGroupSelectedEvent`, `PageErrorEvent`, `ListViewStatusEvent`.
---
### 5. Gotchas
- **Sorting logic comment**: The `Sort` method contains commented-out logic suggesting a potential bug or inconsistency in handling already-sorted lists (especially for `LastModified`). This may cause unexpected sort direction toggling.
- **`GetGroup(string displayName)` behavior**: Returns only non-embedded groups *if* any exist; otherwise returns `null`. This may hide embedded groups unexpectedly.
- **`GetGroups(int[] ids)` order**: Output order is not guaranteed to match input `ids` order (uses `Contains` in reverse iteration).
- **`SelectedGroupItems` setter**: Unsubscribes from `CollectionChanged` only if `_selectedGroupItems` was non-null *before* assignment. If `SelectedGroupItems` is set multiple times, old handlers may leak if not handled carefully.
- **`OnSetActive` filtering**: Filtering by user role/tag compatibility happens *only* in `OnSetActive`, not in `Filter` or `Sort`. Thus, filtering/sorting operates on already-filtered `AllGroups`.
- **`GetTestSetupListsAsync`**: Runs `SetTestSetupLists()` in parallel (`AsParallel().ForAll`), but UI thread re-sort is done via `Dispatcher.Invoke`. Potential for race conditions if `SetTestSetupLists()` modifies group state accessed during sort.
- **`GroupFilter` case sensitivity**: Uses `CompareOptions.OrdinalIgnoreCase` for all fields, including `LastModified` (stringified) — may yield unexpected matches (e.g., "12" matches "12" but also "12" in "12/12/2023").
- **No validation on `DeleteGroups`**: Does not check if groups are in use (e.g., by tests); relies on underlying `Group.Delete(id)` to handle errors (which are then published via `PageErrorEvent`).
- **`IsDirty` property**: Declared but never set; always `false`.
- **`Cleanup()`/`Initialize()` stubs**: All `Initialize*`, `Cleanup*`, and `Activated()` methods are empty — may indicate incomplete implementation or reliance on external lifecycle management.
None identified beyond those above.