This commit is contained in:
Dev
2026-04-24 10:50:19 +02:00
14 changed files with 523 additions and 0 deletions
@@ -16,8 +16,12 @@
<!-- Action bar: new folder (destination mode only) -->
<StackPanel x:Name="ActionBar" DockPanel.Dock="Top" Orientation="Horizontal"
Margin="0,0,0,6" Visibility="Collapsed">
<<<<<<< HEAD
<Button x:Name="NewFolderButton"
Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[common.new_folder]}"
=======
<Button x:Name="NewFolderButton" Content="+ New Folder"
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
Padding="8,3" Click="NewFolder_Click" IsEnabled="False" />
</StackPanel>
@@ -22,7 +22,10 @@ public partial class FolderBrowserDialog : Window
public IReadOnlyList<string> SelectedFilePaths { get; private set; } = Array.Empty<string>();
private readonly List<CheckBox> _fileCheckboxes = new();
<<<<<<< HEAD
private readonly List<TreeViewItem> _expandedNodes = new();
=======
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
/// <summary>
/// Dialog for browsing library folders. Set <paramref name="allowFileSelection"/>
@@ -81,7 +84,10 @@ public partial class FolderBrowserDialog : Window
// Placeholder child so the expand arrow appears.
node.Items.Add(new TreeViewItem { Header = "Loading..." });
node.Expanded += FolderNode_Expanded;
<<<<<<< HEAD
_expandedNodes.Add(node);
=======
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
return node;
}
@@ -101,9 +107,18 @@ public partial class FolderBrowserDialog : Window
{
var folder = _ctx.Web.GetFolderByServerRelativeUrl(info.ServerRelativeUrl);
_ctx.Load(folder, f => f.StorageMetrics.TotalSize,
<<<<<<< HEAD
f => f.StorageMetrics.TotalFileCount);
var list = _ctx.Web.Lists.GetByTitle(info.LibraryTitle);
_ctx.Load(list, l => l.Title);
=======
f => f.StorageMetrics.TotalFileCount,
f => f.Folders.Include(sf => sf.Name, sf => sf.ServerRelativeUrl,
sf => sf.StorageMetrics.TotalSize,
sf => sf.StorageMetrics.TotalFileCount),
f => f.Files.Include(fi => fi.Name, fi => fi.Length,
fi => fi.ServerRelativeUrl));
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
var progress = new Progress<Core.Models.OperationProgress>();
await ExecuteQueryRetryHelper.ExecuteQueryRetryAsync(_ctx, progress, CancellationToken.None);
@@ -114,6 +129,7 @@ public partial class FolderBrowserDialog : Window
folder.StorageMetrics.TotalFileCount,
folder.StorageMetrics.TotalSize);
<<<<<<< HEAD
// Enumerate direct children via paginated CAML — Folder.Folders /
// Folder.Files lazy loading hits the list-view threshold on libraries
// above 5,000 items even when only a small folder is being expanded.
@@ -191,6 +207,53 @@ public partial class FolderBrowserDialog : Window
node.Items.Add(fileItem);
}
}
=======
// Child folders first
foreach (var subFolder in folder.Folders)
{
if (subFolder.Name.StartsWith("_") || subFolder.Name == "Forms")
continue;
var childRelative = string.IsNullOrEmpty(info.RelativePath)
? subFolder.Name
: $"{info.RelativePath}/{subFolder.Name}";
var childInfo = new FolderNodeInfo(
info.LibraryTitle, childRelative, subFolder.ServerRelativeUrl);
var childNode = MakeFolderNode(
FormatFolderHeader(subFolder.Name,
subFolder.StorageMetrics.TotalFileCount,
subFolder.StorageMetrics.TotalSize),
childInfo);
node.Items.Add(childNode);
}
// Files under this folder — only shown when selection is enabled.
if (_allowFileSelection)
{
foreach (var file in folder.Files)
{
// Library-relative path for the file (used by the transfer service)
var fileRel = string.IsNullOrEmpty(info.RelativePath)
? file.Name
: $"{info.RelativePath}/{file.Name}";
var cb = new CheckBox
{
Content = $"{file.Name} ({FormatSize(file.Length)})",
Tag = new FileNodeInfo(info.LibraryTitle, fileRel),
Margin = new Thickness(4, 2, 0, 2),
};
cb.Checked += FileCheckbox_Toggled;
cb.Unchecked += FileCheckbox_Toggled;
_fileCheckboxes.Add(cb);
var fileItem = new TreeViewItem { Header = cb, Focusable = false };
node.Items.Add(fileItem);
}
}
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
}
catch (Exception ex)
{
@@ -305,6 +368,7 @@ public partial class FolderBrowserDialog : Window
Close();
}
<<<<<<< HEAD
protected override void OnClosed(EventArgs e)
{
Loaded -= OnLoaded;
@@ -320,6 +384,8 @@ public partial class FolderBrowserDialog : Window
base.OnClosed(e);
}
=======
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
private record FolderNodeInfo(string LibraryTitle, string RelativePath, string ServerRelativeUrl);
private record FileNodeInfo(string LibraryTitle, string RelativePath);
}
@@ -1,8 +1,12 @@
<Window x:Class="SharepointToolbox.Views.Dialogs.InputDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<<<<<<< HEAD
xmlns:loc="clr-namespace:SharepointToolbox.Localization"
Title="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[input.title]}"
=======
Title="Input"
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
Width="340" Height="140"
WindowStartupLocation="CenterOwner"
Background="{DynamicResource AppBgBrush}"
@@ -12,8 +16,12 @@
<DockPanel Margin="12">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal"
HorizontalAlignment="Right" Margin="0,10,0,0">
<<<<<<< HEAD
<Button Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[btn.cancel]}"
Width="70" IsCancel="True" Margin="0,0,8,0"
=======
<Button Content="Cancel" Width="70" IsCancel="True" Margin="0,0,8,0"
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
Click="Cancel_Click" />
<Button Content="OK" Width="70" IsDefault="True"
Click="Ok_Click" />
@@ -60,8 +60,12 @@
<!-- Site list with checkboxes -->
<ListView x:Name="SiteList" Grid.Row="2" Margin="0,0,0,8"
SelectionMode="Single"
<<<<<<< HEAD
BorderThickness="1" BorderBrush="{DynamicResource BorderSoftBrush}"
GridViewColumnHeader.Click="SiteList_ColumnHeaderClick">
=======
BorderThickness="1" BorderBrush="{DynamicResource BorderSoftBrush}">
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
<ListView.View>
<GridView>
<GridViewColumn Width="32">
@@ -104,7 +108,11 @@
</ListView>
<!-- Status text -->
<<<<<<< HEAD
<TextBlock x:Name="StatusText" Grid.Row="3" Margin="0,0,0,8"
=======
<TextBlock x:Name="StatusText" Grid.Row="2" Margin="0,0,0,8"
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
Foreground="{DynamicResource TextMutedBrush}" FontSize="11" />
<!-- Button row -->
@@ -44,6 +44,7 @@
<Button Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[btn.cancel]}"
Command="{Binding CancelCommand}" Height="28" Margin="0,0,0,8" />
<<<<<<< HEAD
<Label Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[export.split.label]}" Margin="0,4,0,0" />
<ComboBox SelectedIndex="{Binding SplitModeIndex}" Height="26" Margin="0,0,0,4">
<ComboBoxItem Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[export.split.single]}" />
@@ -55,6 +56,8 @@
<ComboBoxItem Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[export.html.layout.tabbed]}" />
</ComboBox>
=======
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
<Button Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[audit.btn.exportCsv]}"
Command="{Binding ExportCsvCommand}" Height="28" Margin="0,0,0,4" />
<Button Content="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[audit.btn.exportHtml]}"
@@ -83,12 +86,18 @@
<DataGridTextColumn Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[report.col.size]}"
Binding="{Binding SizeBytes, Converter={StaticResource BytesConverter}}"
Width="90" ElementStyle="{StaticResource RightAlignStyle}" />
<<<<<<< HEAD
<DataGridTextColumn Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[report.col.created]}"
Binding="{Binding Created, StringFormat=yyyy-MM-dd}" Width="100" />
<DataGridTextColumn Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[report.col.modified]}"
Binding="{Binding Modified, StringFormat=yyyy-MM-dd}" Width="100" />
<DataGridTextColumn Header="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[report.col.path]}"
Binding="{Binding Path}" Width="400" />
=======
<DataGridTextColumn Header="Created" Binding="{Binding Created, StringFormat=yyyy-MM-dd}" Width="100" />
<DataGridTextColumn Header="Modified" Binding="{Binding Modified, StringFormat=yyyy-MM-dd}" Width="100" />
<DataGridTextColumn Header="Path" Binding="{Binding Path}" Width="400" />
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
</DataGrid.Columns>
</DataGrid>
</DockPanel>
@@ -18,6 +18,7 @@
Click="BrowseSource_Click" Margin="0,0,0,5" />
<TextBlock Text="{Binding SourceLibrary}" FontWeight="SemiBold" />
<TextBlock Text="{Binding SourceFolderPath}" Foreground="{DynamicResource TextMutedBrush}" />
<<<<<<< HEAD
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="{DynamicResource AccentBrush}" FontStyle="Italic" FontSize="11"
Text="{Binding SelectedFileCount, Mode=OneWay}" />
@@ -32,6 +33,20 @@
IsChecked="{Binding CopyFolderContents}"
Margin="0,4,0,0"
ToolTip="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[transfer.chk.copy_contents.tooltip]}" />
=======
<TextBlock Foreground="{DynamicResource AccentBrush}" FontStyle="Italic" FontSize="11">
<Run Text="{Binding SelectedFileCount, Mode=OneWay}" />
<Run Text=" file(s) selected" />
</TextBlock>
<CheckBox Content="Include source folder at destination"
IsChecked="{Binding IncludeSourceFolder}"
Margin="0,6,0,0"
ToolTip="When on, recreate the source folder under the destination. When off, drop contents directly into the destination folder." />
<CheckBox Content="Copy folder contents"
IsChecked="{Binding CopyFolderContents}"
Margin="0,4,0,0"
ToolTip="When on (default), transfer files inside the folder. When off, only the folder is created at the destination." />
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
</StackPanel>
</GroupBox>
@@ -44,7 +44,11 @@
</GroupBox.Style>
<StackPanel>
<TextBox Text="{Binding SearchQuery, UpdateSourceTrigger=PropertyChanged}" Margin="0,0,0,2" />
<<<<<<< HEAD
<TextBlock Text="{Binding Source={x:Static loc:TranslationSource.Instance}, Path=[audit.searching]}" FontStyle="Italic" FontSize="10" Foreground="{DynamicResource TextMutedBrush}" Margin="0,0,0,2">
=======
<TextBlock Text="Searching..." FontStyle="Italic" FontSize="10" Foreground="{DynamicResource TextMutedBrush}" Margin="0,0,0,2">
>>>>>>> f4cc81bb71b935c6f6f050288c9e283dcca5cfa8
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed" />