Files
Sharepoint-Toolbox/.planning/phases/08-simplified-permissions/08-02-PLAN.md
Dev c871effa87 docs(08-simplified-permissions): create phase plan (6 plans, 5 waves)
Plans cover plain-language permission labels, risk-level color coding,
summary counts, detail-level toggle, export integration, and unit tests.
PermissionEntry record is NOT modified — uses wrapper pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:00:08 +02:00

10 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
08-simplified-permissions 02 execute 2
08-01
SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs
true
SIMP-01
SIMP-02
SIMP-03
truths artifacts key_links
IsSimplifiedMode toggle switches between raw and simplified permission labels in the DataGrid
IsDetailView toggle controls whether individual rows are shown or collapsed into summary rows
Toggling modes does NOT re-run the scan — it re-renders from existing Results data
Summary counts per risk level are available as observable properties when simplified mode is on
SimplifiedResults collection is computed from Results whenever Results changes or mode toggles
ActiveItemsSource provides the correct collection for DataGrid binding depending on current mode
path provides contains
SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs Extended PermissionsViewModel with simplified mode, detail toggle, and summary IsSimplifiedMode
from to via pattern
SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs SharepointToolbox/Core/Helpers/PermissionLevelMapping.cs SimplifiedPermissionEntry.WrapAll uses PermissionLevelMapping internally SimplifiedPermissionEntry.WrapAll
from to via pattern
SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs SharepointToolbox/Core/Models/PermissionSummary.cs PermissionSummaryBuilder.Build computes summary from simplified entries PermissionSummaryBuilder.Build
Extend PermissionsViewModel with IsSimplifiedMode toggle, IsDetailView toggle, SimplifiedResults collection, summary statistics, and an ActiveItemsSource that the DataGrid binds to. All toggles re-render from cached data — no re-scan required.

Purpose: This is the ViewModel logic for all three SIMP requirements. The View (08-03) binds to these new properties. Output: Updated PermissionsViewModel.cs

<execution_context> @C:/Users/dev/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/dev/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/08-simplified-permissions/08-01-SUMMARY.md From SharepointToolbox/Core/Models/RiskLevel.cs: ```csharp public enum RiskLevel { High, Medium, Low, ReadOnly } ```

From SharepointToolbox/Core/Helpers/PermissionLevelMapping.cs:

public static class PermissionLevelMapping
{
    public record MappingResult(string Label, RiskLevel RiskLevel);
    public static MappingResult GetMapping(string roleName);
    public static IReadOnlyList<MappingResult> GetMappings(string permissionLevels);
    public static RiskLevel GetHighestRisk(string permissionLevels);
    public static string GetSimplifiedLabels(string permissionLevels);
}

From SharepointToolbox/Core/Models/SimplifiedPermissionEntry.cs:

public class SimplifiedPermissionEntry
{
    public PermissionEntry Inner { get; }
    public string SimplifiedLabels { get; }
    public RiskLevel RiskLevel { get; }
    public IReadOnlyList<PermissionLevelMapping.MappingResult> Mappings { get; }
    // Passthrough: ObjectType, Title, Url, HasUniquePermissions, Users, UserLogins,
    //              PermissionLevels, GrantedThrough, PrincipalType
    public static IReadOnlyList<SimplifiedPermissionEntry> WrapAll(IEnumerable<PermissionEntry> entries);
}

From SharepointToolbox/Core/Models/PermissionSummary.cs:

public record PermissionSummary(string Label, RiskLevel RiskLevel, int Count, int DistinctUsers);

public static class PermissionSummaryBuilder
{
    public static IReadOnlyList<PermissionSummary> Build(IEnumerable<SimplifiedPermissionEntry> entries);
}

From SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs:

public partial class PermissionsViewModel : FeatureViewModelBase
{
    // Existing fields and services — unchanged
    [ObservableProperty] private ObservableCollection<PermissionEntry> _results = new();
    
    // Existing commands — unchanged
    public IAsyncRelayCommand ExportCsvCommand { get; }
    public IAsyncRelayCommand ExportHtmlCommand { get; }
    public RelayCommand OpenSitePickerCommand { get; }
    
    // Full constructor and test constructor (internal)
}
Task 1: Add simplified mode properties and summary computation to PermissionsViewModel SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs Modify `SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs` to add simplified mode support. Add the following new using statements at the top:
```csharp
using SharepointToolbox.Core.Helpers;
```

Add these new observable properties to the class (in the "Observable properties" section):

```csharp
/// <summary>
/// When true, displays simplified plain-language labels instead of raw SharePoint role names.
/// Toggling does not re-run the scan.
/// </summary>
[ObservableProperty]
private bool _isSimplifiedMode;

/// <summary>
/// When true, shows individual item-level rows (detailed view).
/// When false, shows only summary rows grouped by risk level (simple view).
/// Only meaningful when IsSimplifiedMode is true.
/// </summary>
[ObservableProperty]
private bool _isDetailView = true;
```

