fix: resolve post-milestone tech debt items

- Add DataGrid RowStyle with red highlighting for invalid CSV rows
  in BulkMembersView, BulkSitesView, and FolderStructureView
- Fix cancel test locale mismatch by setting EN culture before assertion
- Remove dead FeatureTabBase placeholder (replaced by full tab views)
- Clean up unused xmlns:controls from MainWindow.xaml

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dev
2026-04-07 09:15:02 +02:00
parent c81d8959f7
commit b815c323d7
7 changed files with 56 additions and 59 deletions

View File

@@ -1,3 +1,4 @@
using System.Globalization;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using SharepointToolbox.Core.Models; using SharepointToolbox.Core.Models;
using SharepointToolbox.ViewModels; using SharepointToolbox.ViewModels;
@@ -60,6 +61,11 @@ public class FeatureViewModelBaseTests
[Fact] [Fact]
public async Task CancelCommand_DuringOperation_SetsStatusMessageToCancelled() public async Task CancelCommand_DuringOperation_SetsStatusMessageToCancelled()
{
// Ensure EN culture so TranslationSource resolves "Operation cancelled"
var prev = CultureInfo.CurrentUICulture;
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("en");
try
{ {
var vm = new TestViewModel(); var vm = new TestViewModel();
var started = new TaskCompletionSource<bool>(); var started = new TaskCompletionSource<bool>();
@@ -79,6 +85,11 @@ public class FeatureViewModelBaseTests
Assert.Contains("cancel", vm.StatusMessage, StringComparison.OrdinalIgnoreCase); Assert.Contains("cancel", vm.StatusMessage, StringComparison.OrdinalIgnoreCase);
Assert.False(vm.IsRunning); Assert.False(vm.IsRunning);
} }
finally
{
CultureInfo.CurrentUICulture = prev;
}
}
[Fact] [Fact]
public async Task OperationCanceledException_IsCaughtGracefully_IsRunningBecomesFalse() public async Task OperationCanceledException_IsCaughtGracefully_IsRunningBecomesFalse()

View File

@@ -4,7 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:loc="clr-namespace:SharepointToolbox.Localization" xmlns:loc="clr-namespace:SharepointToolbox.Localization"
xmlns:controls="clr-namespace:SharepointToolbox.Views.Controls"
xmlns:views="clr-namespace:SharepointToolbox.Views.Tabs" xmlns:views="clr-namespace:SharepointToolbox.Views.Tabs"
mc:Ignorable="d" mc:Ignorable="d"
Title="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[app.title]}" Title="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[app.title]}"
@@ -39,7 +39,7 @@
Background="Black" Foreground="LimeGreen" Background="Black" Foreground="LimeGreen"
FontFamily="Consolas" FontSize="11" /> FontFamily="Consolas" FontSize="11" />
<!-- TabControl: 7 stub tabs use FeatureTabBase; Settings tab wired in plan 01-07 --> <!-- TabControl -->
<TabControl> <TabControl>
<TabItem x:Name="PermissionsTabItem" <TabItem x:Name="PermissionsTabItem"
Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[tab.permissions]}"> Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[tab.permissions]}">

View File

@@ -1,33 +0,0 @@
<UserControl x:Class="SharepointToolbox.Views.Controls.FeatureTabBase"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc="clr-namespace:SharepointToolbox.Localization">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Placeholder content — Phase 2+ replaces Row 0 -->
<TextBlock Grid.Row="0"
Text="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[tab.comingsoon]}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
<!-- Per-tab progress/cancel strip (shown only when IsRunning) -->
<Grid Grid.Row="1" Margin="8,4"
Visibility="{Binding IsRunning, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ProgressBar Grid.Column="0" Height="16" Minimum="0" Maximum="100"
Value="{Binding ProgressValue}" />
<TextBlock Grid.Column="1" Margin="8,0" VerticalAlignment="Center"
Text="{Binding StatusMessage}" />
<Button Grid.Column="2"
Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[btn.cancel]}"
Command="{Binding CancelCommand}" Width="70" />
</Grid>
</Grid>
</UserControl>

View File

@@ -1,11 +0,0 @@
using System.Windows.Controls;
namespace SharepointToolbox.Views.Controls;
public partial class FeatureTabBase : UserControl
{
public FeatureTabBase()
{
InitializeComponent();
}
}

View File

@@ -33,6 +33,16 @@
<!-- Preview DataGrid (Right) --> <!-- Preview DataGrid (Right) -->
<DataGrid ItemsSource="{Binding PreviewRows}" AutoGenerateColumns="False" <DataGrid ItemsSource="{Binding PreviewRows}" AutoGenerateColumns="False"
IsReadOnly="True" CanUserSortColumns="True"> IsReadOnly="True" CanUserSortColumns="True">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding IsValid}" Value="False">
<Setter Property="Background" Value="#FFFDE0E0" />
<Setter Property="Foreground" Value="#FFB00020" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="Valid" Binding="{Binding IsValid}" Width="50" /> <DataGridTextColumn Header="Valid" Binding="{Binding IsValid}" Width="50" />
<DataGridTextColumn Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[bulkmembers.groupname]}" <DataGridTextColumn Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[bulkmembers.groupname]}"

View File

@@ -31,6 +31,16 @@
<DataGrid ItemsSource="{Binding PreviewRows}" AutoGenerateColumns="False" <DataGrid ItemsSource="{Binding PreviewRows}" AutoGenerateColumns="False"
IsReadOnly="True" CanUserSortColumns="True"> IsReadOnly="True" CanUserSortColumns="True">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding IsValid}" Value="False">
<Setter Property="Background" Value="#FFFDE0E0" />
<Setter Property="Foreground" Value="#FFB00020" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="Valid" Binding="{Binding IsValid}" Width="50" /> <DataGridTextColumn Header="Valid" Binding="{Binding IsValid}" Width="50" />
<DataGridTextColumn Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[bulksites.name]}" <DataGridTextColumn Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[bulksites.name]}"

View File

@@ -38,6 +38,16 @@
<DataGrid ItemsSource="{Binding PreviewRows}" AutoGenerateColumns="False" <DataGrid ItemsSource="{Binding PreviewRows}" AutoGenerateColumns="False"
IsReadOnly="True" CanUserSortColumns="True"> IsReadOnly="True" CanUserSortColumns="True">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding IsValid}" Value="False">
<Setter Property="Background" Value="#FFFDE0E0" />
<Setter Property="Foreground" Value="#FFB00020" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="Valid" Binding="{Binding IsValid}" Width="50" /> <DataGridTextColumn Header="Valid" Binding="{Binding IsValid}" Width="50" />
<DataGridTextColumn Header="Level 1" Binding="{Binding Record.Level1}" Width="*" /> <DataGridTextColumn Header="Level 1" Binding="{Binding Record.Level1}" Width="*" />