|
@@ -7,16 +7,107 @@ using InABox.Wpf;
|
|
|
using InABox.WPF;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.Diagnostics.CodeAnalysis;
|
|
|
using System.Drawing;
|
|
|
using System.Globalization;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
using System.Windows;
|
|
|
+using System.Windows.Controls;
|
|
|
using System.Windows.Media.Imaging;
|
|
|
|
|
|
namespace PRSDesktop;
|
|
|
|
|
|
+public class PullResultGrid<T> : DynamicItemsListGrid<T>
|
|
|
+ where T : BaseObject, IPostable, new()
|
|
|
+{
|
|
|
+ private static BitmapImage tick = InABox.Wpf.Resources.tick.AsBitmapImage();
|
|
|
+
|
|
|
+ private class ResultItem(PullResultItem<T> item, bool selected)
|
|
|
+ {
|
|
|
+ public PullResultItem<T> Item { get; set; } = item;
|
|
|
+
|
|
|
+ public bool Selected { get; set; } = selected;
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool CanSave => _items.Any(x => x.Selected);
|
|
|
+
|
|
|
+ private List<ResultItem> _items;
|
|
|
+
|
|
|
+ public IEnumerable<PullResultItem<T>> Selected => _items.Where(x => x.Selected).Select(x => x.Item);
|
|
|
+
|
|
|
+ protected DynamicGridCustomColumnsComponent<T> ColumnsComponent;
|
|
|
+
|
|
|
+ public PullResultGrid(IPullResult<T> result)
|
|
|
+ {
|
|
|
+ _items = result.PulledEntities.Where(x => x.Item.PostedStatus != PostedStatus.PostFailed).Select(x => new ResultItem(x, false)).ToList();
|
|
|
+ Items = _items.Select(x => x.Item.Item).ToList();
|
|
|
+
|
|
|
+ ColumnsComponent = new DynamicGridCustomColumnsComponent<T>(this, typeof(T).Name);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override DynamicGridColumns LoadColumns()
|
|
|
+ {
|
|
|
+ return ColumnsComponent.LoadColumns();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void SaveColumns(DynamicGridColumns columns)
|
|
|
+ {
|
|
|
+ ColumnsComponent.SaveColumns(columns);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void LoadColumnsMenu(ContextMenu menu)
|
|
|
+ {
|
|
|
+ ColumnsComponent.LoadColumnsMenu(menu);
|
|
|
+ }
|
|
|
+
|
|
|
+ private ResultItem? GetItem(CoreRow? row)
|
|
|
+ {
|
|
|
+ return row is not null ? _items[_recordmap[row].Index] : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void Init()
|
|
|
+ {
|
|
|
+ base.Init();
|
|
|
+
|
|
|
+ ActionColumns.Add(new DynamicImageColumn(Selected_Image, Selected_Click) { Position = DynamicActionColumnPosition.Start });
|
|
|
+ ActionColumns.Add(new DynamicTextColumn(row => GetItem(row)?.Item.Type.ToString() ?? "Action")
|
|
|
+ {
|
|
|
+ Position = DynamicActionColumnPosition.Start
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private BitmapImage? Selected_Image(CoreRow? row)
|
|
|
+ {
|
|
|
+ var item = GetItem(row);
|
|
|
+ return (item is null || item.Selected)
|
|
|
+ ? tick
|
|
|
+ : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool Selected_Click(CoreRow? row)
|
|
|
+ {
|
|
|
+ var item = GetItem(row);
|
|
|
+ if(item is not null)
|
|
|
+ {
|
|
|
+ item.Selected = !item.Selected;
|
|
|
+ DoChanged();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void DoReconfigure(DynamicGridOptions options)
|
|
|
+ {
|
|
|
+ base.DoReconfigure(options);
|
|
|
+
|
|
|
+ options.Clear();
|
|
|
+ options.SelectColumns = true;
|
|
|
+ options.FilterRows = true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
public static class PostUtils
|
|
|
{
|
|
|
private static readonly Inflector.Inflector inflector = new(new CultureInfo("en"));
|
|
@@ -144,12 +235,191 @@ public static class PostUtils
|
|
|
} while (retry);
|
|
|
}
|
|
|
|
|
|
+ public static bool ShowPullResultGrid<T>(IPullResult<T> result, [NotNullWhen(true)] out List<PullResultItem<T>>? items)
|
|
|
+ where T : Entity, IPostable, IRemotable, IPersistent, new()
|
|
|
+ {
|
|
|
+ var resultGrid = new PullResultGrid<T>(result);
|
|
|
+ var window = new DynamicContentDialog(resultGrid)
|
|
|
+ {
|
|
|
+ Title = "Select items to import:",
|
|
|
+ CanSave = false
|
|
|
+ };
|
|
|
+ resultGrid.OnChanged += (o, e) => window.CanSave = resultGrid.CanSave;
|
|
|
+ resultGrid.Refresh(true, true);
|
|
|
+ if(window.ShowDialog() == true)
|
|
|
+ {
|
|
|
+ items = resultGrid.Selected.ToList();
|
|
|
+ Client.Save(items.Select(x => x.Item), "Posted by user.");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ items = null;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void PullEntities<T>(Action refresh, Action? configurePost = null)
|
|
|
+ where T : Entity, IPostable, IRemotable, IPersistent, new()
|
|
|
+ {
|
|
|
+ bool retry;
|
|
|
+ do
|
|
|
+ {
|
|
|
+ retry = false;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var result = PosterUtils.Pull<T>();
|
|
|
+ if (result is null)
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage($"Import failed", "Import failed");
|
|
|
+ refresh();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ List<PullResultItem<T>>? items;
|
|
|
+ if (!result.PulledEntities.Any(x => x.Item.PostedStatus != PostedStatus.PostFailed))
|
|
|
+ {
|
|
|
+ items = result.PulledEntities.ToList();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ShowPullResultGrid(result, out items);
|
|
|
+ }
|
|
|
+ if (items is null)
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage("Import cancelled.", "Cancelled");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var failedMessages = new List<string>();
|
|
|
+ var successCount = 0;
|
|
|
+ var importCount = 0;
|
|
|
+ var updateCount = 0;
|
|
|
+ foreach (var item in items)
|
|
|
+ {
|
|
|
+ if (item.Item.PostedStatus == PostedStatus.PostFailed)
|
|
|
+ {
|
|
|
+ failedMessages.Add(item.Item.PostedNote);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ successCount++;
|
|
|
+ switch (item.Type)
|
|
|
+ {
|
|
|
+ case PullResultType.New:
|
|
|
+ importCount++;
|
|
|
+ break;
|
|
|
+ case PullResultType.Updated:
|
|
|
+ case PullResultType.Linked:
|
|
|
+ default:
|
|
|
+ updateCount++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (failedMessages.Count > 0 && successCount == 0)
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage($"Import failed:\n - {string.Join("\n - ", failedMessages)}", "Import failed.");
|
|
|
+ }
|
|
|
+ else if (failedMessages.Count == 0)
|
|
|
+ {
|
|
|
+ if (successCount == 0)
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage($"Nothing imported.", "Import successful.");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage($"Import successful; {importCount} items imported.", "Import successful.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage($"{successCount} items succeeded, but {failedMessages.Count} failed:\n - {string.Join("\n - ", failedMessages)}", "Partial success");
|
|
|
+ }
|
|
|
+ refresh();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (PullFailedMessageException e)
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage(e.Message, "Import failed");
|
|
|
+ }
|
|
|
+ catch (PullCancelledException)
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage("Import cancelled.", "Cancelled");
|
|
|
+ }
|
|
|
+ catch (MissingSettingException e)
|
|
|
+ {
|
|
|
+ if (configurePost is not null && Security.CanConfigurePost<T>())
|
|
|
+ {
|
|
|
+ if (MessageWindow.ShowYesNo($"'{e.Setting}' has not been set-up for {inflector.Pluralize(typeof(T).Name)}. Would you like to configure this now?",
|
|
|
+ "Configure Import?"))
|
|
|
+ {
|
|
|
+ bool success = false;
|
|
|
+ if (e.SettingsType.IsAssignableTo(typeof(IGlobalPosterSettings)))
|
|
|
+ {
|
|
|
+ success = PostableSettingsGrid.ConfigureGlobalPosterSettings(e.SettingsType);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ success = PostableSettingsGrid.ConfigurePosterSettings<T>(e.SettingsType);
|
|
|
+ }
|
|
|
+ if (success && MessageWindow.ShowYesNo("Settings updated; Would you like to retry the import?", "Retry?"))
|
|
|
+ {
|
|
|
+ retry = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage("Import cancelled.", "Cancelled");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage("Import cancelled.", "Cancelled");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage($"'{e.Setting}' has not been set-up for {inflector.Pluralize(typeof(T).Name)}", "Unconfigured");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (MissingSettingsException)
|
|
|
+ {
|
|
|
+ if (configurePost is not null && Security.CanConfigurePost<T>())
|
|
|
+ {
|
|
|
+ if (MessageWindow.ShowYesNo($"Importing has not been configured for {inflector.Pluralize(typeof(T).Name)}. Would you like to configure this now?",
|
|
|
+ "Configure Import?"))
|
|
|
+ {
|
|
|
+ configurePost();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage("Import cancelled.", "Cancelled");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage($"Importing has not been configured for {inflector.Pluralize(typeof(T).Name)}!", "Unconfigured");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ MessageWindow.ShowError("Import failed.", e);
|
|
|
+ refresh();
|
|
|
+ }
|
|
|
+ } while (retry);
|
|
|
+ }
|
|
|
+
|
|
|
public static void CreateToolbarButtons<T>(IPanelHost host, Func<IDataModel<T>> model, Action refresh, Action? configurePost = null)
|
|
|
where T : Entity, IPostable, IRemotable, IPersistent, new()
|
|
|
{
|
|
|
+ if (!Security.CanPost<T>()) return;
|
|
|
+
|
|
|
var postSettings = PosterUtils.LoadPostableSettings<T>();
|
|
|
- if (Security.CanPost<T>() && !postSettings.PosterType.IsNullOrWhiteSpace())
|
|
|
+ if (!postSettings.PosterType.IsNullOrWhiteSpace())
|
|
|
{
|
|
|
+ var posterEngine = PosterUtils.GetEngine(typeof(T));
|
|
|
+
|
|
|
Bitmap? image = null;
|
|
|
if (postSettings.Thumbnail.ID != Guid.Empty)
|
|
|
{
|
|
@@ -170,6 +440,13 @@ public static class PostUtils
|
|
|
configurePost);
|
|
|
}
|
|
|
});
|
|
|
+ if(posterEngine.Get(out var posterEngineType, out var _) && posterEngineType.HasInterface(typeof(IPullerEngine<>)))
|
|
|
+ {
|
|
|
+ host.CreatePanelAction(new PanelAction($"Import {inflector.Pluralize(typeof(T).Name)}", image ?? PRSDesktop.Resources.doc_xls, action =>
|
|
|
+ {
|
|
|
+ PullEntities<T>(refresh);
|
|
|
+ }));
|
|
|
+ }
|
|
|
|
|
|
if (postSettings.ShowClearButton)
|
|
|
{
|
|
@@ -202,7 +479,7 @@ public static class PostUtils
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (configurePost is not null && Security.CanConfigurePost<T>())
|
|
|
+ if (configurePost is not null)
|
|
|
{
|
|
|
host.CreateSetupAction(new PanelAction
|
|
|
{
|