# Phase 13 Research: User Directory ViewModel ## What Exists ### GraphUserDirectoryService (Phase 10) - `GetUsersAsync(clientId, progress?, ct)` → `IReadOnlyList` - Filter: `accountEnabled eq true and userType eq 'Member'` (members only) - Select: displayName, userPrincipalName, mail, department, jobTitle - Uses `PageIterator` for transparent pagination - Reports progress via `IProgress` (running count) - Honors cancellation in page callback ### GraphDirectoryUser Model ```csharp public record GraphDirectoryUser( string DisplayName, string UserPrincipalName, string? Mail, string? Department, string? JobTitle); ``` **GAP**: No `UserType` property — needed for SC3 member/guest in-memory filtering. ### UserAccessAuditViewModel (Phase 7) - Inherits `FeatureViewModelBase` (IsRunning, StatusMessage, ProgressValue, RunCommand, CancelCommand) - People-picker search: `SearchQuery` → debounce → `IGraphUserSearchService.SearchUsersAsync` → `SearchResults` - User selection: `SelectedUsers` (ObservableCollection) → `RunOperationAsync` → audit - Results: `Results` (ObservableCollection) + `ResultsView` (ICollectionView with grouping/filtering) - Two constructors: full (DI) and test (omits export services) - `_currentProfile` tracks active tenant (via TenantSwitchedMessage) - `OnTenantSwitched` clears all state ### ICollectionView Pattern (existing in same ViewModel) ```csharp var cvs = new CollectionViewSource { Source = Results }; ResultsView = cvs.View; ResultsView.GroupDescriptions.Add(new PropertyGroupDescription(...)); ResultsView.Filter = FilterPredicate; // On filter change: ResultsView.Refresh(); ``` ### DI Registration - `IGraphUserDirectoryService` registered as Transient - `UserAccessAuditViewModel` registered as Transient - Currently NOT injected into UserAccessAuditViewModel ## Gaps to Fill 1. **GraphDirectoryUser needs UserType** — add `string? UserType` to record + update MapUser + select 2. **Service needs guest inclusion** — add `bool includeGuests` parameter; when true, drop userType filter 3. **ViewModel needs IGraphUserDirectoryService** — add to both constructors 4. **ViewModel needs browse mode** — mode toggle, directory collection, load command, cancel, filter, sort 5. **DI registration** — add IGraphUserDirectoryService to UserAccessAuditViewModel constructor resolution ## Plan Breakdown 1. **13-01** (Wave 1): Extend GraphDirectoryUser + GraphUserDirectoryService - Add UserType to model - Add userType to select fields - Add `includeGuests` parameter (default false for backward compat) - Update MapUser - Update tests 2. **13-02** (Wave 2): UserAccessAuditViewModel directory browse mode - Inject IGraphUserDirectoryService - Add AuditMode enum (Search/Browse) + IsBrowseMode toggle - Add DirectoryUsers collection + DirectoryUsersView (ICollectionView) - Add LoadDirectoryCommand with own CTS, progress reporting - Add CancelDirectoryLoadCommand - Add IncludeGuests toggle + in-memory filter by UserType - Add DirectoryFilterText + filter predicate (DisplayName, UPN, Department, JobTitle) - Add SortDescription defaults (DisplayName ascending) - Add DirectoryLoadStatus string for "Loading... X users" display - Update OnTenantSwitched to clear directory state - Update DI in App.xaml.cs - Comprehensive tests