diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index df42f1b..e8765b1 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -8,7 +8,7 @@ ### Global Site Selection - [x] **SITE-01**: User can select one or multiple target sites from the toolbar and all feature tabs use that selection as default -- [ ] **SITE-02**: User can override global site selection per-tab for single-site operations +- [x] **SITE-02**: User can override global site selection per-tab for single-site operations ### User Access Audit @@ -46,7 +46,7 @@ None deferred — all active requirements scoped to v1.1. | Requirement | Phase | Status | |-------------|-------|--------| | SITE-01 | Phase 6 | Complete | -| SITE-02 | Phase 6 | Pending | +| SITE-02 | Phase 6 | Complete | | UACC-01 | Phase 7 | Pending | | UACC-02 | Phase 7 | Pending | | SIMP-01 | Phase 8 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index e5f1347..026108f 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -36,7 +36,7 @@ 2. Selecting sites in the toolbar causes all feature tabs to default to those sites when an operation is run 3. A user can override the global selection on any individual tab without clearing the global state 4. The global site selection persists across tab switches within the same session -**Plans:** 3/5 plans executed +**Plans:** 4/5 plans executed Plans: - [ ] 06-01-PLAN.md — GlobalSitesChangedMessage + FeatureViewModelBase extension - [ ] 06-02-PLAN.md — MainWindowViewModel global selection state + command @@ -86,7 +86,7 @@ Plans: | 3. Storage and File Operations | v1.0 | 8/8 | Complete | 2026-04-02 | | 4. Bulk Operations and Provisioning | v1.0 | 10/10 | Complete | 2026-04-03 | | 5. Distribution and Hardening | v1.0 | 3/3 | Complete | 2026-04-03 | -| 6. Global Site Selection | 3/5 | In Progress| | - | +| 6. Global Site Selection | 4/5 | In Progress| | - | | 7. User Access Audit | v1.1 | 0/? | Not started | - | | 8. Simplified Permissions | v1.1 | 0/? | Not started | - | | 9. Storage Visualization | v1.1 | 0/? | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 9b0193d..0c799dc 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 06-03-PLAN.md — toolbar Select Sites button, localization keys, and dialog factory wiring done -last_updated: "2026-04-07T08:08:43.719Z" +stopped_at: Completed 06-04-PLAN.md — all 6 tab VMs wired to OnGlobalSitesChanged with local override protection +last_updated: "2026-04-07T08:10:03.678Z" last_activity: 2026-04-07 — Roadmap created (Phases 6-9), 10/10 requirements mapped progress: total_phases: 4 completed_phases: 0 total_plans: 5 - completed_plans: 3 + completed_plans: 4 --- # Project State @@ -45,6 +45,7 @@ Phase 6 [ ] → Phase 7 [ ] → Phase 8 [ ] → Phase 9 [ ] | Phase 06-global-site-selection P02 | 8 | 1 tasks | 1 files | | Phase 06-global-site-selection P01 | 2 | 2 tasks | 3 files | | Phase 06-global-site-selection P03 | 2 | 3 tasks | 5 files | +| Phase 06-global-site-selection P04 | 2 | 3 tasks | 6 files | ## Accumulated Context @@ -62,6 +63,9 @@ Decisions are logged in PROJECT.md Key Decisions table. - [Phase 06-01]: FeatureViewModelBase.OnGlobalSitesReceived (private) updates GlobalSites then calls OnGlobalSitesChanged (protected virtual) — separates storage from derived class hooks - [Phase 06-03]: Added using SharepointToolbox.Core.Models to MainWindow.xaml.cs for TenantProfile in SitePickerDialog factory lambda - [Phase 06-03]: toolbar.selectSites.tooltipDisabled added to resources but not wired in XAML — WPF Button disabled tooltip requires style trigger (deferred) +- [Phase 06-global-site-selection]: PermissionsViewModel uses _hasLocalSiteOverride guard for SelectedSites; site picker sets flag, tenant switch resets it +- [Phase 06-global-site-selection]: Single-site VMs use partial void OnSiteUrlChanged to detect local typing; clearing field reverts to global +- [Phase 06-global-site-selection]: BulkMembersViewModel confirmed excluded: no SiteUrl field, CSV-driven per-row site URLs ### Pending Todos @@ -73,6 +77,6 @@ None. ## Session Continuity -Last session: 2026-04-07T08:08:43.717Z -Stopped at: Completed 06-03-PLAN.md — toolbar Select Sites button, localization keys, and dialog factory wiring done +Last session: 2026-04-07T08:10:03.675Z +Stopped at: Completed 06-04-PLAN.md — all 6 tab VMs wired to OnGlobalSitesChanged with local override protection Resume file: None diff --git a/.planning/phases/06-global-site-selection/06-04-SUMMARY.md b/.planning/phases/06-global-site-selection/06-04-SUMMARY.md new file mode 100644 index 0000000..352fc3e --- /dev/null +++ b/.planning/phases/06-global-site-selection/06-04-SUMMARY.md @@ -0,0 +1,119 @@ +--- +phase: 06-global-site-selection +plan: 04 +subsystem: tab-viewmodels +tags: [wpf, mvvm, community-toolkit, global-sites, override-pattern] + +# Dependency graph +requires: + - 06-01 (FeatureViewModelBase.OnGlobalSitesChanged virtual hook) +provides: + - PermissionsViewModel.OnGlobalSitesChanged (multi-site: pre-populates SelectedSites) + - StorageViewModel.OnGlobalSitesChanged (single-site: pre-fills SiteUrl) + - SearchViewModel.OnGlobalSitesChanged (single-site: pre-fills SiteUrl) + - DuplicatesViewModel.OnGlobalSitesChanged (single-site: pre-fills SiteUrl) + - FolderStructureViewModel.OnGlobalSitesChanged (single-site: pre-fills SiteUrl) + - TransferViewModel.OnGlobalSitesChanged (single-site: pre-fills SourceSiteUrl) +affects: + - 06-05-per-tab-override (consumes GlobalSites in RunOperationAsync as fallback) + +# Tech tracking +tech-stack: + added: [] + patterns: + - "partial void OnXxxChanged — CommunityToolkit partial property change notification used to detect local user input and set override flag" + - "_hasLocalSiteOverride / _hasLocalSourceSiteOverride field pattern — prevents global site changes from overwriting user's local entry" + - "Tenant switch resets override flag — ensures fresh tenant starts with global site pre-fill active" + +key-files: + created: [] + modified: + - SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs + - SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs + - SharepointToolbox/ViewModels/Tabs/SearchViewModel.cs + - SharepointToolbox/ViewModels/Tabs/DuplicatesViewModel.cs + - SharepointToolbox/ViewModels/Tabs/FolderStructureViewModel.cs + - SharepointToolbox/ViewModels/Tabs/TransferViewModel.cs + +key-decisions: + - "PermissionsViewModel uses _hasLocalSiteOverride to guard SelectedSites; site picker dialog sets flag to true, tenant switch resets it to false" + - "Single-site VMs use partial void OnSiteUrlChanged to detect local typing; clearing the field reverts to global, non-empty different value sets override" + - "BulkMembersViewModel excluded: confirmed no SiteUrl field (CSV-driven per-row site URLs)" + - "SettingsViewModel, BulkSitesViewModel, TemplatesViewModel excluded per CONTEXT decisions — not modified" + +# Metrics +duration: 2min +completed: 2026-04-07 +requirements-completed: + - SITE-01 + - SITE-02 +--- + +# Phase 06 Plan 04: Tab ViewModels Global Site Consumption Summary + +**All 6 consuming tab ViewModels wired to override OnGlobalSitesChanged — PermissionsViewModel pre-populates SelectedSites (multi-site), 4 single-site tabs pre-fill SiteUrl, TransferViewModel pre-fills SourceSiteUrl, all with local-override protection via _hasLocalSiteOverride flag** + +## Performance + +- **Duration:** ~2 min +- **Started:** 2026-04-07T08:06:19Z +- **Completed:** 2026-04-07T08:08:35Z +- **Tasks:** 3 +- **Files modified:** 6 + +## Accomplishments + +- PermissionsViewModel: Added `OnGlobalSitesChanged` override that pre-populates `SelectedSites` from global sites when no local override is active +- PermissionsViewModel: Site picker dialog (`ExecuteOpenSitePicker`) now sets `_hasLocalSiteOverride = true` before clearing/repopulating SelectedSites +- PermissionsViewModel: `OnTenantSwitched` resets `_hasLocalSiteOverride = false` so new tenant immediately uses global sites +- StorageViewModel, SearchViewModel, DuplicatesViewModel, FolderStructureViewModel: Added identical `OnGlobalSitesChanged` + `partial void OnSiteUrlChanged` + `_hasLocalSiteOverride` pattern +- TransferViewModel: Added `OnGlobalSitesChanged` + `partial void OnSourceSiteUrlChanged` + `_hasLocalSourceSiteOverride` pattern for `SourceSiteUrl` +- BulkMembersViewModel confirmed excluded — no `SiteUrl` field, CSV-driven, no changes made +- All 134 tests pass (0 failures, 22 skipped — same baseline as plan 06-01) +- Build succeeds with 0 errors, 0 warnings + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Update PermissionsViewModel for multi-site global consumption** - `1bf47b5` (feat) +2. **Task 2: Update single-site tab VMs (Storage, Search, Duplicates, FolderStructure)** - `6a2e4d1` (feat) +3. **Task 3: Update TransferViewModel and verify BulkMembersViewModel excluded** - `0a91dd4` (feat) + +## Files Created/Modified + +- `SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs` — Added `_hasLocalSiteOverride`, `OnGlobalSitesChanged`, updated `ExecuteOpenSitePicker` and `OnTenantSwitched` +- `SharepointToolbox/ViewModels/Tabs/StorageViewModel.cs` — Added `_hasLocalSiteOverride`, `OnGlobalSitesChanged`, `OnSiteUrlChanged`, updated `OnTenantSwitched` +- `SharepointToolbox/ViewModels/Tabs/SearchViewModel.cs` — Added `_hasLocalSiteOverride`, `OnGlobalSitesChanged`, `OnSiteUrlChanged`, updated `OnTenantSwitched` +- `SharepointToolbox/ViewModels/Tabs/DuplicatesViewModel.cs` — Added `_hasLocalSiteOverride`, `OnGlobalSitesChanged`, `OnSiteUrlChanged`, updated `OnTenantSwitched` +- `SharepointToolbox/ViewModels/Tabs/FolderStructureViewModel.cs` — Added `_hasLocalSiteOverride`, `OnGlobalSitesChanged`, `OnSiteUrlChanged`, updated `OnTenantSwitched` +- `SharepointToolbox/ViewModels/Tabs/TransferViewModel.cs` — Added `_hasLocalSourceSiteOverride`, `OnGlobalSitesChanged`, `OnSourceSiteUrlChanged`, updated `OnTenantSwitched` + +## Decisions Made + +- Used `partial void OnSiteUrlChanged` (CommunityToolkit partial method) to detect user typing — this fires for every programmatic and user-driven change, so the guard `value != GlobalSites[0].Url` ensures global pre-fills don't incorrectly set the override flag +- When user clears SiteUrl (empty string), the override resets and global is re-applied immediately — design choice to make clearing feel like "go back to global" +- PermissionsViewModel pattern differs from single-site VMs: it has no `OnSiteUrlChanged` because its authoritative input is `SelectedSites` (managed by site picker dialog), not free text + +## Deviations from Plan + +None — plan executed exactly as written. BulkMembersViewModel was confirmed to have no `SiteUrl` field as expected. + +## Issues Encountered + +None. + +## User Setup Required + +None — no external service configuration required. + +## Self-Check: PASSED + +All 7 expected files found. All 3 task commits verified in git log. + +## Next Phase Readiness + +- All 6 consuming tab VMs now react to `GlobalSitesChangedMessage` automatically +- Local override pattern is consistent across all tabs — users can type freely without clearing global state +- Plan 06-05 (per-tab override enforcement in RunOperationAsync) can proceed +- No blockers