docs(03-07): complete StorageViewModel and StorageView plan — SUMMARY, STATE, ROADMAP updated
This commit is contained in:
@@ -125,6 +125,6 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. Foundation | 8/8 | Complete | 2026-04-02 |
|
||||
| 2. Permissions | 7/7 | Complete | 2026-04-02 |
|
||||
| 3. Storage and File Operations | 5/8 | In Progress| |
|
||||
| 3. Storage and File Operations | 7/8 | In Progress| |
|
||||
| 4. Bulk Operations and Provisioning | 0/? | Not started | - |
|
||||
| 5. Distribution and Hardening | 0/? | Not started | - |
|
||||
|
||||
@@ -3,14 +3,14 @@ gsd_state_version: 1.0
|
||||
milestone: v1.0
|
||||
milestone_name: milestone
|
||||
status: executing
|
||||
stopped_at: Completed 03-04-PLAN.md — SearchService and DuplicatesService
|
||||
last_updated: "2026-04-02T13:33:35.151Z"
|
||||
stopped_at: Completed 03-07-PLAN.md — StorageViewModel + StorageView XAML + DI Wiring
|
||||
last_updated: "2026-04-02T13:40:06.726Z"
|
||||
last_activity: 2026-04-02 — Plan 03-02 complete — StorageService CSOM scan engine implemented
|
||||
progress:
|
||||
total_phases: 5
|
||||
completed_phases: 2
|
||||
total_plans: 23
|
||||
completed_plans: 20
|
||||
completed_plans: 22
|
||||
percent: 65
|
||||
---
|
||||
|
||||
@@ -80,6 +80,8 @@ Progress: [██████░░░░] 65%
|
||||
| Phase 03-storage P03 | 2min | 2 tasks | 2 files |
|
||||
| Phase 03-storage P06 | 5min | 1 tasks | 3 files |
|
||||
| Phase 03-storage P04 | 2min | 2 tasks | 2 files |
|
||||
| Phase 03-storage P07 | 4min | 2 tasks | 10 files |
|
||||
| Phase 03-storage P05 | 4min | 2 tasks | 3 files |
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
@@ -142,6 +144,10 @@ Recent decisions affecting current work:
|
||||
- [Phase 03-storage 03-04]: SearchService uses SelectProperties.Add per-item loop — StringCollection has no AddRange(string[]) overload in this SDK version
|
||||
- [Phase 03-storage 03-04]: DuplicatesService.MakeKey internal static method matches inline test helper in DuplicatesServiceTests exactly — deliberate design to ensure test parity
|
||||
- [Phase 03-storage 03-04]: DuplicatesService file mode re-implements pagination inline — avoids coupling between services with different result models (DuplicateItem vs SearchResult)
|
||||
- [Phase 03-storage]: ClientContext.Url is read-only in CSOM — site URL override done via new TenantProfile with site URL for GetOrCreateContextAsync
|
||||
- [Phase 03-storage]: IndentConverter/BytesConverter/InverseBoolConverter registered in App.xaml Application.Resources — accessible to all views without per-UserControl declaration
|
||||
- [Phase 03-storage]: SearchCsvExportService uses UTF-8 BOM for Excel compatibility — consistent with Phase 2 CsvExportService pattern
|
||||
- [Phase 03-storage]: DuplicatesHtmlExportService always uses badge-dup (red) for all groups — ok/diff distinction removed from final DUPL-03 spec
|
||||
|
||||
### Pending Todos
|
||||
|
||||
@@ -154,6 +160,6 @@ None yet.
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-04-02T13:33:35.149Z
|
||||
Stopped at: Completed 03-04-PLAN.md — SearchService and DuplicatesService
|
||||
Last session: 2026-04-02T13:39:46.878Z
|
||||
Stopped at: Completed 03-07-PLAN.md — StorageViewModel + StorageView XAML + DI Wiring
|
||||
Resume file: None
|
||||
|
||||
152
.planning/phases/03-storage/03-07-SUMMARY.md
Normal file
152
.planning/phases/03-storage/03-07-SUMMARY.md
Normal file
@@ -0,0 +1,152 @@
|
||||
---
|
||||
phase: 03-storage
|
||||
plan: 07
|
||||
subsystem: ui
|
||||
tags: [wpf, mvvm, datagrid, ivalueconverter, di, storage, xaml]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 03-storage plan 03-02
|
||||
provides: IStorageService/StorageService — storage scan engine
|
||||
- phase: 03-storage plan 03-03
|
||||
provides: StorageCsvExportService, StorageHtmlExportService
|
||||
- phase: 03-storage plan 03-06
|
||||
provides: localization keys for Storage tab UI
|
||||
|
||||
provides:
|
||||
- StorageViewModel: IStorageService orchestration with FlattenNode, export commands, tenant-switching
|
||||
- StorageView.xaml: DataGrid with IndentLevel-based Thickness margin for tree-indent display
|
||||
- StorageView.xaml.cs: code-behind wiring DataContext
|
||||
- IndentConverter, BytesConverter, InverseBoolConverter registered in Application.Resources
|
||||
- RightAlignStyle registered in Application.Resources
|
||||
- Storage tab wired in MainWindow via DI-resolved StorageView
|
||||
|
||||
affects: [03-08, phase-04-teams]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- StorageViewModel uses FeatureViewModelBase + AsyncRelayCommand (same as PermissionsViewModel)
|
||||
- TenantProfile site override via new profile with site URL (ClientContext.Url is read-only)
|
||||
- IValueConverter triple registration in App.xaml: IndentConverter/BytesConverter/InverseBoolConverter
|
||||
- FlattenNode recursive helper assigns IndentLevel pre-Dispatcher.InvokeAsync
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs
|
||||
- SharepointToolbox/Views/Tabs/StorageView.xaml
|
||||
- SharepointToolbox/Views/Tabs/StorageView.xaml.cs
|
||||
- SharepointToolbox/Views/Converters/IndentConverter.cs
|
||||
modified:
|
||||
- SharepointToolbox/App.xaml
|
||||
- SharepointToolbox/App.xaml.cs
|
||||
- SharepointToolbox/MainWindow.xaml
|
||||
- SharepointToolbox/MainWindow.xaml.cs
|
||||
- SharepointToolbox/Services/Export/SearchCsvExportService.cs
|
||||
- SharepointToolbox/Services/Export/SearchHtmlExportService.cs
|
||||
|
||||
key-decisions:
|
||||
- "ClientContext.Url is read-only in CSOM — must create new TenantProfile with site URL for GetOrCreateContextAsync (same approach as PermissionsViewModel)"
|
||||
- "IndentConverter/BytesConverter/InverseBoolConverter registered in App.xaml Application.Resources — accessible to all views without per-UserControl declaration"
|
||||
- "StorageView XAML omits local UserControl.Resources converter declarations — uses Application-level StaticResource references instead"
|
||||
|
||||
patterns-established:
|
||||
- "Site-scoped operations create new TenantProfile{TenantUrl=siteUrl, ClientId/Name from current profile}"
|
||||
- "FlattenNode pre-assigns IndentLevel before Dispatcher.InvokeAsync to avoid cross-thread collection mutation"
|
||||
|
||||
requirements-completed: [STOR-01, STOR-02, STOR-03, STOR-04, STOR-05]
|
||||
|
||||
# Metrics
|
||||
duration: 4min
|
||||
completed: 2026-04-02
|
||||
---
|
||||
|
||||
# Phase 03 Plan 07: StorageViewModel + StorageView XAML + DI Wiring Summary
|
||||
|
||||
**StorageViewModel orchestrating IStorageService via FeatureViewModelBase + StorageView DataGrid with IndentConverter-based tree indentation, fully wired through DI in MainWindow**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** ~4 min
|
||||
- **Started:** 2026-04-02T13:35:02Z
|
||||
- **Completed:** 2026-04-02T13:39:00Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 10
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- StorageViewModel created with RunOperationAsync → IStorageService.CollectStorageAsync, FlattenNode tree-flattening, Dispatcher.InvokeAsync-safe ObservableCollection update
|
||||
- StorageView.xaml DataGrid with IndentLevel-driven Thickness margin, BytesConverter for human-readable sizes, all scan/export controls bound to ViewModel
|
||||
- IndentConverter, BytesConverter, InverseBoolConverter, and RightAlignStyle registered in App.xaml Application.Resources
|
||||
- Storage tab live in MainWindow via DI-resolved StorageView (same pattern as Permissions tab)
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Create StorageViewModel** - `e174a18` (feat)
|
||||
2. **Task 2: Create StorageView XAML + code-behind, update DI and MainWindow wiring** - `e08452d` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs` - Storage tab ViewModel (IStorageService orchestration, export commands, tenant-switching)
|
||||
- `SharepointToolbox/Views/Tabs/StorageView.xaml` - Storage tab XAML (DataGrid + scan controls + export buttons)
|
||||
- `SharepointToolbox/Views/Tabs/StorageView.xaml.cs` - Code-behind wiring DataContext to StorageViewModel
|
||||
- `SharepointToolbox/Views/Converters/IndentConverter.cs` - IndentConverter, BytesConverter, InverseBoolConverter in one file
|
||||
- `SharepointToolbox/App.xaml` - Registered three converters and RightAlignStyle in Application.Resources
|
||||
- `SharepointToolbox/App.xaml.cs` - Phase 3 Storage DI registrations (IStorageService, exports, VM, View)
|
||||
- `SharepointToolbox/MainWindow.xaml` - Added x:Name=StorageTabItem to Storage TabItem
|
||||
- `SharepointToolbox/MainWindow.xaml.cs` - Wired StorageTabItem.Content from DI
|
||||
- `SharepointToolbox/Services/Export/SearchCsvExportService.cs` - Added missing System.IO using
|
||||
- `SharepointToolbox/Services/Export/SearchHtmlExportService.cs` - Added missing System.IO using
|
||||
|
||||
## Decisions Made
|
||||
|
||||
- `ClientContext.Url` is read-only in CSOM — the site URL override is done by creating a new `TenantProfile` with `TenantUrl = SiteUrl` (same ClientId/Name from current profile), passed to `GetOrCreateContextAsync`.
|
||||
- All three converters (IndentConverter, BytesConverter, InverseBoolConverter) registered at Application scope in App.xaml rather than per-view, avoiding duplicate resource key definitions.
|
||||
- `StorageView.xaml` omits local `UserControl.Resources` declarations for converters — references Application-level `StaticResource` instead, keeping the XAML clean.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] Fixed ClientContext.Url read-only assignment in StorageViewModel.RunOperationAsync**
|
||||
- **Found during:** Task 1 (StorageViewModel creation)
|
||||
- **Issue:** Plan included `ctx.Url = SiteUrl.TrimEnd('/')` but `ClientRuntimeContext.Url` is a read-only property in CSOM
|
||||
- **Fix:** Created a new `TenantProfile{TenantUrl=siteUrl, ClientId, Name}` and passed it to `GetOrCreateContextAsync` — the context is keyed by URL so it gets or creates the right session
|
||||
- **Files modified:** `SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs`
|
||||
- **Verification:** Build succeeded with 0 errors
|
||||
- **Committed in:** `e174a18` (Task 1 commit)
|
||||
|
||||
**2. [Rule 3 - Blocking] Added missing System.IO using to SearchCsvExportService and SearchHtmlExportService**
|
||||
- **Found during:** Task 1 build verification
|
||||
- **Issue:** Both Search export services used `File.WriteAllTextAsync` without `using System.IO;` — same established project convention (WPF project does not include System.IO in implicit usings)
|
||||
- **Fix:** Added `using System.IO;` to both files
|
||||
- **Files modified:** `SharepointToolbox/Services/Export/SearchCsvExportService.cs`, `SharepointToolbox/Services/Export/SearchHtmlExportService.cs`
|
||||
- **Verification:** Build succeeded with 0 errors; 82 tests pass
|
||||
- **Committed in:** `e174a18` (Task 1 commit)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 2 auto-fixed (1 bug, 1 blocking)
|
||||
**Impact on plan:** Both auto-fixes necessary for correctness. No scope creep.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
None beyond the two auto-fixed deviations above.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- StorageView is live and functional — users can enter site URL, configure scan options, run scan, and export results
|
||||
- Plans 03-03 (StorageCsvExportService) and 03-06 (localization keys) are prerequisites and were already completed
|
||||
- Ready for Wave 4: Plan 03-08 (SearchViewModel + DuplicatesViewModel + Views + visual checkpoint)
|
||||
- All 82 tests passing, 10 expected skips (CSOM live-connection tests)
|
||||
|
||||
---
|
||||
*Phase: 03-storage*
|
||||
*Completed: 2026-04-02*
|
||||
Reference in New Issue
Block a user