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>
82 lines
4.6 KiB
Markdown
82 lines
4.6 KiB
Markdown
---
|
|
phase: 03
|
|
plan: 08
|
|
subsystem: ui-viewmodels
|
|
tags: [wpf, viewmodel, search, duplicates, di, xaml]
|
|
dependency_graph:
|
|
requires: [03-05, 03-06, 03-07]
|
|
provides: [SearchViewModel, DuplicatesViewModel, SearchView, DuplicatesView, Phase3-DI]
|
|
affects: [App.xaml.cs, MainWindow.xaml, MainWindow.xaml.cs]
|
|
tech_stack:
|
|
added: []
|
|
patterns: [FeatureViewModelBase, AsyncRelayCommand, TenantProfile-site-override, DI-tab-wiring]
|
|
key_files:
|
|
created:
|
|
- SharepointToolbox/ViewModels/Tabs/SearchViewModel.cs
|
|
- SharepointToolbox/Views/Tabs/SearchView.xaml
|
|
- SharepointToolbox/Views/Tabs/SearchView.xaml.cs
|
|
- SharepointToolbox/ViewModels/Tabs/DuplicatesViewModel.cs
|
|
- SharepointToolbox/Views/Tabs/DuplicatesView.xaml
|
|
- SharepointToolbox/Views/Tabs/DuplicatesView.xaml.cs
|
|
modified:
|
|
- SharepointToolbox/App.xaml.cs
|
|
- SharepointToolbox/MainWindow.xaml
|
|
- SharepointToolbox/MainWindow.xaml.cs
|
|
decisions:
|
|
- SearchViewModel and DuplicatesViewModel use TenantProfile site URL override pattern — ctx.Url is read-only in CSOM (established pattern from StorageViewModel)
|
|
- DuplicateRow flat DTO wraps DuplicateItem with GroupName and GroupSize for DataGrid display
|
|
metrics:
|
|
duration: 4min
|
|
completed_date: "2026-04-02"
|
|
tasks: 3
|
|
files: 9
|
|
---
|
|
|
|
# Phase 3 Plan 08: SearchViewModel + DuplicatesViewModel + Views + DI Wiring Summary
|
|
|
|
**One-liner:** SearchViewModel and DuplicatesViewModel with full XAML views wired into MainWindow via DI, completing Phase 3 Storage feature tabs.
|
|
|
|
## Tasks Completed
|
|
|
|
| # | Name | Commit | Files |
|
|
|---|------|--------|-------|
|
|
| 1a | SearchViewModel + SearchView | 7e6d39a | SearchViewModel.cs, SearchView.xaml, SearchView.xaml.cs |
|
|
| 1b | DuplicatesViewModel + DuplicatesView | 0984a36 | DuplicatesViewModel.cs, DuplicatesView.xaml, DuplicatesView.xaml.cs |
|
|
| 2 | DI registration + MainWindow wiring | 1f2a49d | App.xaml.cs, MainWindow.xaml, MainWindow.xaml.cs |
|
|
|
|
## What Was Built
|
|
|
|
**SearchViewModel** (`SearchViewModel.cs`): Full filter state (extensions, regex, 4 date range checkboxes, createdBy, modifiedBy, library, maxResults), `RunOperationAsync` that calls `ISearchService.SearchFilesAsync`, `ExportCsvCommand` + `ExportHtmlCommand` with CanExport guard, `OnTenantSwitched` clears results.
|
|
|
|
**SearchView.xaml**: Left filter panel (260px ScrollViewer) with GroupBox for filters, Run Search + Cancel buttons, Export CSV/HTML group, status TextBlock. Right: full-width DataGrid with 8 columns (name, ext, created, author, modified, modifiedBy, size, path) using `BytesConverter` and `RightAlignStyle`.
|
|
|
|
**DuplicatesViewModel** (`DuplicatesViewModel.cs`): Mode (Files/Folders), 5 criteria checkboxes, IncludeSubsites, Library, `RunOperationAsync` that calls `IDuplicatesService.ScanDuplicatesAsync`, flattens `DuplicateGroup.Items` to flat `DuplicateRow` list for DataGrid, `ExportHtmlCommand`.
|
|
|
|
**DuplicatesView.xaml**: Left options panel (240px) with type RadioButtons, criteria checkboxes, library TextBox, IncludeSubsites checkbox, Run Scan + Cancel + Export HTML buttons. Right: DataGrid with group, copies, name, library, size, created, modified, path columns.
|
|
|
|
**DI + Wiring**: App.xaml.cs registers all Phase 3 Search and Duplicates services and views. MainWindow.xaml replaces FeatureTabBase stubs with named TabItems. MainWindow.xaml.cs wires content from DI.
|
|
|
|
## Deviations from Plan
|
|
|
|
### Auto-fixed Issues
|
|
|
|
**1. [Rule 1 - Bug] Fixed ctx.Url read-only error in SearchViewModel**
|
|
- **Found during:** Task 1a verification build
|
|
- **Issue:** Plan code used `ctx.Url = SiteUrl.TrimEnd('/')` — `ClientRuntimeContext.Url` is read-only in CSOM (CS0200)
|
|
- **Fix:** Replaced with `new TenantProfile { TenantUrl = SiteUrl.TrimEnd('/'), ClientId = ..., Name = ... }` and passed to `GetOrCreateContextAsync` — identical to StorageViewModel pattern documented in STATE.md
|
|
- **Files modified:** SearchViewModel.cs
|
|
- **Commit:** 7e6d39a (fix applied in same commit)
|
|
|
|
**2. [Rule 1 - Bug] Pre-emptively fixed ctx.Url in DuplicatesViewModel**
|
|
- **Found during:** Task 1b (same issue pattern as Task 1a)
|
|
- **Issue:** Plan code also used `ctx.Url =` for DuplicatesViewModel
|
|
- **Fix:** Same TenantProfile override pattern applied before writing the file
|
|
- **Files modified:** DuplicatesViewModel.cs
|
|
- **Commit:** 0984a36
|
|
|
|
## Pre-existing Test Failure (Out of Scope)
|
|
|
|
`FeatureViewModelBaseTests.CancelCommand_DuringOperation_SetsStatusMessageToCancelled` fails because test asserts `.Contains("cancel")` (case-insensitive) but the app returns French string "Opération annulée". This failure predates this plan (confirmed via git stash test). Out of scope — logged to deferred items.
|
|
|
|
## Self-Check: PASSED
|