Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5c0afc3
Production 'mode' where we merge all the files together.
KevinJump Oct 13, 2025
7f11789
ajust the interface, so we can have nice defaults for new properties.
KevinJump Oct 14, 2025
f63a311
clean up the merge function
KevinJump Oct 14, 2025
17d865b
make sure individual empty files process the 'current' way (we don't …
KevinJump Oct 14, 2025
74f6470
cache the loading of xml files in the clean loop, to stop multiple fi…
KevinJump Oct 14, 2025
31eb694
clean up the import/report methods to make them more readable.
KevinJump Oct 14, 2025
5270df1
add incremental update messages so we can smooth out progress even wh…
KevinJump Oct 14, 2025
a57c990
fix typo on exportOnSave settings localization string.
KevinJump Oct 14, 2025
870fb83
XML Comments.
KevinJump Oct 14, 2025
09ed275
more xml comments
KevinJump Oct 14, 2025
65167b9
Update uSync.BackOffice/Hubs/uSyncCallbacks.cs
KevinJump Oct 15, 2025
a51e2c5
Update uSync.BackOffice/Configuration/uSyncSettings.cs
KevinJump Oct 15, 2025
f815e98
Update uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs
KevinJump Oct 15, 2025
3a6d585
Update uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs
KevinJump Oct 15, 2025
060d73d
Update uSync.BackOffice/Configuration/uSyncSettings.cs
KevinJump Oct 15, 2025
115e49a
Update uSync.BackOffice/Services/SyncService_Files.cs
KevinJump Oct 15, 2025
3a3763f
Update uSync.BackOffice/Services/SyncFileService.cs
KevinJump Oct 15, 2025
1bb1d9f
Update uSync.BackOffice/Hubs/uSyncCallbacks.cs
KevinJump Oct 15, 2025
3f7a6ba
make sure we process all single actions (Co-piolt fix)
KevinJump Oct 15, 2025
c13d744
Update uSync.BackOffice/SyncHandlers/Interfaces/ISyncHandler.cs
KevinJump Oct 15, 2025
5392700
fix serializer interface typo.
KevinJump Oct 15, 2025
1479fe9
remove bool clean from merge public api
KevinJump Oct 15, 2025
ad7f0a7
add using alias for core constants.
KevinJump Oct 15, 2025
07e65bf
Replace File.Exists with call to SyncFileService.FileExists
KevinJump Oct 15, 2025
4c76f4e
Update uSync.BackOffice/Configuration/SyncConfigService.cs
KevinJump Oct 15, 2025
cc9df71
typo fixes in the generated schema file.
KevinJump Oct 15, 2025
f75b4d8
Update uSync.BackOffice/Hubs/HubClientService.cs
KevinJump Oct 15, 2025
42743b7
Update uSync.BackOffice/Services/ISyncFileService.cs
KevinJump Oct 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion uSync.BackOffice.Targets/appsettings-schema.usync.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@
},
"DisableNotificationSuppression": {
"type": "boolean",
"description": "turns of use of the Notifications.Supress method, so notifications\nfire after every item is imported.\n ",
"description": "turns of use of the Notifications.Suppress method, so notifications\nfire after every item is imported.\n ",
Comment thread
KevinJump marked this conversation as resolved.
Outdated
"default": "true"
},
"BackgroundNotifications": {
Expand All @@ -217,9 +217,37 @@
"type": "boolean",
"description": "Move the uSync tree to it's own section in the back office. \n(requires a restart to take effect).\n ",
"default": false
},
"FolderMode": {
"description": "What type of mode the folder should work in (default, root, or production)\n ",
"default": "Normal",
"oneOf": [
{
"$ref": "#/definitions/USyncBackOfficeConfigurationSyncFolderMode"
}
]
},
"ProductionFolder": {
"type": "string",
"description": "location of the 'production' folder to use when in production mode, \nor when creating the production mode files.\n ",
"default": "uSync/production"
}
}
},
"USyncBackOfficeConfigurationSyncFolderMode": {
"type": "string",
"description": "uSync's folder mode - normal, root or production\n ",
"x-enumNames": [
"Normal",
"Root",
"Production"
],
"enum": [
"Normal",
"Root",
"Production"
]
},
"USyncuSyncSetsDefinition": {
"type": "object",
"properties": {
Expand Down
19 changes: 11 additions & 8 deletions uSync.BackOffice/Configuration/SyncConfigService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,24 @@ private class SyncFolderItem
/// <inheritdoc/>
public string GetWorkingFolder()
{
var folders = FetchFolders();

return Settings.IsRootSite
? folders[0].TrimStart('/')
: folders.Last().TrimStart('/');
var folders = GetFolders();
return folders.Last().TrimStart('/');
}

/// <inheritdoc/>
public string[] GetFolders()
{
var folders = FetchFolders();

return Settings.IsRootSite
? [folders[0].TrimStart('/')]
: [.. folders.Select(x => x.TrimStart('/'))];
switch(Settings.FolderMode)
{
case SyncFolderMode.Root:
return [folders[0].TrimStart('/')];
case SyncFolderMode.Production:
return [Settings.ProductionFolder];
Comment thread
KevinJump marked this conversation as resolved.
Outdated
default:
return [.. folders.Select(x => x.TrimStart('/'))];
}
}

/// <inheritdoc/>
Expand Down
59 changes: 45 additions & 14 deletions uSync.BackOffice/Configuration/uSyncSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,26 +197,22 @@ public class uSyncSettings
public string HideAddOns { get; set; } = "licence";

/// <summary>
/// turns of use of the Notifications.Supress method, so notifications
/// turns of use of the Notifications.Suppress method, so notifications
Comment thread
KevinJump marked this conversation as resolved.
Outdated
/// fire after every item is imported.
/// </summary>
/// <remarks>
/// I am not sure this does what i think it does, it doesn't suppress
/// then fire at the end , it just suppresses them all.
/// this disables the internal uSync scope provider that delays all
/// non cancellable notifications until after the import is complete.
///
/// until we have had time to look at this , we will leave this as
/// disabled by default so all notification messages fire.
/// on v13 this is false, the import happens and then the notifications fire.
///
/// for v13 thius is fine, but for v14, grouping the notifications
/// can causes issues if something fails.
///
/// So if a single content import fails then the whole batch doesn't
/// get published properly (so no content for you :( ) .
/// on v16 the default is true, because some of the notifications appear to
/// be closely coupled to the save/publish process, and if something goes
/// wrong in one item's import it can cause a cascade of failures across
/// everything that might have been imported along with it.
///
/// there might be something downlever we can do, but it likey means
/// lots of core investigation to find that, for now 'old' school
/// non suppressed notifications should be fine (if a little slower).
///
/// if the notifications are not suppressed, then if an item fails to import
/// it doesn't stop other items from being imported.
/// </remarks>
[DefaultValue("true")]
public bool DisableNotificationSuppression { get; set; } = true;
Expand All @@ -238,4 +234,39 @@ public class uSyncSettings
/// </summary>
[DefaultValue(false)]
public bool MoveToSection { get; set; } = false;

/// <summary>
/// What type of mode the folder should work in (default, root, or production)
/// </summary>
[DefaultValue("Normal")]
Comment thread
KevinJump marked this conversation as resolved.
Outdated
public SyncFolderMode FolderMode { get; set; } = SyncFolderMode.Normal;

/// <summary>
/// location of the 'production' folder to use when in production mode,
/// or when creating the production mode files.
/// </summary>
[DefaultValue("uSync/production")]
public string ProductionFolder { get; set; } = "uSync/production";
}

/// <summary>
/// uSync's folder mode - normal, root or production
/// </summary>
public enum SyncFolderMode
{
/// <summary>
/// normal - expects individual files in the uSync folder(s)
/// </summary>
Normal,

/// <summary>
/// root - will read and write things to the root folder,
/// </summary>
Root,

/// <summary>
/// production - looks in a 'production' folder, expects a single file per handler.
/// </summary>
Production,
};

24 changes: 23 additions & 1 deletion uSync.BackOffice/Hubs/HubClientService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,27 @@ public void PostUpdate(string message, int count, int total)
/// get the uSync callbacks for this connection
/// </summary>
/// <returns></returns>
public uSyncCallbacks Callbacks() => new(this.PostSummary, this.PostUpdate);
public uSyncCallbacks Callbacks() => new(this.PostSummary, this.PostUpdate, this.SetCountRange, this.PostIncrementalUpdate);

private int _start = 0;
private int _end = 0;

/// <summary>
/// set a range (start to end) that we except the next set of updates to be bound within.
Comment thread
KevinJump marked this conversation as resolved.
Outdated
/// </summary>
public void SetCountRange(int start, int end)
{
_start = start;
_end = end;
}

/// <summary>
/// post an update and increment the counter by one.
/// </summary>
public void PostIncrementalUpdate(string message)
{
_start++;
if (_start > _end) _end = _start;
this.PostUpdate(message, _start, _end);
}
}
47 changes: 46 additions & 1 deletion uSync.BackOffice/Hubs/uSyncCallbacks.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
using uSync.BackOffice.SyncHandlers.Interfaces;
using Org.BouncyCastle.Bcpg.OpenPgp;

