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:
@@ -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;
|
||||||
@@ -61,23 +62,33 @@ public class FeatureViewModelBaseTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task CancelCommand_DuringOperation_SetsStatusMessageToCancelled()
|
public async Task CancelCommand_DuringOperation_SetsStatusMessageToCancelled()
|
||||||
{
|
{
|
||||||
var vm = new TestViewModel();
|
// Ensure EN culture so TranslationSource resolves "Operation cancelled"
|
||||||
var started = new TaskCompletionSource<bool>();
|
var prev = CultureInfo.CurrentUICulture;
|
||||||
|
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("en");
|
||||||
vm.OperationFunc = async (ct, p) =>
|
try
|
||||||
{
|
{
|
||||||
started.SetResult(true);
|
var vm = new TestViewModel();
|
||||||
await Task.Delay(5000, ct); // Will be cancelled
|
var started = new TaskCompletionSource<bool>();
|
||||||
};
|
|
||||||
|
|
||||||
var runTask = vm.RunCommand.ExecuteAsync(null);
|
vm.OperationFunc = async (ct, p) =>
|
||||||
await started.Task;
|
{
|
||||||
|
started.SetResult(true);
|
||||||
|
await Task.Delay(5000, ct); // Will be cancelled
|
||||||
|
};
|
||||||
|
|
||||||
vm.CancelCommand.Execute(null);
|
var runTask = vm.RunCommand.ExecuteAsync(null);
|
||||||
await runTask;
|
await started.Task;
|
||||||
|
|
||||||
Assert.Contains("cancel", vm.StatusMessage, StringComparison.OrdinalIgnoreCase);
|
vm.CancelCommand.Execute(null);
|
||||||
Assert.False(vm.IsRunning);
|
await runTask;
|
||||||
|
|
||||||
|
Assert.Contains("cancel", vm.StatusMessage, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.False(vm.IsRunning);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
CultureInfo.CurrentUICulture = prev;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -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]}">
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace SharepointToolbox.Views.Controls;
|
|
||||||
|
|
||||||
public partial class FeatureTabBase : UserControl
|
|
||||||
{
|
|
||||||
public FeatureTabBase()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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]}"
|
||||||
|
|||||||
@@ -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]}"
|
||||||
|
|||||||
@@ -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="*" />
|
||||||
|
|||||||
Reference in New Issue
Block a user