Files
Sharepoint-Toolbox/.planning/milestones/v1.0-phases/01-foundation/01-07-PLAN.md
Dev 724fdc550d chore: complete v1.0 milestone
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>
2026-04-07 09:19:03 +02:00

13 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
01-foundation 07 execute 6
01-06
SharepointToolbox/Views/Dialogs/ProfileManagementDialog.xaml
SharepointToolbox/Views/Dialogs/ProfileManagementDialog.xaml.cs
SharepointToolbox/Views/Tabs/SettingsView.xaml
SharepointToolbox/Views/Tabs/SettingsView.xaml.cs
SharepointToolbox/Views/MainWindow.xaml
true
FOUND-02
FOUND-09
FOUND-12
truths artifacts key_links
ProfileManagementDialog opens as a modal window from the Manage Profiles button
User can add a new profile (Name + Tenant URL + Client ID fields) and it appears in the toolbar ComboBox
User can rename and delete existing profiles in the dialog
SettingsView has a language ComboBox (English / French) and a data folder TextBox with Browse button
Changing language in SettingsView switches the UI language immediately without restart
Data folder setting persists to Sharepoint_Settings.json
path provides contains
SharepointToolbox/Views/Dialogs/ProfileManagementDialog.xaml Modal dialog for profile CRUD ProfileManagementViewModel
path provides contains
SharepointToolbox/Views/Tabs/SettingsView.xaml Settings tab content with language and folder controls TranslationSource
from to via pattern
SharepointToolbox/Views/Dialogs/ProfileManagementDialog.xaml SharepointToolbox/ViewModels/ProfileManagementViewModel.cs DataContext = viewModel (constructor injected) DataContext
from to via pattern
SharepointToolbox/Views/Tabs/SettingsView.xaml SharepointToolbox/Localization/TranslationSource.cs Language ComboBox selection sets TranslationSource.Instance.CurrentCulture TranslationSource
from to via pattern
SharepointToolbox/Views/MainWindow.xaml SharepointToolbox/Views/Tabs/SettingsView.xaml Settings TabItem ContentTemplate or direct UserControl reference SettingsView
Build the two user-facing views completing Phase 1 UX: ProfileManagementDialog (profile CRUD modal) and SettingsView (language + data folder). Wire SettingsView into the MainWindow Settings tab.

Purpose: These are the last two user-visible pieces before the visual checkpoint. After this plan the application is functional enough for a human to create a tenant profile, connect, and switch language. Output: ProfileManagementDialog + SettingsView wired into the shell.

<execution_context> @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/phases/01-foundation/01-CONTEXT.md @.planning/phases/01-foundation/01-06-SUMMARY.md ```csharp public class ProfileManagementViewModel : ObservableObject { public ObservableCollection Profiles { get; } public TenantProfile? SelectedProfile { get; set; } public string NewName { get; set; } public string NewTenantUrl { get; set; } public string NewClientId { get; set; } public IAsyncRelayCommand AddCommand { get; } public IAsyncRelayCommand RenameCommand { get; } public IAsyncRelayCommand DeleteCommand { get; } } ```
public class SettingsViewModel : FeatureViewModelBase
{
    public string SelectedLanguage { get; set; } // "en" or "fr"
    public string DataFolder { get; set; }
    public RelayCommand BrowseFolderCommand { get; }
}

// ProfileManagementDialog: modal Window, fields: Name + Tenant URL + Client ID // Profile fields: { name, tenantUrl, clientId } — JSON schema // SettingsView: language ComboBox (English/French) + DataFolder TextBox + Browse button // Language switch: immediate, no restart, via TranslationSource.Instance.CurrentCulture

Task 1: ProfileManagementDialog XAML and code-behind SharepointToolbox/Views/Dialogs/ProfileManagementDialog.xaml, SharepointToolbox/Views/Dialogs/ProfileManagementDialog.xaml.cs Create `Views/Dialogs/` directory.
**ProfileManagementDialog.xaml** — modal Window (not UserControl):
```xml
<Window x:Class="SharepointToolbox.Views.Dialogs.ProfileManagementDialog"
        Title="Manage Profiles" Width="500" Height="480"
        WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
        ResizeMode="NoResize">
  <Grid Margin="12">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" /> <!-- Existing profiles list -->
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" /> <!-- Add/Edit fields -->
      <RowDefinition Height="Auto" /> <!-- Action buttons -->
    </Grid.RowDefinitions>

    <!-- Profile list -->
    <Label Content="Profiles" Grid.Row="0" />
    <ListBox Grid.Row="1" Margin="0,0,0,8"
             ItemsSource="{Binding Profiles}"
             SelectedItem="{Binding SelectedProfile}"
             DisplayMemberPath="Name" />

    <!-- Input fields -->
    <Grid Grid.Row="2" Margin="0,0,0,8">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>
      <Label Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[profile.name]}"
             Grid.Row="0" Grid.Column="0" />
      <TextBox Text="{Binding NewName, UpdateSourceTrigger=PropertyChanged}"
               Grid.Row="0" Grid.Column="1" Margin="0,2" />
      <Label Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[profile.url]}"
             Grid.Row="1" Grid.Column="0" />
      <TextBox Text="{Binding NewTenantUrl, UpdateSourceTrigger=PropertyChanged}"
               Grid.Row="1" Grid.Column="1" Margin="0,2" />
      <Label Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[profile.clientid]}"
             Grid.Row="2" Grid.Column="0" />
      <TextBox Text="{Binding NewClientId, UpdateSourceTrigger=PropertyChanged}"
               Grid.Row="2" Grid.Column="1" Margin="0,2" />
    </Grid>

    <!-- Buttons -->
    <StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right">
      <Button Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[profile.add]}"
              Command="{Binding AddCommand}" Width="60" Margin="4,0" />
      <Button Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[profile.rename]}"
              Command="{Binding RenameCommand}" Width="60" Margin="4,0" />
      <Button Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[profile.delete]}"
              Command="{Binding DeleteCommand}" Width="60" Margin="4,0" />
      <Button Content="Close" Width="60" Margin="4,0"
              Click="CloseButton_Click" IsCancel="True" />
    </StackPanel>
  </Grid>
</Window>
```

