diff --git a/src/DynamoCore/Graph/Workspaces/HomeWorkspaceModel.cs b/src/DynamoCore/Graph/Workspaces/HomeWorkspaceModel.cs
index 6fd3d6ae87e..8858121b6c7 100644
--- a/src/DynamoCore/Graph/Workspaces/HomeWorkspaceModel.cs
+++ b/src/DynamoCore/Graph/Workspaces/HomeWorkspaceModel.cs
@@ -27,6 +27,8 @@ public class HomeWorkspaceModel : WorkspaceModel
{
#region Class Data Members and Properties
+ private string thumbnail;
+ private Uri graphDocumentationURL;
private readonly DynamoScheduler scheduler;
private PulseMaker pulseMaker;
private readonly bool verboseLogging;
@@ -89,6 +91,46 @@ public class HomeWorkspaceModel : WorkspaceModel
[JsonIgnore]
public long EvaluationCount { get; private set; }
+ ///
+ /// Link to documentation page for this workspace
+ ///
+ public Uri GraphDocumentationURL
+ {
+ get { return graphDocumentationURL; }
+ set
+ {
+ if (graphDocumentationURL == value)
+ return;
+
+ graphDocumentationURL = value;
+ RaisePropertyChanged(nameof(GraphDocumentationURL));
+ }
+ }
+
+
+ ///
+ /// Workspace thumbnail as Base64 string.
+ /// Returns null if provide value is not Base64 encoded.
+ ///
+ public string Thumbnail
+ {
+ get { return thumbnail; }
+ set
+ {
+ try
+ {
+ // if value is not a valid Base64 string this will throw, and we return null.
+ byte[] data = Convert.FromBase64String(value);
+ thumbnail = value;
+ RaisePropertyChanged(nameof(Thumbnail));
+ }
+ catch
+ {
+ return;
+ }
+ }
+ }
+
///
/// In near future, the file loading mechanism will be completely moved
/// into WorkspaceModel, that's the time we removed this property setter below.
diff --git a/src/DynamoCore/Graph/Workspaces/SerializationConverters.cs b/src/DynamoCore/Graph/Workspaces/SerializationConverters.cs
index 950a1d444d7..3416cc9e2bf 100644
--- a/src/DynamoCore/Graph/Workspaces/SerializationConverters.cs
+++ b/src/DynamoCore/Graph/Workspaces/SerializationConverters.cs
@@ -641,15 +641,30 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
}
else
{
- ws = new HomeWorkspaceModel(guid, engine, scheduler, factory,
+ var homeWorkspace = new HomeWorkspaceModel(guid, engine, scheduler, factory,
loadedTraceData, nodes, notes, annotations,
Enumerable.Empty(), elementResolver,
info, verboseLogging, isTestMode);
+
+ if (obj.TryGetValue(nameof(HomeWorkspaceModel.Thumbnail), StringComparison.OrdinalIgnoreCase, out JToken thumbnail))
+ homeWorkspace.Thumbnail = thumbnail.ToString();
+
+ if (obj.TryGetValue(nameof(HomeWorkspaceModel.GraphDocumentationURL), StringComparison.OrdinalIgnoreCase, out JToken helpLink))
+ {
+ if (Uri.TryCreate(helpLink.ToString(), UriKind.Absolute, out Uri uri))
+ homeWorkspace.GraphDocumentationURL = uri;
+ }
+
+ ws = homeWorkspace;
}
ws.NodeLibraryDependencies = nodeLibraryDependencies.ToList();
ws.ExtensionData = GetExtensionData(serializer, obj);
+ if (obj.TryGetValue(nameof(WorkspaceModel.Author), StringComparison.OrdinalIgnoreCase, out JToken author))
+ ws.Author = author.ToString();
+
+
return ws;
}
@@ -771,6 +786,22 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
writer.WritePropertyName(WorkspaceReadConverter.EXTENSION_WORKSPACE_DATA);
serializer.Serialize(writer, ws.ExtensionData);
+
+ if (!isCustomNode && ws is HomeWorkspaceModel hws)
+ {
+ // Thumbnail
+ writer.WritePropertyName(nameof(HomeWorkspaceModel.Thumbnail));
+ writer.WriteValue(hws.Thumbnail);
+
+ // GraphDocumentaionLink
+ writer.WritePropertyName(nameof(HomeWorkspaceModel.GraphDocumentationURL));
+ writer.WriteValue(hws.GraphDocumentationURL);
+ }
+
+ // Graph Author
+ writer.WritePropertyName(nameof(WorkspaceModel.Author));
+ writer.WriteValue(ws.Author);
+
if (engine != null)
{
// Bindings
diff --git a/src/DynamoCore/Graph/Workspaces/WorkspaceModel.cs b/src/DynamoCore/Graph/Workspaces/WorkspaceModel.cs
index b68336d6953..040b982c9da 100644
--- a/src/DynamoCore/Graph/Workspaces/WorkspaceModel.cs
+++ b/src/DynamoCore/Graph/Workspaces/WorkspaceModel.cs
@@ -696,7 +696,7 @@ internal List NodeLibraryDependencies
}
private Dictionary nodePackageDictionary = new Dictionary();
-
+
///
/// An author of the workspace
@@ -707,7 +707,7 @@ public string Author
set
{
author = value;
- RaisePropertyChanged("Author");
+ RaisePropertyChanged(nameof(Author));
}
}
diff --git a/test/DynamoCoreTests/Graph/Workspaces/WorkspaceModelTests.cs b/test/DynamoCoreTests/Graph/Workspaces/WorkspaceModelTests.cs
index 4974f2a7e98..a4e998de46f 100644
--- a/test/DynamoCoreTests/Graph/Workspaces/WorkspaceModelTests.cs
+++ b/test/DynamoCoreTests/Graph/Workspaces/WorkspaceModelTests.cs
@@ -284,5 +284,40 @@ public void UpdateModelValueInvalidParameters()
Assert.AreEqual(Resources.ModelNotFoundError, ex3.Message);
}
+
+ [Test]
+ public void CanStoreBase64EncodedImageInThumbnailProperty()
+ {
+ // Arrange
+ var imagePath = Path.Combine(TestDirectory, @"DynamoCoreTests\Graph\Workspaces\thumbnailTestImage.png");
+ Assert.That(File.Exists(imagePath));
+
+ // Act
+ byte[] imageArray = System.IO.File.ReadAllBytes(imagePath);
+ string base64ImageRepresentation = Convert.ToBase64String(imageArray);
+ if (!(this.CurrentDynamoModel.CurrentWorkspace is HomeWorkspaceModel hws))
+ throw new Exception("current workspace is not a HomeWorkspaceModel");
+
+ hws.Thumbnail = base64ImageRepresentation;
+
+ // Assert
+ Assert.NotNull(base64ImageRepresentation);
+ Assert.AreEqual(hws.Thumbnail, base64ImageRepresentation);
+ }
+
+ [Test]
+ public void WillNotStoreInvalidBase64StringInThumbnailProperty()
+ {
+ // Arrange
+ var invalidImagePath = "GenericString";
+
+ // Act
+ if (!(this.CurrentDynamoModel.CurrentWorkspace is HomeWorkspaceModel hws))
+ throw new Exception("current workspace is not a HomeWorkspaceModel");
+ hws.Thumbnail = invalidImagePath;
+
+ // Assert
+ Assert.IsNull(hws.Thumbnail);
+ }
}
}
diff --git a/test/DynamoCoreTests/Graph/Workspaces/thumbnailTestImage.png b/test/DynamoCoreTests/Graph/Workspaces/thumbnailTestImage.png
new file mode 100644
index 00000000000..6e4f005b3b7
Binary files /dev/null and b/test/DynamoCoreTests/Graph/Workspaces/thumbnailTestImage.png differ
diff --git a/test/core/dummy_node/2080_JSONTESTCRASH undo_redo.dyn b/test/core/dummy_node/2080_JSONTESTCRASH undo_redo.dyn
index d015940da0a..fe13685ae1c 100644
--- a/test/core/dummy_node/2080_JSONTESTCRASH undo_redo.dyn
+++ b/test/core/dummy_node/2080_JSONTESTCRASH undo_redo.dyn
@@ -53,13 +53,16 @@
"Connectors": [],
"Dependencies": [],
"NodeLibraryDependencies": [],
+ "Thumbnail": "",
+ "GraphDocumentationURL": null,
+ "Author": "None provided",
"Bindings": [],
"View": {
"Dynamo": {
"ScaleFactor": 1.0,
"HasRunWithoutCrash": true,
"IsVisibleInDynamoLibrary": true,
- "Version": "2.3.0.5184",
+ "Version": "2.11.0.4415",
"RunType": "Automatic",
"RunPeriod": "1000"
},
@@ -77,21 +80,21 @@
},
"NodeViews": [
{
- "ShowGeometry": true,
- "Name": "Code Block",
"Id": "158f8f25ddb746c88323ae262e87611e",
"IsSetAsInput": false,
"IsSetAsOutput": false,
+ "Name": "Code Block",
+ "ShowGeometry": true,
"Excluded": false,
"X": 179.8,
"Y": 160.39999999999992
},
{
- "ShowGeometry": true,
- "Name": "Code Block",
"Id": "6cbd0760736f4235a03b38fb359e9957",
"IsSetAsInput": false,
"IsSetAsOutput": false,
+ "Name": "Code Block",
+ "ShowGeometry": true,
"Excluded": false,
"X": 76.8,
"Y": 162.4