All checks were successful
Release zip package / release (push) Successful in 10s
Archive 5 phases (36 plans) to milestones/v1.0-phases/. Archive roadmap, requirements, and audit to milestones/. Evolve PROJECT.md with shipped state and validated requirements. Collapse ROADMAP.md to one-line milestone summary. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
253 lines
12 KiB
Markdown
253 lines
12 KiB
Markdown
---
|
|
phase: 02-permissions
|
|
plan: 07
|
|
type: execute
|
|
wave: 4
|
|
depends_on:
|
|
- 02-06
|
|
files_modified:
|
|
- SharepointToolbox/Views/Tabs/PermissionsView.xaml
|
|
- SharepointToolbox/Views/Tabs/PermissionsView.xaml.cs
|
|
- SharepointToolbox/App.xaml.cs
|
|
- SharepointToolbox/MainWindow.xaml
|
|
- SharepointToolbox/MainWindow.xaml.cs
|
|
autonomous: false
|
|
requirements:
|
|
- PERM-01
|
|
- PERM-02
|
|
- PERM-03
|
|
- PERM-04
|
|
- PERM-05
|
|
- PERM-06
|
|
- PERM-07
|
|
|
|
must_haves:
|
|
truths:
|
|
- "The Permissions tab in the running application shows PermissionsView — not the 'Coming soon' FeatureTabBase stub"
|
|
- "User can enter a site URL, click Generate Report, see progress, and results appear in a DataGrid"
|
|
- "User can click Export CSV and Export HTML — file save dialog appears and file is created"
|
|
- "Scan Options panel shows checkboxes for Scan Folders, Include Inherited Permissions, and a Folder Depth input"
|
|
- "View Sites button opens SitePickerDialog and selected sites appear as '{N} site(s) selected' label"
|
|
- "Cancel button stops the scan mid-operation"
|
|
artifacts:
|
|
- path: "SharepointToolbox/Views/Tabs/PermissionsView.xaml"
|
|
provides: "Complete Permissions tab UI"
|
|
- path: "SharepointToolbox/Views/Tabs/PermissionsView.xaml.cs"
|
|
provides: "Code-behind: sets DataContext, wires dialog factory"
|
|
- path: "SharepointToolbox/App.xaml.cs"
|
|
provides: "DI registration for Phase 2 services"
|
|
contains: "PermissionsViewModel"
|
|
- path: "SharepointToolbox/MainWindow.xaml"
|
|
provides: "Permissions TabItem uses PermissionsView instead of FeatureTabBase stub"
|
|
key_links:
|
|
- from: "PermissionsView.xaml.cs"
|
|
to: "PermissionsViewModel"
|
|
via: "DataContext = ServiceProvider.GetRequiredService<PermissionsViewModel>()"
|
|
pattern: "GetRequiredService.*PermissionsViewModel"
|
|
- from: "PermissionsView.xaml.cs"
|
|
to: "SitePickerDialog"
|
|
via: "viewModel.OpenSitePickerDialog factory"
|
|
pattern: "OpenSitePickerDialog"
|
|
- from: "App.xaml.cs"
|
|
to: "PermissionsViewModel, PermissionsService, SiteListService, CsvExportService, HtmlExportService"
|
|
via: "services.AddTransient / AddScoped"
|
|
pattern: "AddTransient.*Permissions"
|
|
---
|
|
|
|
<objective>
|
|
Create PermissionsView XAML, wire it into MainWindow replacing the FeatureTabBase stub, register all Phase 2 services in DI, and checkpoint with a human visual verification of the running application.
|
|
|
|
Purpose: This is the integration plan — all services exist, ViewModel exists, now wire everything together and confirm the full feature works end-to-end in the UI.
|
|
Output: PermissionsView.xaml + .cs, updated App.xaml.cs DI, updated MainWindow.xaml.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
|
|
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/phases/02-permissions/02-RESEARCH.md
|
|
|
|
<interfaces>
|
|
<!-- DI registration pattern from Phase 1 (App.xaml.cs) -->
|
|
<!-- ProfileManagementDialog and SettingsView are registered as Transient -->
|
|
<!-- MainWindowViewModel is registered as Singleton -->
|
|
<!-- IServiceProvider is injected into MainWindow constructor -->
|
|
|
|
From MainWindow.xaml (current stub — line 45 is the Permissions tab):
|
|
```xml
|
|
<!-- TabControl: 7 stub tabs use FeatureTabBase; Settings tab wired in plan 01-07 -->
|
|
<!-- Tab order: Permissions, Storage, File Search, Duplicates, Templates, Folder Structure, Bulk Ops -->
|
|
<TabItem Header="Permissions">
|
|
<controls:FeatureTabBase /> <!-- REPLACE THIS with <views:PermissionsView /> -->
|
|
</TabItem>
|
|
```
|
|
|
|
PermissionsView code-behind wiring pattern (same as SettingsView from Phase 1):
|
|
```csharp
|
|
public partial class PermissionsView : UserControl
|
|
{
|
|
public PermissionsView(IServiceProvider serviceProvider)
|
|
{
|
|
InitializeComponent();
|
|
var vm = serviceProvider.GetRequiredService<PermissionsViewModel>();
|
|
DataContext = vm;
|
|
// Wire dialog factory — avoids Window/DI coupling in ViewModel (Phase 1 pattern)
|
|
vm.OpenSitePickerDialog = () => serviceProvider.GetRequiredService<SitePickerDialog>();
|
|
}
|
|
}
|
|
```
|
|
|
|
SitePickerDialog needs the current TenantProfile — pass it via a factory:
|
|
```csharp
|
|
// In PermissionsView code-behind, the dialog factory must pass the current profile from the ViewModel:
|
|
vm.OpenSitePickerDialog = () => serviceProvider.GetRequiredService<Func<TenantProfile, SitePickerDialog>>()(vm.CurrentProfile!);
|
|
// Register in DI: services.AddTransient<Func<TenantProfile, SitePickerDialog>>(sp =>
|
|
// profile => new SitePickerDialog(sp.GetRequiredService<ISiteListService>(), profile));
|
|
```
|
|
|
|
PermissionsView DataGrid columns (results binding):
|
|
- Object Type (ObjectType)
|
|
- Title
|
|
- URL (as hyperlink or plain text)
|
|
- Has Unique Permissions (HasUniquePermissions — bool, display as Yes/No)
|
|
- Users
|
|
- Permission Levels (PermissionLevels)
|
|
- Granted Through (GrantedThrough)
|
|
- Principal Type (PrincipalType)
|
|
|
|
All text in XAML uses TranslationSource binding: `{Binding [btn.gen.perms], Source={x:Static loc:TranslationSource.Instance}}`
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create PermissionsView XAML + code-behind and register DI</name>
|
|
<files>
|
|
SharepointToolbox/Views/Tabs/PermissionsView.xaml
|
|
SharepointToolbox/Views/Tabs/PermissionsView.xaml.cs
|
|
SharepointToolbox/App.xaml.cs
|
|
SharepointToolbox/MainWindow.xaml
|
|
SharepointToolbox/MainWindow.xaml.cs
|
|
</files>
|
|
<action>
|
|
READ App.xaml.cs and MainWindow.xaml before modifying to understand existing structure.
|
|
|
|
Step 1 — Create PermissionsView.xaml:
|
|
WPF UserControl. Layout with a Grid split into:
|
|
- Left panel (~280px): Scan configuration
|
|
- GroupBox "Scan Options" (bound to `[grp.scan.opts]`):
|
|
- TextBlock + TextBox for SiteUrl (bound to `{Binding SiteUrl}`)
|
|
- Button "View Sites" (bound to `{Binding [btn.view.sites]}`, Command=`{Binding OpenSitePickerCommand}`)
|
|
- TextBlock showing `{Binding SitesSelectedLabel}` (e.g., "3 site(s) selected") — expose this as [ObservableProperty] in ViewModel
|
|
- CheckBox "Scan Folders" (bound to `{Binding ScanFolders}`)
|
|
- CheckBox "Include Inherited Permissions" (bound to `{Binding IncludeInherited}`)
|
|
- CheckBox "Recursive (subsites)" (bound to `{Binding IncludeSubsites}`)
|
|
- Label + TextBox for FolderDepth (bound to `{Binding FolderDepth}`)
|
|
- CheckBox "Maximum (all levels)" — when checked sets FolderDepth to 999
|
|
- Buttons row: "Generate Report" (bound to `{Binding RunCommand}`), "Cancel" (bound to `{Binding CancelCommand}`)
|
|
- Buttons row: "Export CSV" (bound to `{Binding ExportCsvCommand}`), "Export HTML" (bound to `{Binding ExportHtmlCommand}`)
|
|
- Right panel (remaining space): Results DataGrid
|
|
- DataGrid bound to `{Binding Results}`, AutoGenerateColumns=False, IsReadOnly=True, VirtualizingPanel.IsVirtualizing=True, EnableRowVirtualization=True
|
|
- Columns: ObjectType, Title, Url, HasUniquePermissions (display Yes/No via StringFormat or converter), Users, PermissionLevels, GrantedThrough, PrincipalType
|
|
- Bottom StatusBar: ProgressBar (bound to `{Binding ProgressValue}`) + TextBlock (bound to `{Binding StatusMessage}`)
|
|
|
|
Step 2 — Create PermissionsView.xaml.cs code-behind:
|
|
```csharp
|
|
public partial class PermissionsView : UserControl
|
|
{
|
|
public PermissionsView(IServiceProvider serviceProvider)
|
|
{
|
|
InitializeComponent();
|
|
var vm = serviceProvider.GetRequiredService<PermissionsViewModel>();
|
|
DataContext = vm;
|
|
vm.OpenSitePickerDialog = () =>
|
|
{
|
|
var factory = serviceProvider.GetRequiredService<Func<TenantProfile, SitePickerDialog>>();
|
|
return factory(vm.CurrentProfile ?? new TenantProfile());
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
Step 3 — Update App.xaml.cs DI registrations. Add inside the `ConfigureServices` method:
|
|
```csharp
|
|
// Phase 2: Permissions
|
|
services.AddTransient<IPermissionsService, PermissionsService>();
|
|
services.AddTransient<ISiteListService, SiteListService>();
|
|
services.AddTransient<CsvExportService>();
|
|
services.AddTransient<HtmlExportService>();
|
|
services.AddTransient<PermissionsViewModel>();
|
|
services.AddTransient<PermissionsView>();
|
|
services.AddTransient<SitePickerDialog>();
|
|
services.AddTransient<Func<TenantProfile, SitePickerDialog>>(sp =>
|
|
profile => new SitePickerDialog(sp.GetRequiredService<ISiteListService>(), profile));
|
|
```
|
|
|
|
Step 4 — Update MainWindow.xaml: replace the FIRST `<controls:FeatureTabBase />` (the Permissions tab) with:
|
|
```xml
|
|
<TabItem>
|
|
<TabItem.Header>
|
|
<TextBlock Text="{Binding [tab.permissions], Source={x:Static loc:TranslationSource.Instance}}"/>
|
|
</TabItem.Header>
|
|
<views:PermissionsView />
|
|
</TabItem>
|
|
```
|
|
Add `xmlns:views="clr-namespace:SharepointToolbox.Views.Tabs"` to the Window namespaces if not already present.
|
|
Add localization key `tab.permissions` = "Permissions" (EN) / "Permissions" (FR — same word) to resx files and Strings.Designer.cs.
|
|
|
|
Step 5 — Update MainWindow.xaml.cs if needed to resolve PermissionsView from DI (same pattern used for SettingsView — check existing code for how the Settings tab UserControl is created).
|
|
</action>
|
|
<verify>
|
|
<automated>dotnet build C:/Users/dev/Documents/projets/Sharepoint/SharepointToolbox.slnx 2>&1 | tail -5</automated>
|
|
</verify>
|
|
<done>dotnet build succeeds with 0 errors. All services registered in DI. PermissionsView compiles. MainWindow.xaml has `<views:PermissionsView />` instead of `<controls:FeatureTabBase />` for the Permissions tab.</done>
|
|
</task>
|
|
|
|
<task type="checkpoint:human-verify" gate="blocking">
|
|
<name>Checkpoint: Visual verification of Permissions tab in running application</name>
|
|
<action>Human verifies the running application visually as described in how-to-verify below.</action>
|
|
<verify>
|
|
<automated>HUMAN — run app and confirm checklist: tab visible, scan options present, export buttons disabled, French locale works</automated>
|
|
</verify>
|
|
<done>Human types "approved" confirming all 7 checklist items pass.</done>
|
|
<what-built>
|
|
Full Permissions tab: scan configuration panel, DataGrid results display, export buttons, site picker dialog. All Phase 2 services registered in DI. The tab replaces the previous "Coming soon" stub.
|
|
</what-built>
|
|
<how-to-verify>
|
|
1. Run the application (F5 or `dotnet run --project SharepointToolbox`)
|
|
2. The Permissions tab is visible in the tab bar — it shows the scan options panel and an empty DataGrid (not "Coming soon")
|
|
3. The Scan Options panel shows: Site URL input, View Sites button, Scan Folders checkbox, Include Inherited Permissions checkbox, Recursive checkbox, Folder Depth input, Generate Report button, Cancel button, Export CSV button, Export HTML button
|
|
4. Click "View Sites" — SitePickerDialog opens (may fail with auth error if not connected to a tenant — that is expected; verify the dialog opens and shows a loading state or error, not a crash)
|
|
5. Export CSV / Export HTML buttons are disabled (grayed out) when no results are loaded
|
|
6. Switch the language to French (Settings tab) — all Permissions tab labels change to French text (no English fallback visible)
|
|
7. The Cancel button exists and is disabled when no scan is running
|
|
</how-to-verify>
|
|
<resume-signal>Type "approved" if all verifications pass, or describe what is wrong</resume-signal>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `dotnet build C:/Users/dev/Documents/projets/Sharepoint/SharepointToolbox.slnx` → 0 errors
|
|
- `dotnet test C:/Users/dev/Documents/projets/Sharepoint/SharepointToolbox.slnx` → all tests pass (Phase 1 + Phase 2)
|
|
- MainWindow.xaml no longer has `<controls:FeatureTabBase />` for the Permissions tab position
|
|
- App.xaml.cs contains `AddTransient<IPermissionsService, PermissionsService>()`
|
|
- Human confirms: Permissions tab visible and functional in running app
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Running application shows Permissions tab with full UI (not a stub)
|
|
- All Phase 2 services registered in DI: IPermissionsService, ISiteListService, CsvExportService, HtmlExportService
|
|
- Language switching works — all Phase 2 labels translate to French
|
|
- Export buttons are disabled when no results; enabled after scan completes
|
|
- Full test suite passes (Phase 1 + Phase 2: target ~50+ tests passing)
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/02-permissions/02-07-SUMMARY.md`
|
|
</output>
|