Comment thread
KevinJump marked this conversation as resolved.
Outdated
using uSync.BackOffice.Models;
using uSync.BackOffice.SyncHandlers.Interfaces;

namespace uSync.BackOffice;

/// <summary>
/// Callback event for SignalR hub
/// </summary>
public delegate void SyncEventCallback(SyncProgressSummary summary);

/// <summary>
/// callback delegate for SignalR messaging
/// </summary>
public delegate void SyncUpdateCallback(string message, int count, int total);

/// <summary>
/// callback delegate to set the start and end rage for the update counters.
Comment thread
KevinJump marked this conversation as resolved.
Outdated
/// </summary>
public delegate void SyncSetUpdateRange(int start, int end);

/// <summary>
/// callback to send a update message and increment the counter by one so moving the progress bar.
/// </summary>
/// <param name="message"></param>
public delegate void SyncIncrementalUpdateCallback(string message);


/// <summary>
/// Callback objects used to communicate via SignalR
/// </summary>
Expand All @@ -17,6 +42,16 @@ public class uSyncCallbacks
/// </summary>
public SyncUpdateCallback? Update { get; private set; }

/// <summary>
/// set a start and end range for the counter.
/// </summary>
public SyncSetUpdateRange? SetRange { get; private set; }

/// <summary>
/// update and increment callback.
/// </summary>
public SyncIncrementalUpdateCallback? IncrementalUpdate { get; private set; }

