feat(08-03): add simplified mode UI to PermissionsView
- Add Display Options GroupBox with Simplified Mode toggle and Simple/Detailed radio buttons - Add summary panel with color-coded risk level cards bound to Summaries collection - DataGrid binds to ActiveItemsSource, rows color-coded by RiskLevel via DataTriggers - SimplifiedLabels column visible only in simplified mode via BooleanToVisibilityConverter - DataGrid collapses in Simple mode via MultiDataTrigger on IsSimplifiedMode+IsDetailView - Create InvertBoolConverter for radio button inverse binding Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
18
SharepointToolbox/Core/Converters/InvertBoolConverter.cs
Normal file
18
SharepointToolbox/Core/Converters/InvertBoolConverter.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace SharepointToolbox.Core.Converters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inverts a boolean value. Used for radio button binding where
|
||||||
|
/// one option is the inverse of the bound property.
|
||||||
|
/// </summary>
|
||||||
|
[ValueConversion(typeof(bool), typeof(bool))]
|
||||||
|
public class InvertBoolConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
=> value is bool b ? !b : value;
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
=> value is bool b ? !b : value;
|
||||||
|
}
|
||||||
@@ -1,7 +1,15 @@
|
|||||||
<UserControl x:Class="SharepointToolbox.Views.Tabs.PermissionsView"
|
<UserControl x:Class="SharepointToolbox.Views.Tabs.PermissionsView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:loc="clr-namespace:SharepointToolbox.Localization">
|
xmlns:loc="clr-namespace:SharepointToolbox.Localization"
|
||||||
|
xmlns:models="clr-namespace:SharepointToolbox.Core.Models"
|
||||||
|
xmlns:converters="clr-namespace:SharepointToolbox.Core.Converters">
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<BooleanToVisibilityConverter x:Key="BoolToVis" />
|
||||||
|
<converters:InvertBoolConverter x:Key="InvertBoolConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="290" />
|
<ColumnDefinition Width="290" />
|
||||||
@@ -55,6 +63,41 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
|
<!-- Display Options GroupBox (Phase 8: Simplified Permissions) -->
|
||||||
|
<GroupBox Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[grp.display.opts]}"
|
||||||
|
DockPanel.Dock="Top" Margin="0,0,0,8" Padding="8">
|
||||||
|
<StackPanel>
|
||||||
|
|
||||||
|
<!-- Simplified Mode toggle -->
|
||||||
|
<CheckBox Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[chk.simplified.mode]}"
|
||||||
|
IsChecked="{Binding IsSimplifiedMode}" Margin="0,0,0,8" />
|
||||||
|
|
||||||
|
<!-- Detail Level radio buttons (only enabled when simplified mode is on) -->
|
||||||
|
<TextBlock Text="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[lbl.detail.level]}"
|
||||||
|
Margin="0,0,0,4"
|
||||||
|
IsEnabled="{Binding IsSimplifiedMode}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="TextBlock">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsSimplifiedMode}" Value="False">
|
||||||
|
<Setter Property="Foreground" Value="Gray" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
<RadioButton Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[rad.detail.simple]}"
|
||||||
|
IsChecked="{Binding IsDetailView, Converter={StaticResource InvertBoolConverter}, Mode=TwoWay}"
|
||||||
|
IsEnabled="{Binding IsSimplifiedMode}"
|
||||||
|
Margin="0,0,0,2" />
|
||||||
|
<RadioButton Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[rad.detail.detailed]}"
|
||||||
|
IsChecked="{Binding IsDetailView}"
|
||||||
|
IsEnabled="{Binding IsSimplifiedMode}"
|
||||||
|
Margin="0,0,0,0" />
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
<!-- Action buttons -->
|
<!-- Action buttons -->
|
||||||
<StackPanel DockPanel.Dock="Top" Margin="0,0,0,4">
|
<StackPanel DockPanel.Dock="Top" Margin="0,0,0,4">
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -89,25 +132,138 @@
|
|||||||
|
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<!-- Right panel: Results DataGrid -->
|
<!-- Right panel: Summary + Results -->
|
||||||
<DataGrid Grid.Column="1" Grid.Row="0"
|
<Grid Grid.Column="1" Grid.Row="0" Margin="0,8,8,8">
|
||||||
ItemsSource="{Binding Results}"
|
<Grid.RowDefinitions>
|
||||||
AutoGenerateColumns="False"
|
<RowDefinition Height="Auto" />
|
||||||
IsReadOnly="True"
|
<RowDefinition Height="*" />
|
||||||
VirtualizingPanel.IsVirtualizing="True"
|
</Grid.RowDefinitions>
|
||||||
EnableRowVirtualization="True"
|
|
||||||
Margin="0,8,8,8">
|
<!-- Summary panel (visible only in simplified mode) -->
|
||||||
<DataGrid.Columns>
|
<ItemsControl Grid.Row="0" ItemsSource="{Binding Summaries}"
|
||||||
<DataGridTextColumn Header="Object Type" Binding="{Binding ObjectType}" Width="100" />
|
Margin="0,0,0,8">
|
||||||
<DataGridTextColumn Header="Title" Binding="{Binding Title}" Width="140" />
|
<ItemsControl.Style>
|
||||||
<DataGridTextColumn Header="URL" Binding="{Binding Url}" Width="200" />
|
<Style TargetType="ItemsControl">
|
||||||
<DataGridTextColumn Header="Unique Perms" Binding="{Binding HasUniquePermissions}" Width="90" />
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
<DataGridTextColumn Header="Users" Binding="{Binding Users}" Width="140" />
|
<Style.Triggers>
|
||||||
<DataGridTextColumn Header="Permission Levels" Binding="{Binding PermissionLevels}" Width="140" />
|
<DataTrigger Binding="{Binding IsSimplifiedMode}" Value="True">
|
||||||
<DataGridTextColumn Header="Granted Through" Binding="{Binding GrantedThrough}" Width="140" />
|
<Setter Property="Visibility" Value="Visible" />
|
||||||
<DataGridTextColumn Header="Principal Type" Binding="{Binding PrincipalType}" Width="110" />
|
</DataTrigger>
|
||||||
</DataGrid.Columns>
|
</Style.Triggers>
|
||||||
</DataGrid>
|
</Style>
|
||||||
|
</ItemsControl.Style>
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<WrapPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border CornerRadius="6" Padding="14,10" Margin="0,0,10,4" MinWidth="140">
|
||||||
|
<Border.Style>
|
||||||
|
<Style TargetType="Border">
|
||||||
|
<Setter Property="Background" Value="#F3F4F6" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding RiskLevel}" Value="{x:Static models:RiskLevel.High}">
|
||||||
|
<Setter Property="Background" Value="#FEE2E2" />
|
||||||
|
<Setter Property="BorderBrush" Value="#FECACA" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding RiskLevel}" Value="{x:Static models:RiskLevel.Medium}">
|
||||||
|
<Setter Property="Background" Value="#FEF3C7" />
|
||||||
|
<Setter Property="BorderBrush" Value="#FDE68A" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding RiskLevel}" Value="{x:Static models:RiskLevel.Low}">
|
||||||
|
<Setter Property="Background" Value="#D1FAE5" />
|
||||||
|
<Setter Property="BorderBrush" Value="#A7F3D0" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding RiskLevel}" Value="{x:Static models:RiskLevel.ReadOnly}">
|
||||||
|
<Setter Property="Background" Value="#DBEAFE" />
|
||||||
|
<Setter Property="BorderBrush" Value="#BFDBFE" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Border.Style>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{Binding Count}" FontSize="22" FontWeight="Bold" />
|
||||||
|
<TextBlock Text="{Binding Label}" FontSize="11" Foreground="#555" />
|
||||||
|
<TextBlock FontSize="10" Foreground="#888" Margin="0,2,0,0">
|
||||||
|
<Run Text="{Binding DistinctUsers, Mode=OneWay}" />
|
||||||
|
<Run Text=" user(s)" />
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
|
||||||
|
<!-- Results DataGrid -->
|
||||||
|
<DataGrid Grid.Row="1"
|
||||||
|
ItemsSource="{Binding ActiveItemsSource}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
VirtualizingPanel.IsVirtualizing="True"
|
||||||
|
EnableRowVirtualization="True">
|
||||||
|
<DataGrid.Style>
|
||||||
|
<Style TargetType="DataGrid">
|
||||||
|
<Style.Triggers>
|
||||||
|
<!-- Hide DataGrid when simplified mode is on but detail view is off -->
|
||||||
|
<MultiDataTrigger>
|
||||||
|
<MultiDataTrigger.Conditions>
|
||||||
|
<Condition Binding="{Binding IsSimplifiedMode}" Value="True" />
|
||||||
|
<Condition Binding="{Binding IsDetailView}" Value="False" />
|
||||||
|
</MultiDataTrigger.Conditions>
|
||||||
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
</MultiDataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.Style>
|
||||||
|
|
||||||
|
<!-- Row style: color-code by RiskLevel when in simplified mode -->
|
||||||
|
<DataGrid.RowStyle>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding RiskLevel}" Value="{x:Static models:RiskLevel.High}">
|
||||||
|
<Setter Property="Background" Value="#FEF2F2" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding RiskLevel}" Value="{x:Static models:RiskLevel.Medium}">
|
||||||
|
<Setter Property="Background" Value="#FFFBEB" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding RiskLevel}" Value="{x:Static models:RiskLevel.Low}">
|
||||||
|
<Setter Property="Background" Value="#ECFDF5" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding RiskLevel}" Value="{x:Static models:RiskLevel.ReadOnly}">
|
||||||
|
<Setter Property="Background" Value="#EFF6FF" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowStyle>
|
||||||
|
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Object Type" Binding="{Binding ObjectType}" Width="100" />
|
||||||
|
<DataGridTextColumn Header="Title" Binding="{Binding Title}" Width="140" />
|
||||||
|
<DataGridTextColumn Header="URL" Binding="{Binding Url}" Width="200" />
|
||||||
|
<DataGridTextColumn Header="Unique Perms" Binding="{Binding HasUniquePermissions}" Width="90" />
|
||||||
|
<DataGridTextColumn Header="Users" Binding="{Binding Users}" Width="140" />
|
||||||
|
<DataGridTextColumn Header="Permission Levels" Binding="{Binding PermissionLevels}" Width="140" />
|
||||||
|
|
||||||
|
<!-- Simplified Labels column (only visible in simplified mode) -->
|
||||||
|
<DataGridTextColumn Header="Simplified" Binding="{Binding SimplifiedLabels}" Width="200">
|
||||||
|
<DataGridTextColumn.Visibility>
|
||||||
|
<Binding Path="DataContext.IsSimplifiedMode"
|
||||||
|
RelativeSource="{RelativeSource AncestorType=DataGrid}"
|
||||||
|
Converter="{StaticResource BoolToVis}" />
|
||||||
|
</DataGridTextColumn.Visibility>
|
||||||
|
</DataGridTextColumn>
|
||||||
|
|
||||||
|
<DataGridTextColumn Header="Granted Through" Binding="{Binding GrantedThrough}" Width="140" />
|
||||||
|
<DataGridTextColumn Header="Principal Type" Binding="{Binding PrincipalType}" Width="110" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<!-- Bottom: status bar spanning both columns -->
|
<!-- Bottom: status bar spanning both columns -->
|
||||||
<StatusBar Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1">
|
<StatusBar Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1">
|
||||||
|
|||||||
Reference in New Issue
Block a user