**ProfileManagementDialog.xaml.cs**:
- Constructor receives `ProfileManagementViewModel` via DI (register as `Transient` in App.xaml.cs — already done in plan 01-06)
- Sets `DataContext = viewModel`
- `CloseButton_Click`: calls `this.Close()`
- `Owner` set by caller (`MainWindowViewModel.ManageProfilesCommand` opens as `new ProfileManagementDialog { Owner = Application.Current.MainWindow }.ShowDialog()`)

After adding: the Add command in `ProfileManagementViewModel` must also trigger `MainWindowViewModel.TenantProfiles` refresh. Implement by having `ProfileManagementViewModel` accept a callback or raise an event. The simplest approach: `MainWindowViewModel.ManageProfilesCommand` reloads profiles after the dialog closes (dialog is modal — `ShowDialog()` blocks until closed).
cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj 2>&1 | tail -5 Build succeeds. ProfileManagementDialog.xaml contains all three input fields (Name, Tenant URL, Client ID). All labels use TranslationSource bindings. Task 2: SettingsView XAML and MainWindow Settings tab wiring SharepointToolbox/Views/Tabs/SettingsView.xaml, SharepointToolbox/Views/Tabs/SettingsView.xaml.cs, SharepointToolbox/Views/MainWindow.xaml Create `Views/Tabs/` directory.
**SettingsView.xaml** — UserControl (embedded in TabItem):
```xml
<UserControl x:Class="SharepointToolbox.Views.Tabs.SettingsView">
  <StackPanel Margin="16">
    <!-- Language -->
    <Label Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[settings.language]}" />
    <ComboBox Width="200" HorizontalAlignment="Left"
              SelectedValue="{Binding SelectedLanguage}"
              SelectedValuePath="Tag">
      <ComboBoxItem Tag="en"
                    Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[settings.lang.en]}" />
      <ComboBoxItem Tag="fr"
                    Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[settings.lang.fr]}" />
    </ComboBox>

    <Separator Margin="0,12" />

    <!-- Data folder -->
    <Label Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[settings.folder]}" />
    <DockPanel>
      <Button DockPanel.Dock="Right"
              Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[settings.browse]}"
              Command="{Binding BrowseFolderCommand}" Width="80" Margin="8,0,0,0" />
      <TextBox Text="{Binding DataFolder, UpdateSourceTrigger=PropertyChanged}" />
    </DockPanel>
  </StackPanel>
</UserControl>
```

**SettingsView.xaml.cs**: Constructor receives `SettingsViewModel` via DI. Sets `DataContext = viewModel`. Calls `viewModel.LoadAsync()` in `Loaded` event to populate current settings.

Add `LoadAsync()` to SettingsViewModel if not present — loads current settings from SettingsService and sets `SelectedLanguage` and `DataFolder` properties.

**MainWindow.xaml** — Update Settings TabItem to use SettingsView (replace placeholder TextBlock):
```xml
<TabItem Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[tab.settings]}">
  <views:SettingsView />
</TabItem>
```
Add namespace: `xmlns:views="clr-namespace:SharepointToolbox.Views.Tabs"`

Also register `SettingsView` in DI in App.xaml.cs (if not already):
```csharp
services.AddTransient<SettingsView>();
```
And resolve it in MainWindow constructor to inject into the Settings TabItem Content, OR use a DataTemplate approach. The simpler approach for Phase 1: resolve `SettingsView` from DI in `MainWindow.xaml.cs` constructor and set it as the TabItem Content directly:
```csharp
SettingsTabItem.Content = serviceProvider.GetRequiredService<SettingsView>();
```
The Settings TabItem already has `x:Name="SettingsTabItem"` from plan 01-06.

Run `dotnet build` and fix any errors.
cd "C:\Users\dev\Documents\projets\Sharepoint" && dotnet build SharepointToolbox/SharepointToolbox.csproj 2>&1 | tail -5 Build succeeds. SettingsView.xaml contains language ComboBox with "en"/"fr" options and data folder TextBox with Browse button. MainWindow.xaml Settings tab shows SettingsView (not placeholder TextBlock). - `dotnet build SharepointToolbox.sln` passes with 0 errors - `dotnet test --filter "Category=Unit"` still passes (no regressions) - ProfileManagementDialog has all three input fields using TranslationSource keys - SettingsView language ComboBox has Tag="en" and Tag="fr" items - MainWindow Settings TabItem Content is SettingsView (not placeholder)

<success_criteria> All Phase 1 UI is built. Application runs and shows: shell with 8 tabs, log panel, status bar, language switching, profile management dialog, and settings. Ready for the visual checkpoint in plan 01-08. </success_criteria>

After completion, create `.planning/phases/01-foundation/01-07-SUMMARY.md`