/// <summary>
/// generate a new callback object
/// </summary>
Expand All @@ -25,4 +60,14 @@ public uSyncCallbacks(SyncEventCallback? callback, SyncUpdateCallback? update)
this.Callback = callback;
this.Update = update;
}

/// <summary>
/// generate a callback object with range and incremental update
/// </summary>
public uSyncCallbacks(SyncEventCallback? callback, SyncUpdateCallback? update, SyncSetUpdateRange? updateRange, SyncIncrementalUpdateCallback incrementalUpdate)
: this(callback, update)
{
this.SetRange = updateRange;
this.IncrementalUpdate = incrementalUpdate;
}
}
5 changes: 5 additions & 0 deletions uSync.BackOffice/Services/ISyncFileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ public interface ISyncFileService
/// <returns></returns>
Task<XElement> LoadXElementAsync(string file);

/// <summary>
/// merge all the files in the give folders into a single xml node, that can be bulk imported
Comment thread
KevinJump marked this conversation as resolved.
Outdated
/// </summary>
Task<int> MakeSingleExportFromFolders(string[] folders, string itemType, ISyncTrackerBase? trackerBase, string fileName, string extension);

/// <summary>
/// merge a list of files into a single XElement
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions uSync.BackOffice/Services/ISyncService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,10 @@ public interface ISyncService
/// trigger the end of the bulk process
/// </summary>
Task FinishBulkProcessAsync(HandlerActions action, IEnumerable<uSyncAction> actions);

