---
phase: 14-user-directory-view
plan: 02
type: execute
wave: 2
depends_on: [14-01]
files_modified:
- SharepointToolbox/Views/Tabs/UserAccessAuditView.xaml
autonomous: true
requirements:
- UDIR-05
- UDIR-01
must_haves:
truths:
- "The left panel shows a mode toggle (two RadioButtons: Search / Browse Directory) at the top"
- "When Search mode is selected (IsBrowseMode=false), the existing people-picker GroupBox is visible and the directory panel is collapsed"
- "When Browse mode is selected (IsBrowseMode=true), the directory panel is visible and the people-picker GroupBox is collapsed"
- "The Scan Options GroupBox and Run/Export buttons remain visible in both modes"
- "The directory panel contains: Load Directory button, Cancel button, Include guests checkbox, filter TextBox, status text, user count, and a DataGrid"
- "The DataGrid is bound to DirectoryUsersView with columns: Name, Email, Department, Job Title, Type"
- "The DataGrid has MouseDoubleClick wired to DirectoryDataGrid_MouseDoubleClick code-behind handler"
- "While loading, the status text shows DirectoryLoadStatus and Load button is disabled"
- "A hint text tells users to double-click to add a user to the audit"
- "The SelectedUsers ItemsControl remains visible in both modes (users added from directory appear here)"
artifacts:
- path: "SharepointToolbox/Views/Tabs/UserAccessAuditView.xaml"
provides: "Complete directory browse UI with mode toggle, directory DataGrid, and loading UX"
contains: "DirectoryUsersView"
key_links:
- from: "SharepointToolbox/Views/Tabs/UserAccessAuditView.xaml"
to: "SharepointToolbox/ViewModels/Tabs/UserAccessAuditViewModel.cs"
via: "data binding"
pattern: "IsBrowseMode|DirectoryUsersView|LoadDirectoryCommand|DirectoryFilterText|IncludeGuests"
---
Add the complete directory browse UI to UserAccessAuditView.xaml with mode toggle, directory DataGrid, loading indicators, and seamless integration with the existing audit workflow.
Purpose: SC1-SC4 require visible UI for mode switching, directory display, loading progress, and cancellation. This plan wires all Phase 13 ViewModel properties to the View layer.
Output: Updated UserAccessAuditView.xaml with full directory browse mode.
@C:/Users/dev/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/dev/.claude/get-shit-done/templates/summary.md
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/14-user-directory-view/14-RESEARCH.md
From SharepointToolbox/ViewModels/Tabs/UserAccessAuditViewModel.cs:
```csharp
// Mode toggle
public bool IsBrowseMode { get; set; }
// Directory data
public ObservableCollection DirectoryUsers { get; }
public ICollectionView DirectoryUsersView { get; } // filtered + sorted
public int DirectoryUserCount { get; } // computed filtered count
// Directory commands
public IAsyncRelayCommand LoadDirectoryCommand { get; }
public RelayCommand CancelDirectoryLoadCommand { get; }
public RelayCommand SelectDirectoryUserCommand { get; }
// Directory state
public bool IsLoadingDirectory { get; }
public string DirectoryLoadStatus { get; }
public bool IncludeGuests { get; set; }
public string DirectoryFilterText { get; set; }
// Existing (still visible in both modes)
public ObservableCollection SelectedUsers { get; }
public string SelectedUsersLabel { get; }
public IAsyncRelayCommand RunCommand { get; }
public RelayCommand CancelCommand { get; }
public IAsyncRelayCommand ExportCsvCommand { get; }
public IAsyncRelayCommand ExportHtmlCommand { get; }
```
- `{StaticResource BoolToVisibilityConverter}` — true→Visible, false→Collapsed
- `{StaticResource InverseBoolConverter}` — inverts bool
- `{StaticResource StringToVisibilityConverter}` — non-empty→Visible
```
DockPanel (290px, Margin 8)
├── GroupBox "Select Users" (DockPanel.Dock="Top") — SEARCH MODE (hide when IsBrowseMode)
│ └── SearchQuery, SearchResults, SelectedUsers, SelectedUsersLabel
├── GroupBox "Scan Options" (DockPanel.Dock="Top") — ALWAYS VISIBLE
│ └── CheckBoxes
└── StackPanel (DockPanel.Dock="Top") — ALWAYS VISIBLE
└── Run/Cancel/Export buttons
```
```csharp
private void DirectoryDataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender is DataGrid grid && grid.SelectedItem is GraphDirectoryUser user)
{
var vm = (UserAccessAuditViewModel)DataContext;
if (vm.SelectDirectoryUserCommand.CanExecute(user))
vm.SelectDirectoryUserCommand.Execute(user);
}
}
```
Task 1: Restructure left panel with mode toggle and conditional panels
SharepointToolbox/Views/Tabs/UserAccessAuditView.xaml
- At the top of the left panel DockPanel, a mode toggle section appears with two RadioButtons
- RadioButton "Search" is checked when IsBrowseMode=false (uses InverseBoolConverter)
- RadioButton "Browse Directory" is checked when IsBrowseMode=true
- Below the toggle: existing Search GroupBox (visible when IsBrowseMode=false) OR new Directory GroupBox (visible when IsBrowseMode=true)
- SelectedUsers ItemsControl + label extracted from Search GroupBox and placed in a shared section visible in BOTH modes
- Scan Options GroupBox and buttons remain always visible
- Directory GroupBox contains:
a) Two-button grid: Load Directory + Cancel (like Run/Cancel pattern)
b) CheckBox for IncludeGuests
c) Filter TextBox bound to DirectoryFilterText
d) Status/count row: DirectoryLoadStatus + DirectoryUserCount
e) DataGrid bound to DirectoryUsersView with 5 columns (Name, Email, Department, Job Title, Type)
f) Hint text: "Double-click a user to add to audit"
- DataGrid has MouseDoubleClick="DirectoryDataGrid_MouseDoubleClick"
- DataGrid uses AutoGenerateColumns="False", IsReadOnly="True", virtualization enabled
- DataGrid columns are DataGridTextColumn (simple text, sortable by default)
- Guest users highlighted with a subtle "Guest" badge in the Type column (orange, like the existing UserAccessAuditView pattern)
1. Read the current `UserAccessAuditView.xaml` to get the exact current content.
2. Replace the left panel DockPanel content with the new structure:
```xml
[existing DataTrigger style]
[existing ItemTemplate with blue border badges + x remove button]
[existing checkboxes]
[existing button grids]
```
IMPORTANT NOTES:
- The `BoolToVisibilityConverter` natively shows when true. For the Search panel (show when IsBrowseMode=false), we need inverse behavior. Two approaches:
a) Use a DataTrigger-based Style on Visibility (reliable)
b) Check if BoolToVisibilityConverter supports a ConverterParameter for inversion
Since we're not sure the converter supports inversion, use DataTrigger approach for the Search panel:
```xml
```
And for the Browse panel, use `BoolToVisibilityConverter` directly (shows when IsBrowseMode=true).
- The SelectedUsers ItemsControl must be EXTRACTED from the Search GroupBox and placed in a standalone section — it needs to remain visible when in Browse mode so users can see who they've selected from the directory.
- DataGrid column headers use localized bindings. Note: DataGridTextColumn.Header does NOT support binding in standard WPF — it's not a FrameworkElement. Instead, use DataGridTemplateColumn with HeaderTemplate for localized headers, OR set the Header as a plain string and skip localization for column headers (simpler approach). DECISION: Use plain English headers for DataGrid columns (they are technical column names that don't benefit from localization as much). This avoids the complex HeaderTemplate pattern. Use the localization keys in other UI elements.
Alternative if Header binding works (some WPF versions support it via x:Static): Test with `Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[directory.col.name]}"` — if it compiles and works, great. If not, fall back to plain strings.
dotnet build --no-restore -warnaserrorUserAccessAuditView has full directory browse UI with mode toggle, conditional panels, directory DataGrid, loading status, and double-click selection. Build passes.
```bash
dotnet build --no-restore -warnaserror
```
Build must pass. Visual verification requires manual testing.
- SC1: Mode toggle (RadioButtons) visibly switches left panel between search and browse
- SC2: DataGrid double-click adds user to SelectedUsers; Run Audit button works as usual
- SC3: Loading status shows DirectoryLoadStatus, Load button disabled while loading, Cancel button active
- SC4: Cancel clears loading state; status returns to ready; no broken UI
- SelectedUsers visible in both modes
- DataGrid columns: Name, Email, Department, Job Title, Type (Guest highlighted in orange)
- Filter TextBox and IncludeGuests checkbox functional
- Build passes with zero warnings