--- phase: 09-storage-visualization plan: 01 type: execute wave: 1 depends_on: [] files_modified: - SharepointToolbox/SharepointToolbox.csproj - SharepointToolbox/Core/Models/FileTypeMetric.cs - SharepointToolbox/Services/IStorageService.cs autonomous: true requirements: - VIZZ-01 must_haves: truths: - "LiveCharts2 SkiaSharp WPF package is a NuGet dependency and the project compiles" - "FileTypeMetric record models file extension, total size, and file count" - "IStorageService declares CollectFileTypeMetricsAsync without breaking existing CollectStorageAsync" artifacts: - path: "SharepointToolbox/SharepointToolbox.csproj" provides: "LiveChartsCore.SkiaSharpView.WPF package reference" contains: "LiveChartsCore.SkiaSharpView.WPF" - path: "SharepointToolbox/Core/Models/FileTypeMetric.cs" provides: "Data model for file type breakdown" contains: "record FileTypeMetric" - path: "SharepointToolbox/Services/IStorageService.cs" provides: "Extended interface with file type metrics method" contains: "CollectFileTypeMetricsAsync" key_links: - from: "SharepointToolbox/Services/IStorageService.cs" to: "SharepointToolbox/Core/Models/FileTypeMetric.cs" via: "Return type of CollectFileTypeMetricsAsync" pattern: "IReadOnlyList" --- Add LiveCharts2 NuGet dependency, create the FileTypeMetric data model, and extend IStorageService with a file-type metrics collection method signature. Purpose: Establishes the charting library dependency (VIZZ-01) and the data contracts that all subsequent plans depend on. No implementation yet -- just the NuGet, the model, and the interface. Output: Updated csproj, FileTypeMetric.cs, updated IStorageService.cs @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/STATE.md From SharepointToolbox/Services/IStorageService.cs: ```csharp using Microsoft.SharePoint.Client; using SharepointToolbox.Core.Models; namespace SharepointToolbox.Services; public interface IStorageService { Task> CollectStorageAsync( ClientContext ctx, StorageScanOptions options, IProgress progress, CancellationToken ct); } ``` From SharepointToolbox/Core/Models/StorageScanOptions.cs: ```csharp public record StorageScanOptions(bool PerLibrary = true, bool IncludeSubsites = false, int FolderDepth = 0); ``` From SharepointToolbox/Core/Models/OperationProgress.cs: ```csharp public record OperationProgress(int Current, int Total, string Message) { public static OperationProgress Indeterminate(string message) => new(0, 0, message); } ``` Task 1: Add LiveCharts2 NuGet and create FileTypeMetric model SharepointToolbox/SharepointToolbox.csproj, SharepointToolbox/Core/Models/FileTypeMetric.cs **Step 1:** Add LiveCharts2 WPF NuGet package: ```bash cd "C:\Users\dev\Documents\projets\Sharepoint" dotnet add SharepointToolbox/SharepointToolbox.csproj package LiveChartsCore.SkiaSharpView.WPF --version 2.0.0-rc5.4 ``` This will add the package reference to the csproj. The `--version 2.0.0-rc5.4` is a pre-release RC, so the command may need `--prerelease` flag if it fails. Try with explicit version first; if that fails, use: ```bash dotnet add SharepointToolbox/SharepointToolbox.csproj package LiveChartsCore.SkiaSharpView.WPF --prerelease ``` **Step 2:** Create `SharepointToolbox/Core/Models/FileTypeMetric.cs`: ```csharp namespace SharepointToolbox.Core.Models; /// /// Represents storage consumption for a single file extension across all scanned libraries. /// Produced by IStorageService.CollectFileTypeMetricsAsync and consumed by chart bindings. /// public record FileTypeMetric( /// File extension including dot, e.g. ".docx", ".pdf". Empty string for extensionless files. string Extension, /// Total size in bytes of all files with this extension. long TotalSizeBytes, /// Number of files with this extension. int FileCount) { /// /// Human-friendly display label: ".docx" becomes "DOCX", empty becomes "No Extension". /// public string DisplayLabel => string.IsNullOrEmpty(Extension) ? "No Extension" : Extension.TrimStart('.').ToUpperInvariant(); } ``` Design notes: - Record type for value semantics (same as StorageScanOptions, PermissionSummary patterns) - Extension stored with dot prefix for consistency with Path.GetExtension - DisplayLabel computed property for chart label binding - TotalSizeBytes is long to match StorageNode.TotalSizeBytes type cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5 LiveChartsCore.SkiaSharpView.WPF appears in csproj PackageReference. FileTypeMetric.cs exists with Extension, TotalSizeBytes, FileCount properties and DisplayLabel computed property. Project compiles with 0 errors. Task 2: Extend IStorageService with CollectFileTypeMetricsAsync SharepointToolbox/Services/IStorageService.cs Update `SharepointToolbox/Services/IStorageService.cs` to add a second method for file-type metrics collection. Do NOT modify the existing CollectStorageAsync signature. Replace the file contents with: ```csharp using Microsoft.SharePoint.Client; using SharepointToolbox.Core.Models; namespace SharepointToolbox.Services; public interface IStorageService { /// /// Collects storage metrics per library/folder using SharePoint StorageMetrics API. /// Returns a tree of StorageNode objects with aggregate size data. /// Task> CollectStorageAsync( ClientContext ctx, StorageScanOptions options, IProgress progress, CancellationToken ct); /// /// Enumerates files across all non-hidden document libraries in the site /// and aggregates storage consumption grouped by file extension. /// Uses CSOM CamlQuery to retrieve FileLeafRef and File_x0020_Size per file. /// This is a separate operation from CollectStorageAsync -- it provides /// file-type breakdown data for chart visualization. /// Task> CollectFileTypeMetricsAsync( ClientContext ctx, IProgress progress, CancellationToken ct); } ``` Design notes: - CollectFileTypeMetricsAsync does NOT take StorageScanOptions because file-type enumeration scans ALL non-hidden doc libraries (no per-library/subfolder filtering needed for chart aggregation) - Returns IReadOnlyList sorted by TotalSizeBytes descending (convention -- implementation will handle sorting) - Separate from CollectStorageAsync so existing storage scan flow is untouched cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj --no-incremental 2>&1 | tail -5 IStorageService.cs declares both CollectStorageAsync (unchanged) and CollectFileTypeMetricsAsync (new). Build fails with CS0535 in StorageService.cs (expected -- Plan 09-02 implements the method). If build succeeds, even better. Interface contract is established. - `dotnet restore SharepointToolbox/SharepointToolbox.csproj` succeeds and LiveChartsCore.SkiaSharpView.WPF is resolved - FileTypeMetric.cs exists in Core/Models with record definition - IStorageService.cs has both method signatures - Existing CollectStorageAsync signature is byte-identical to original LiveCharts2 is a project dependency. FileTypeMetric data model is defined. IStorageService has the new CollectFileTypeMetricsAsync method signature. The project compiles (or fails only because StorageService doesn't implement the new method yet -- that is acceptable and expected). After completion, create `.planning/phases/09-storage-visualization/09-01-SUMMARY.md`