/// <summary>
/// merge the given folders in single 'production' files for each handler.
/// </summary>
Task<int> MergeExportFolder(string[] paths, IEnumerable<HandlerConfigPair> handlers, bool clean);

}
22 changes: 20 additions & 2 deletions uSync.BackOffice/Services/SyncFileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ public async Task SaveFileAsync(string filename, string content)
{
CheckCharacters = false,
Async = true,
IgnoreWhitespace = true,
};

private static XmlWriterSettings _writerSettings = new XmlWriterSettings
Expand All @@ -251,8 +252,6 @@ public async Task SaveFileAsync(string filename, string content)
Async = true,
CloseOutput= false,
Indent = true,


};

/// <inheritdoc/>
Expand Down Expand Up @@ -323,7 +322,26 @@ public void CopyFolder(string source, string target)
{
File.Copy(file, file.Replace(resolvedSource, resolvedTarget), true);
}
}

public async Task<int> MakeSingleExportFromFolders(string[] folders, string itemType, ISyncTrackerBase? trackerBase, string filename, string extension)
{
var merged = await MergeFoldersAsync(folders, extension, trackerBase);

var megaNode = new XElement(itemType + "s");
int count = 0;
foreach(var item in merged)
{
count++;
megaNode.Add(new XElement(item.Node));
}

var resolvedTargetFile = GetAbsPath(filename);
CreateFoldersForFile(resolvedTargetFile);

await SaveXElementAsync(megaNode, filename);
Comment thread
KevinJump marked this conversation as resolved.
Outdated

return count;
}

/// <inheritdoc/>
Expand Down
6 changes: 0 additions & 6 deletions uSync.BackOffice/Services/SyncService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@

namespace uSync.BackOffice;


/// <summary>
/// Callback event for SignalR hub
/// </summary>
public delegate void SyncEventCallback(SyncProgressSummary summary);

/// <summary>
/// the service that does all the processing,
/// this forms the entry point as an API to
Expand Down
34 changes: 33 additions & 1 deletion uSync.BackOffice/Services/SyncService_Files.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
using System;
using Microsoft.Extensions.Logging;

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;

using uSync.BackOffice.SyncHandlers.Models;

namespace uSync.BackOffice;

Expand Down Expand Up @@ -104,4 +110,30 @@ private static string CleanPathForZip(string path)
=> Path.GetFullPath(
path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar))
.TrimEnd(Path.DirectorySeparatorChar);

/// <inheritdoc />
public async Task<int> MergeExportFolder(string[] paths, IEnumerable<HandlerConfigPair> handlers, bool clean)
Comment thread
KevinJump marked this conversation as resolved.
Outdated
{
var totalMerged = 0;
var root = _uSyncConfig.GetWorkingFolder();
Comment thread
KevinJump marked this conversation as resolved.
Outdated

foreach (var handler in handlers)
{
var serializerType = handler.Handler.GetSerializeType();
var baseTracker = handler.Handler.GetBaseTracker();
if (serializerType is null || baseTracker is null)
{
_logger.LogWarning("Handler {Handler} does not support file merging", handler.Handler.Alias);
continue;
}
Comment thread
KevinJump marked this conversation as resolved.
Outdated

var folders = paths.Select(x => Path.Combine(x, handler.Handler.DefaultFolder)).ToArray();
var targetFileName = Path.Combine(_uSyncConfig.Settings.ProductionFolder,
handler.Handler.DefaultFolder + "." + _uSyncConfig.Settings.DefaultExtension);

totalMerged += await _syncFileService.MakeSingleExportFromFolders(folders, serializerType, baseTracker, targetFileName, _uSyncConfig.Settings.DefaultExtension);
}

return totalMerged;
}
}
Loading