Add these computed collection properties (NOT ObservableProperty — manually raised):

```csharp
/// <summary>
/// Simplified wrappers computed from Results. Rebuilt when Results changes.
/// </summary>
private IReadOnlyList<SimplifiedPermissionEntry> _simplifiedResults = Array.Empty<SimplifiedPermissionEntry>();
public IReadOnlyList<SimplifiedPermissionEntry> SimplifiedResults
{
    get => _simplifiedResults;
    private set => SetProperty(ref _simplifiedResults, value);
}

/// <summary>
/// Summary counts grouped by risk level. Rebuilt when SimplifiedResults changes.
/// </summary>
private IReadOnlyList<PermissionSummary> _summaries = Array.Empty<PermissionSummary>();
public IReadOnlyList<PermissionSummary> Summaries
{
    get => _summaries;
    private set => SetProperty(ref _summaries, value);
}

/// <summary>
/// The collection the DataGrid actually binds to. Returns:
/// - Results (raw) when simplified mode is OFF
/// - SimplifiedResults when simplified mode is ON and detail view is ON
/// - (View handles summary display separately via Summaries property)
/// </summary>
public object ActiveItemsSource => IsSimplifiedMode
    ? (object)SimplifiedResults
    : Results;
```

Add partial methods triggered by property changes:

```csharp
partial void OnIsSimplifiedModeChanged(bool value)
{
    if (value && Results.Count > 0)
        RebuildSimplifiedData();
    OnPropertyChanged(nameof(ActiveItemsSource));
}

partial void OnIsDetailViewChanged(bool value)
{
    OnPropertyChanged(nameof(ActiveItemsSource));
}
```

Add a private method to rebuild simplified data from existing Results:

```csharp
/// <summary>
/// Recomputes SimplifiedResults and Summaries from the current Results collection.
/// Called when Results changes or when simplified mode is toggled on.
/// </summary>
private void RebuildSimplifiedData()
{
    SimplifiedResults = SimplifiedPermissionEntry.WrapAll(Results);
    Summaries = PermissionSummaryBuilder.Build(SimplifiedResults);
}
```

Modify the existing `RunOperationAsync` method: after the line that sets `Results = new ObservableCollection<PermissionEntry>(allEntries);` (both in the dispatcher branch and the else branch), add:

```csharp
if (IsSimplifiedMode)
    RebuildSimplifiedData();
OnPropertyChanged(nameof(ActiveItemsSource));
```

So the end of RunOperationAsync becomes (both branches):
```csharp
Results = new ObservableCollection<PermissionEntry>(allEntries);
if (IsSimplifiedMode)
    RebuildSimplifiedData();
OnPropertyChanged(nameof(ActiveItemsSource));
```

Modify `OnTenantSwitched` to also reset simplified state:
After `Results = new ObservableCollection<PermissionEntry>();` add:
```csharp
SimplifiedResults = Array.Empty<SimplifiedPermissionEntry>();
Summaries = Array.Empty<PermissionSummary>();
OnPropertyChanged(nameof(ActiveItemsSource));
```

Do NOT change:
- Constructor signatures (both full and test constructors remain unchanged)
- Existing properties (SiteUrl, IncludeInherited, ScanFolders, etc.)
- ExportCsvCommand and ExportHtmlCommand implementations (export updates are in plan 08-04)
- OpenSitePickerCommand
- _hasLocalSiteOverride / OnGlobalSitesChanged logic
cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5 PermissionsViewModel has IsSimplifiedMode, IsDetailView, SimplifiedResults, Summaries, and ActiveItemsSource properties. Toggling IsSimplifiedMode rebuilds simplified data from cached Results without re-scanning. Toggling IsDetailView triggers ActiveItemsSource change notification. Existing tests still compile (no constructor changes). - `dotnet build SharepointToolbox/SharepointToolbox.csproj` succeeds with 0 errors - `dotnet test SharepointToolbox.Tests/ --filter PermissionsViewModelTests` passes (no constructor changes) - PermissionsViewModel has IsSimplifiedMode, IsDetailView, SimplifiedResults, Summaries, ActiveItemsSource - Toggling IsSimplifiedMode calls RebuildSimplifiedData + raises ActiveItemsSource changed - RunOperationAsync calls RebuildSimplifiedData when IsSimplifiedMode is true - OnTenantSwitched resets SimplifiedResults and Summaries

<success_criteria> The ViewModel is the orchestration layer for SIMP-01/02/03. All mode toggles re-render from cached data. The View (08-03) can bind to IsSimplifiedMode, IsDetailView, ActiveItemsSource, and Summaries. Export services (08-04) can access SimplifiedResults and IsSimplifiedMode. </success_criteria>

After completion, create `.planning/phases/08-simplified-permissions/08-02-SUMMARY.md`