- Add 80+ Phase 4 EN/FR localization keys to Strings.resx and Strings.fr.resx (tabs, transfer, bulkmembers, bulksites, folderstruct, templates, bulk-shared, folderbrowser) - Add ResourceManager property accessors for all new keys to Strings.Designer.cs - Create ConfirmBulkOperationDialog (XAML + code-behind) with Proceed/Cancel buttons - Create FolderBrowserDialog (XAML + code-behind) with lazy-loading TreeView of SharePoint libraries/folders - Bundle bulk_add_members.csv, bulk_create_sites.csv, folder_structure.csv as EmbeddedResource in csproj
126 lines
4.3 KiB
C#
126 lines
4.3 KiB
C#
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using Microsoft.SharePoint.Client;
|
|
using SharepointToolbox.Core.Helpers;
|
|
|
|
namespace SharepointToolbox.Views.Dialogs;
|
|
|
|
public partial class FolderBrowserDialog : Window
|
|
{
|
|
private readonly ClientContext _ctx;
|
|
public string SelectedLibrary { get; private set; } = string.Empty;
|
|
public string SelectedFolderPath { get; private set; } = string.Empty;
|
|
|
|
public FolderBrowserDialog(ClientContext ctx)
|
|
{
|
|
InitializeComponent();
|
|
_ctx = ctx;
|
|
Loaded += OnLoaded;
|
|
}
|
|
|
|
private async void OnLoaded(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
// Load libraries
|
|
var web = _ctx.Web;
|
|
var lists = _ctx.LoadQuery(web.Lists
|
|
.Include(l => l.Title, l => l.Hidden, l => l.BaseType, l => l.RootFolder)
|
|
.Where(l => !l.Hidden && l.BaseType == BaseType.DocumentLibrary));
|
|
var progress = new Progress<Core.Models.OperationProgress>();
|
|
await ExecuteQueryRetryHelper.ExecuteQueryRetryAsync(_ctx, progress, CancellationToken.None);
|
|
|
|
foreach (var list in lists)
|
|
{
|
|
var libNode = new TreeViewItem
|
|
{
|
|
Header = list.Title,
|
|
Tag = new FolderNodeInfo(list.Title, string.Empty),
|
|
};
|
|
// Add dummy child for expand arrow
|
|
libNode.Items.Add(new TreeViewItem { Header = "Loading..." });
|
|
libNode.Expanded += LibNode_Expanded;
|
|
FolderTree.Items.Add(libNode);
|
|
}
|
|
|
|
StatusText.Text = $"{FolderTree.Items.Count} libraries loaded.";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusText.Text = $"Error: {ex.Message}";
|
|
}
|
|
}
|
|
|
|
private async void LibNode_Expanded(object sender, RoutedEventArgs e)
|
|
{
|
|
if (sender is not TreeViewItem node || node.Tag is not FolderNodeInfo info)
|
|
return;
|
|
|
|
// Only load children once
|
|
if (node.Items.Count == 1 && node.Items[0] is TreeViewItem dummy && dummy.Header?.ToString() == "Loading...")
|
|
{
|
|
node.Items.Clear();
|
|
try
|
|
{
|
|
var folderUrl = string.IsNullOrEmpty(info.FolderPath)
|
|
? GetLibraryRootUrl(info.LibraryTitle)
|
|
: info.FolderPath;
|
|
|
|
var folder = _ctx.Web.GetFolderByServerRelativeUrl(folderUrl);
|
|
_ctx.Load(folder, f => f.Folders.Include(sf => sf.Name, sf => sf.ServerRelativeUrl));
|
|
var progress = new Progress<Core.Models.OperationProgress>();
|
|
await ExecuteQueryRetryHelper.ExecuteQueryRetryAsync(_ctx, progress, CancellationToken.None);
|
|
|
|
foreach (var subFolder in folder.Folders)
|
|
{
|
|
if (subFolder.Name.StartsWith("_") || subFolder.Name == "Forms")
|
|
continue;
|
|
|
|
var childNode = new TreeViewItem
|
|
{
|
|
Header = subFolder.Name,
|
|
Tag = new FolderNodeInfo(info.LibraryTitle, subFolder.ServerRelativeUrl),
|
|
};
|
|
childNode.Items.Add(new TreeViewItem { Header = "Loading..." });
|
|
childNode.Expanded += LibNode_Expanded;
|
|
node.Items.Add(childNode);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
node.Items.Add(new TreeViewItem { Header = $"Error: {ex.Message}" });
|
|
}
|
|
}
|
|
}
|
|
|
|
private string GetLibraryRootUrl(string libraryTitle)
|
|
{
|
|
var uri = new Uri(_ctx.Url);
|
|
return $"{uri.AbsolutePath.TrimEnd('/')}/{libraryTitle}";
|
|
}
|
|
|
|
private void FolderTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
|
{
|
|
if (e.NewValue is TreeViewItem node && node.Tag is FolderNodeInfo info)
|
|
{
|
|
SelectedLibrary = info.LibraryTitle;
|
|
SelectedFolderPath = info.FolderPath;
|
|
SelectButton.IsEnabled = true;
|
|
}
|
|
}
|
|
|
|
private void Select_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
DialogResult = true;
|
|
Close();
|
|
}
|
|
|
|
private void Cancel_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
DialogResult = false;
|
|
Close();
|
|
}
|
|
|
|
private record FolderNodeInfo(string LibraryTitle, string FolderPath);
|
|
}
|