feat(14-02): add directory browse mode UI with mode toggle, DataGrid, and loading UX
- Mode toggle (Search/Browse) RadioButtons at top of left panel - Search panel uses DataTrigger inverse visibility (collapses when IsBrowseMode=true) - Browse panel with Load/Cancel buttons, IncludeGuests checkbox, filter TextBox, status/count - Directory DataGrid with 5 columns (Name, Email, Department, Job Title, Type) - Guest users highlighted in orange via DataTrigger on UserType - SelectedUsers extracted to shared section visible in both modes - DataGrid wired to DirectoryDataGrid_MouseDoubleClick handler - Scan Options and Run/Export buttons remain always visible Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,8 +15,30 @@
|
|||||||
<!-- Left panel -->
|
<!-- Left panel -->
|
||||||
<DockPanel Grid.Column="0" Grid.Row="0" Margin="8">
|
<DockPanel Grid.Column="0" Grid.Row="0" Margin="8">
|
||||||
|
|
||||||
<GroupBox Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[audit.grp.users]}"
|
<!-- Mode toggle -->
|
||||||
DockPanel.Dock="Top" Margin="0,0,0,8" Padding="8">
|
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,0,0,8">
|
||||||
|
<RadioButton Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[audit.mode.search]}"
|
||||||
|
IsChecked="{Binding IsBrowseMode, Converter={StaticResource InverseBoolConverter}}"
|
||||||
|
Margin="0,0,12,0" />
|
||||||
|
<RadioButton Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[audit.mode.browse]}"
|
||||||
|
IsChecked="{Binding IsBrowseMode}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- SEARCH MODE PANEL (visible when IsBrowseMode=false) -->
|
||||||
|
<GroupBox DockPanel.Dock="Top" Margin="0,0,0,8" Padding="8">
|
||||||
|
<GroupBox.Header>
|
||||||
|
<TextBlock Text="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[audit.grp.users]}" />
|
||||||
|
</GroupBox.Header>
|
||||||
|
<GroupBox.Style>
|
||||||
|
<Style TargetType="GroupBox">
|
||||||
|
<Setter Property="Visibility" Value="Visible" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsBrowseMode}" Value="True">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</GroupBox.Style>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBox Text="{Binding SearchQuery, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,0,2" />
|
<TextBox Text="{Binding SearchQuery, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,0,2" />
|
||||||
<TextBlock Text="Searching..." FontStyle="Italic" FontSize="10" Foreground="Gray" Margin="0,0,0,2">
|
<TextBlock Text="Searching..." FontStyle="Italic" FontSize="10" Foreground="Gray" Margin="0,0,0,2">
|
||||||
@@ -57,26 +79,124 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
<ItemsControl ItemsSource="{Binding SelectedUsers}" Margin="0,0,0,4">
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<Border Background="#EBF5FB" BorderBrush="#2980B9" BorderThickness="1"
|
|
||||||
CornerRadius="4" Padding="6,2" Margin="0,1">
|
|
||||||
<DockPanel>
|
|
||||||
<Button Content="x" DockPanel.Dock="Right" Padding="4,0"
|
|
||||||
Background="Transparent" BorderThickness="0"
|
|
||||||
Command="{Binding DataContext.RemoveUserCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
|
|
||||||
CommandParameter="{Binding}" />
|
|
||||||
<TextBlock Text="{Binding DisplayName}" VerticalAlignment="Center" />
|
|
||||||
</DockPanel>
|
|
||||||
</Border>
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
<TextBlock Text="{Binding SelectedUsersLabel}" FontStyle="Italic" Foreground="Gray" FontSize="10" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
|
<!-- BROWSE MODE PANEL (visible when IsBrowseMode=true) -->
|
||||||
|
<GroupBox DockPanel.Dock="Top" Margin="0,0,0,8" Padding="8"
|
||||||
|
Visibility="{Binding IsBrowseMode, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||||
|
<GroupBox.Header>
|
||||||
|
<TextBlock Text="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[directory.grp.browse]}" />
|
||||||
|
</GroupBox.Header>
|
||||||
|
<DockPanel>
|
||||||
|
<!-- Load/Cancel buttons -->
|
||||||
|
<Grid DockPanel.Dock="Top" Margin="0,0,0,4">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button Grid.Column="0"
|
||||||
|
Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[directory.btn.load]}"
|
||||||
|
Command="{Binding LoadDirectoryCommand}" Margin="0,0,4,0" Padding="6,3" />
|
||||||
|
<Button Grid.Column="1"
|
||||||
|
Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[directory.btn.cancel]}"
|
||||||
|
Command="{Binding CancelDirectoryLoadCommand}" Padding="6,3" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Include guests checkbox -->
|
||||||
|
<CheckBox DockPanel.Dock="Top"
|
||||||
|
Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[directory.chk.guests]}"
|
||||||
|
IsChecked="{Binding IncludeGuests}" Margin="0,0,0,4" />
|
||||||
|
|
||||||
|
<!-- Filter text -->
|
||||||
|
<TextBox DockPanel.Dock="Top"
|
||||||
|
Text="{Binding DirectoryFilterText, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
Margin="0,0,0,4" />
|
||||||
|
|
||||||
|
<!-- Status row: load status + user count -->
|
||||||
|
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,0,0,4">
|
||||||
|
<TextBlock Text="{Binding DirectoryLoadStatus}" FontStyle="Italic" Foreground="Gray" FontSize="10"
|
||||||
|
Margin="0,0,8,0" />
|
||||||
|
<TextBlock FontSize="10" Foreground="Gray">
|
||||||
|
<TextBlock.Text>
|
||||||
|
<MultiBinding StringFormat="{}{0} {1}">
|
||||||
|
<Binding Path="DirectoryUserCount" />
|
||||||
|
<Binding Source="{x:Static loc:TranslationSource.Instance}" Path="[directory.status.count]" />
|
||||||
|
</MultiBinding>
|
||||||
|
</TextBlock.Text>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Hint text -->
|
||||||
|
<TextBlock DockPanel.Dock="Bottom"
|
||||||
|
Text="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[directory.hint.doubleclick]}"
|
||||||
|
FontStyle="Italic" Foreground="Gray" FontSize="10" Margin="0,4,0,0"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<!-- Directory DataGrid -->
|
||||||
|
<DataGrid x:Name="DirectoryDataGrid"
|
||||||
|
ItemsSource="{Binding DirectoryUsersView}"
|
||||||
|
AutoGenerateColumns="False" IsReadOnly="True"
|
||||||
|
VirtualizingPanel.IsVirtualizing="True" EnableRowVirtualization="True"
|
||||||
|
MouseDoubleClick="DirectoryDataGrid_MouseDoubleClick"
|
||||||
|
CanUserSortColumns="True"
|
||||||
|
SelectionMode="Single" SelectionUnit="FullRow"
|
||||||
|
HeadersVisibility="Column" GridLinesVisibility="Horizontal"
|
||||||
|
BorderThickness="1" BorderBrush="#DDDDDD">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Name"
|
||||||
|
Binding="{Binding DisplayName}" Width="120" />
|
||||||
|
<DataGridTextColumn Header="Email"
|
||||||
|
Binding="{Binding UserPrincipalName}" Width="140" />
|
||||||
|
<DataGridTextColumn Header="Department"
|
||||||
|
Binding="{Binding Department}" Width="90" />
|
||||||
|
<DataGridTextColumn Header="Job Title"
|
||||||
|
Binding="{Binding JobTitle}" Width="90" />
|
||||||
|
<DataGridTemplateColumn Header="Type" Width="60">
|
||||||
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding UserType}" VerticalAlignment="Center">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="TextBlock">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding UserType}" Value="Guest">
|
||||||
|
<Setter Property="Foreground" Value="#F39C12" />
|
||||||
|
<Setter Property="FontWeight" Value="SemiBold" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
</DataGridTemplateColumn>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</DockPanel>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<!-- SHARED: Selected users (visible in both modes) -->
|
||||||
|
<StackPanel DockPanel.Dock="Top" Margin="0,0,0,8">
|
||||||
|
<ItemsControl ItemsSource="{Binding SelectedUsers}" Margin="0,0,0,4">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border Background="#EBF5FB" BorderBrush="#2980B9" BorderThickness="1"
|
||||||
|
CornerRadius="4" Padding="6,2" Margin="0,1">
|
||||||
|
<DockPanel>
|
||||||
|
<Button Content="x" DockPanel.Dock="Right" Padding="4,0"
|
||||||
|
Background="Transparent" BorderThickness="0"
|
||||||
|
Command="{Binding DataContext.RemoveUserCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
|
||||||
|
CommandParameter="{Binding}" />
|
||||||
|
<TextBlock Text="{Binding DisplayName}" VerticalAlignment="Center" />
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
<TextBlock Text="{Binding SelectedUsersLabel}" FontStyle="Italic" Foreground="Gray" FontSize="10" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Scan Options (always visible) -->
|
||||||
<GroupBox Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[audit.grp.options]}"
|
<GroupBox Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[audit.grp.options]}"
|
||||||
DockPanel.Dock="Top" Margin="0,0,0,8" Padding="8">
|
DockPanel.Dock="Top" Margin="0,0,0,8" Padding="8">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
@@ -89,6 +209,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
|
<!-- Run/Export buttons (always visible) -->
|
||||||
<StackPanel DockPanel.Dock="Top">
|
<StackPanel DockPanel.Dock="Top">
|
||||||
<Grid Margin="0,0,0,4">
|
<Grid Margin="0,0,0,4">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
|||||||
Reference in New Issue
Block a user