diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index b1e15b2..66c769b 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -25,7 +25,7 @@ - [x] **VIZZ-01**: Storage Metrics tab includes a graph showing space by file type - [x] **VIZZ-02**: User can toggle between pie/donut chart and bar chart views -- [ ] **VIZZ-03**: Graph updates automatically when storage scan completes +- [x] **VIZZ-03**: Graph updates automatically when storage scan completes ## Future Requirements @@ -54,7 +54,7 @@ None deferred — all active requirements scoped to v1.1. | SIMP-03 | Phase 8 | Complete | | VIZZ-01 | Phase 9 | Complete | | VIZZ-02 | Phase 9 | Complete | -| VIZZ-03 | Phase 9 | Pending | +| VIZZ-03 | Phase 9 | Complete | **Coverage:** - v1.1 requirements: 10 total diff --git a/.planning/STATE.md b/.planning/STATE.md index 9fd3c84..0cf9841 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: completed -stopped_at: Completed 09-02-PLAN.md -last_updated: "2026-04-07T13:25:16.593Z" -last_activity: 2026-04-07 — Completed 09-02 (CollectFileTypeMetricsAsync CamlQuery implementation) +stopped_at: Completed 09-03-PLAN.md +last_updated: "2026-04-07T13:37:09.659Z" +last_activity: 2026-04-07 — Completed 09-03 (ViewModel chart properties and View XAML) progress: total_phases: 4 completed_phases: 3 total_plans: 25 - completed_plans: 23 + completed_plans: 24 --- # Project State @@ -25,12 +25,12 @@ See: .planning/PROJECT.md (updated 2026-04-07) ## Current Position Phase: 9 — Storage Visualization -Plan: 2 of 4 -Status: Plan 09-02 complete — CollectFileTypeMetricsAsync CamlQuery implementation -Last activity: 2026-04-07 — Completed 09-02 (CollectFileTypeMetricsAsync CamlQuery implementation) +Plan: 3 of 4 +Status: Plan 09-03 complete — ViewModel chart properties and View XAML +Last activity: 2026-04-07 — Completed 09-03 (ViewModel chart properties and View XAML) ``` -v1.1 Progress: [█████████░] 92% +v1.1 Progress: [██████████] 96% Phase 6 [x] → Phase 7 [x] → Phase 8 [x] → Phase 9 [~] ``` @@ -64,6 +64,7 @@ Phase 6 [x] → Phase 7 [x] → Phase 8 [x] → Phase 9 [~] | Phase 08 P06 | 2 | 2 tasks | 3 files | | Phase 09 P01 | 1 | 2 tasks | 3 files | | Phase 09 P02 | 1 | 1 tasks | 1 files | +| Phase 09 P03 | 573 | 2 tasks | 5 files | ## Accumulated Context @@ -112,6 +113,7 @@ Decisions are logged in PROJECT.md Key Decisions table. - [Phase 09-01]: FileTypeMetric record uses Extension (with dot), TotalSizeBytes (long), FileCount (int), DisplayLabel (computed) matching existing model patterns - [Phase 09-01]: CollectFileTypeMetricsAsync omits StorageScanOptions since file-type scan covers all non-hidden libraries without folder depth filtering - [Phase 09-02]: Added System.IO using explicitly -- WPF project implicit usings do not include System.IO for Path.GetExtension +- [Phase 09]: Used wrapper Grid elements with MultiDataTrigger for LiveCharts2 chart visibility -- more reliable than styling third-party controls directly ### Pending Todos @@ -123,6 +125,6 @@ None. ## Session Continuity -Last session: 2026-04-07T13:25:16.591Z -Stopped at: Completed 09-02-PLAN.md +Last session: 2026-04-07T13:37:09.651Z +Stopped at: Completed 09-03-PLAN.md Resume file: None diff --git a/.planning/phases/09-storage-visualization/09-03-SUMMARY.md b/.planning/phases/09-storage-visualization/09-03-SUMMARY.md new file mode 100644 index 0000000..3aebf7a --- /dev/null +++ b/.planning/phases/09-storage-visualization/09-03-SUMMARY.md @@ -0,0 +1,92 @@ +--- +phase: 09-storage-visualization +plan: 03 +subsystem: storage-visualization +tags: [viewmodel, xaml, charts, livecharts2, localization] +dependency_graph: + requires: [09-01, 09-02] + provides: [chart-ui, chart-toggle, chart-data-binding] + affects: [StorageViewModel, StorageView] +tech_stack: + added: [LiveChartsCore.SkiaSharpView.WPF chart controls in XAML] + patterns: [MultiDataTrigger visibility, ObservableCollection chart binding, top-10 aggregation] +key_files: + created: + - SharepointToolbox/Views/Converters/BytesLabelConverter.cs + modified: + - SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs + - SharepointToolbox/Views/Tabs/StorageView.xaml + - SharepointToolbox/Localization/Strings.resx + - SharepointToolbox/Localization/Strings.fr.resx +decisions: + - "Used wrapper Grid elements with MultiDataTrigger for chart visibility instead of styling LiveCharts controls directly -- more reliable for third-party controls" + - "Removed ToolTipLabelFormatter from ColumnSeries (not available in LiveCharts2 rc5); DataLabelsFormatter provides size labels on bars" + - "Used XML entities for FR accented chars matching existing resx convention" +metrics: + duration: 573s + completed: 2026-04-07 +--- + +# Phase 09 Plan 03: ViewModel Chart Properties and View XAML Summary + +StorageViewModel extended with chart data binding (pie/donut + bar) using LiveCharts2, StorageView updated with split layout (DataGrid + chart panel), chart toggle radio buttons, and EN/FR localization keys. + +## What Was Done + +### Task 1: Extend StorageViewModel with chart data and toggle +- Added LiveCharts2 using statements (LiveChartsCore, SkiaSharpView, SkiaSharp) +- Added IsDonutChart toggle property (ObservableProperty, default true) +- Added FileTypeMetrics ObservableCollection with property-changed notification +- Added HasChartData computed property +- Added PieChartSeries, BarChartSeries, BarXAxes, BarYAxes properties +- Implemented UpdateChartSeries: top-10 by size with "Other" aggregation, PieSeries with configurable InnerRadius for donut mode, ColumnSeries with labeled axes +- Added FormatBytes static helper for chart labels +- Updated RunOperationAsync to call CollectFileTypeMetricsAsync after storage scan +- Updated OnTenantSwitched to clear FileTypeMetrics +- **Commit:** 70048dd + +### Task 2: Update StorageView.xaml with chart panel, toggle, and localization +- Restructured StorageView.xaml: right content area now uses Grid with DataGrid (top), GridSplitter, chart panel (bottom) +- Chart panel contains PieChart and CartesianChart wrapped in Grid elements with MultiDataTrigger visibility (IsDonutChart + HasChartData) +- Added radio button group in left panel for donut/bar chart toggle +- Added "no data" placeholder TextBlock with DataTrigger visibility +- Created BytesLabelConverter for chart tooltip formatting +- Added 5 stor.chart.* localization keys in Strings.resx (EN) and Strings.fr.resx (FR) +- **Commit:** a8d79a8 + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] Removed ToolTipLabelFormatter from ColumnSeries** +- **Found during:** Task 1 +- **Issue:** LiveCharts2 rc5 ColumnSeries does not have ToolTipLabelFormatter property (only PieSeries does) +- **Fix:** Removed the property; DataLabelsFormatter still provides size labels on bar chart columns +- **Files modified:** SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs +- **Commit:** 70048dd + +**2. [Rule 1 - Bug] Used wrapper Grid elements for chart visibility** +- **Found during:** Task 2 +- **Issue:** Setting Style/Visibility directly on LiveCharts WPF controls may not work reliably with third-party controls +- **Fix:** Wrapped each chart in a Grid element and applied MultiDataTrigger visibility on the wrapper instead +- **Files modified:** SharepointToolbox/Views/Tabs/StorageView.xaml +- **Commit:** a8d79a8 + +**3. [Rule 1 - Bug] Used DataTrigger for no-data placeholder visibility** +- **Found during:** Task 2 +- **Issue:** InverseBoolConverter only returns bool, not Visibility; cannot use it with ConverterParameter=Visibility +- **Fix:** Used Style with DataTrigger binding on HasChartData instead of converter approach +- **Files modified:** SharepointToolbox/Views/Tabs/StorageView.xaml +- **Commit:** a8d79a8 + +## Verification + +- `dotnet build SharepointToolbox/SharepointToolbox.csproj` succeeds with 0 errors +- StorageViewModel has all required properties: IsDonutChart, FileTypeMetrics, PieChartSeries, BarChartSeries, BarXAxes, BarYAxes, HasChartData +- RunOperationAsync calls CollectFileTypeMetricsAsync after CollectStorageAsync +- StorageView.xaml contains lvc:PieChart and lvc:CartesianChart controls +- Radio buttons bind to IsDonutChart with InverseBoolConverter for bar option +- Strings.resx and Strings.fr.resx have stor.chart.title, stor.chart.donut, stor.chart.bar, stor.chart.toggle, stor.chart.nodata +- No data placeholder shown via DataTrigger when HasChartData is False + +## Self-Check: PASSED