Skip to content

Commit

Permalink
Linter ViewExtension (#11634)
Browse files Browse the repository at this point in the history
* Initial commit

* Move event subscription to extension base class + add property changed filter to rules

* comment updates

* Update LinterExtensionBase.cs

* Update InputNodesNotAllowedRule.cs

* Add Deactivate method to linterExtensionBase + LinterManager tests

* comment updates

* Initial commit

* Add issues count to WorkspaceSaving

* add scrollviewer

* Dispose LinterManager

* Make concrete issues internal

* summaries on IRuleIssue

* comment updates

* Update severity code icon

* Serialize linter manager to dyn file

* clear ruleEvaluationResults on workspace change

* Remove test extension

* Show names instead of GUIDs

* add help doc

* clean up

* Handle GraphRuleEvaluationResults nodeIds changes

* Update LintingViewExtension.csproj

* Update LintingViewExtension.csproj

* Update SerializationConverters.cs

* Fix failing serialization test

* comment updates

* revert changes to test file

* fix available linters binding

* add rules back in test ext

* comment updates

* remove output path

* Update LinterManagerTests.cs

* comment updates

* hide LinterViewExtension and LinterExtensionBase

* Update LinterViewModel.cs
  • Loading branch information
SHKnudsen authored May 7, 2021
1 parent 2ac55d6 commit cd60aef
Show file tree
Hide file tree
Showing 42 changed files with 2,371 additions and 21 deletions.
11 changes: 11 additions & 0 deletions src/Dynamo.All.sln
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NodeAutoCompleteViewExtensi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Md2Html", "Tools\Md2Html\Md2Html.csproj", "{0893F745-CB1A-427A-8E87-CA927273039A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LintingViewExtension", "LintingViewExtension\LintingViewExtension.csproj", "{C86F9058-229D-40A9-95D5-D6F081AA9230}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -869,6 +871,14 @@ Global
{0893F745-CB1A-427A-8E87-CA927273039A}.Release|Any CPU.Build.0 = Release|Any CPU
{0893F745-CB1A-427A-8E87-CA927273039A}.Release|x64.ActiveCfg = Release|Any CPU
{0893F745-CB1A-427A-8E87-CA927273039A}.Release|x64.Build.0 = Release|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Debug|x64.ActiveCfg = Debug|x64
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Debug|x64.Build.0 = Debug|x64
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Release|Any CPU.Build.0 = Release|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Release|x64.ActiveCfg = Release|x64
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -946,6 +956,7 @@ Global
{10AF430D-0D3A-49CE-A63D-848912959745} = {88D45B00-E564-41DB-B57C-9509646CAA49}
{51511AFD-F326-4995-8E27-5D711419EF6F} = {88D45B00-E564-41DB-B57C-9509646CAA49}
{0893F745-CB1A-427A-8E87-CA927273039A} = {D114C59C-CF66-4CC2-980F-9301FB4EA4E1}
{C86F9058-229D-40A9-95D5-D6F081AA9230} = {88D45B00-E564-41DB-B57C-9509646CAA49}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {89CB19C6-BF0A-4E6A-BFDA-79D143EAB59D}
Expand Down
6 changes: 3 additions & 3 deletions src/DynamoCore/Extensions/LinterExtensionBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Dynamo.Extensions
/// <summary>
/// Base class for all LinterExtensions
/// </summary>
public abstract class LinterExtensionBase : IExtension
internal abstract class LinterExtensionBase : IExtension
{
private const string NODE_ADDED_PROPERTY = "NodeAdded";
private const string NODE_REMOVED_PROPERTY = "NodeRemoved";
Expand Down Expand Up @@ -115,7 +115,7 @@ private void EvaluateGraphRules(NodeModel modifiedNode, string changedProperty)
!rule.EvaluationTriggerEvents.Contains(changedProperty))
continue;

rule.Evaluate(currentWorkspace, modifiedNode);
rule.Evaluate(currentWorkspace, changedProperty, modifiedNode);
}
}

Expand All @@ -137,7 +137,7 @@ private void EvaluateNodeRules(NodeModel modifiedNode, string changedProperty)
if (changedProperty != NODE_ADDED_PROPERTY && !rule.EvaluationTriggerEvents.Contains(changedProperty))
continue;

rule.Evaluate(modifiedNode);
rule.Evaluate(modifiedNode, changedProperty);
}
}

Expand Down
19 changes: 12 additions & 7 deletions src/DynamoCore/Linting/LinterManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,17 @@ public LinterExtensionDescriptor ActiveLinter
{
if (activeLinter == value) return;

if (activeLinter != null)
if (activeLinter != null &&
TryGetLinterExtension(activeLinter, out LinterExtensionBase linterExtension))
{
GetLinterExtension(activeLinter).Deactivate();
linterExtension.Deactivate();
}

var linterExt = GetLinterExtension(value);
if (linterExt is null) return;
if (TryGetLinterExtension(value, out linterExtension))
{
linterExtension.Activate();
}

linterExt.Activate();
activeLinter = value;
}
}
Expand Down Expand Up @@ -131,13 +133,16 @@ private void OnRuleEvaluated(IRuleEvaluationResult result)
}
}

private LinterExtensionBase GetLinterExtension(LinterExtensionDescriptor activeLinter)

internal bool TryGetLinterExtension(LinterExtensionDescriptor activeLinter, out LinterExtensionBase linterExtension)
{
return this.extensionManager.
linterExtension = this.extensionManager.
Extensions.
OfType<LinterExtensionBase>().
Where(x => x.UniqueId == activeLinter.Id).
FirstOrDefault();

return linterExtension != null;
}

public void Dispose()
Expand Down
8 changes: 5 additions & 3 deletions src/DynamoCore/Linting/Rules/GraphLinterRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ public abstract class GraphLinterRule : LinterRule
/// This will use <see cref="EvaluateFunction(WorkspaceModel, NodeModel)"/> to evaluate the rule.
/// </summary>
/// <param name="workspaceModel"></param>
/// <param name="changedEvent"></param>
/// <param name="modifiedNode"></param>
internal void Evaluate(WorkspaceModel workspaceModel, NodeModel modifiedNode = null)
internal void Evaluate(WorkspaceModel workspaceModel, string changedEvent, NodeModel modifiedNode = null)
{
var pair = EvaluateFunction(workspaceModel, modifiedNode);
var pair = EvaluateFunction(workspaceModel, changedEvent, modifiedNode);
if (pair is null) return;

var result = new GraphRuleEvaluationResult(this.Id, pair.Item1, this.SeverityCode, pair.Item2);
Expand All @@ -33,9 +34,10 @@ internal void Evaluate(WorkspaceModel workspaceModel, NodeModel modifiedNode = n
/// Function used to evaluate this rule
/// </summary>
/// <param name="workspaceModel"></param>
/// <param name="changedEvent"></param>
/// <param name="modifiedNode"></param>
/// <returns></returns>
protected abstract Tuple<RuleEvaluationStatusEnum, HashSet<string>> EvaluateFunction(WorkspaceModel workspaceModel, NodeModel modifiedNode = null);
protected abstract Tuple<RuleEvaluationStatusEnum, HashSet<string>> EvaluateFunction(WorkspaceModel workspaceModel, string changedEvent, NodeModel modifiedNode = null);

/// <summary>
/// The init function is used when the Linter extension implementing this Rule is initialized.
Expand Down
8 changes: 5 additions & 3 deletions src/DynamoCore/Linting/Rules/NodeLinterRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ public abstract class NodeLinterRule : LinterRule
/// This will use <see cref="EvaluateFunction(NodeModel)"/> to evaluate the rule.
/// </summary>
/// <param name="nodeModel"></param>
internal void Evaluate(NodeModel nodeModel)
/// <param name="changedEvent"></param>
internal void Evaluate(NodeModel nodeModel, string changedEvent)
{
var status = EvaluateFunction(nodeModel);
var status = EvaluateFunction(nodeModel, changedEvent);
var result = new NodeRuleEvaluationResult(this.Id, status, this.SeverityCode, nodeModel.GUID.ToString());
OnRuleEvaluated(result);
}
Expand All @@ -31,8 +32,9 @@ internal void Evaluate(NodeModel nodeModel)
/// Function used to evaluate this rule
/// </summary>
/// <param name="nodeModel">Node to evaluate</param>
/// <param name="changedEvent"></param>
/// <returns></returns>
protected abstract RuleEvaluationStatusEnum EvaluateFunction(NodeModel nodeModel);
protected abstract RuleEvaluationStatusEnum EvaluateFunction(NodeModel nodeModel, string changedEvent);

/// <summary>
/// The init function is used when the Linter extension implementing this Rule is initialized.
Expand Down
3 changes: 2 additions & 1 deletion src/DynamoCore/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@
[assembly: InternalsVisibleTo("PythonNodeModelsWpf")]
[assembly: InternalsVisibleTo("PythonNodeModels")]
[assembly: InternalsVisibleTo("LibraryViewExtensionMSWebBrowser")]
[assembly: InternalsVisibleTo("PythonMigrationViewExtension")]
[assembly: InternalsVisibleTo("PythonMigrationViewExtension")]
[assembly: InternalsVisibleTo("LintingViewExtension")]
26 changes: 26 additions & 0 deletions src/LintingViewExtension/Controls/GraphRuleIssue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Dynamo.Graph.Nodes;
using Dynamo.Linting.Rules;

namespace Dynamo.LintingViewExtension.Controls
{
internal class GraphRuleIssue : IRuleIssue
{
public string Id { get; }
public LinterRule Rule { get; }
public ObservableCollection<NodeModel> AffectedNodes { get; private set; }

public GraphRuleIssue(string id, GraphLinterRule rule)
{
Id = id;
Rule = rule;
AffectedNodes = new ObservableCollection<NodeModel>();
}

public void AddAffectedNodes(List<NodeModel> nodes)
{
nodes.ForEach(x => AffectedNodes.Add(x));
}
}
}
31 changes: 31 additions & 0 deletions src/LintingViewExtension/Controls/IRuleIssue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Dynamo.Graph.Nodes;
using Dynamo.Linting.Rules;

namespace Dynamo.LintingViewExtension
{
public interface IRuleIssue
{
/// <summary>
/// Collection of nodeIds affected by this rule issue
/// </summary>
ObservableCollection<NodeModel> AffectedNodes { get; }

/// <summary>
/// Id of the rule this issue comes from
/// </summary>
string Id { get; }

/// <summary>
/// Rule this issue comes from
/// </summary>
LinterRule Rule { get; }

/// <summary>
/// Adds a list of affected nodes to this issue
/// </summary>
/// <param name="nodes"></param>
void AddAffectedNodes(List<NodeModel> nodes);
}
}
73 changes: 73 additions & 0 deletions src/LintingViewExtension/Controls/IssueGroup.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<UserControl x:Class="Dynamo.LintingViewExtension.Controls.IssueGroup"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Dynamo.LintingViewExtension.Controls"
xmlns:converter="clr-namespace:Dynamo.LintingViewExtension.Converters"
xmlns:severity="clr-namespace:Dynamo.Linting.Interfaces;assembly=DynamoCore"
xmlns:fa="http://schemas.fontawesome.io/icons/"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800">

<UserControl.Resources>
<ResourceDictionary>
<converter:SeverityCodeToColorConverter x:Key="SeverityCodeToColorConverter" />
<converter:SeverityCodeToIconConverter x:Key="SeverityCodeToIconConverter" />
<converter:CollectionToVisibilityConverter x:Key="CollectionToVisibilityConverter" />

<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground"
Value="White" />
<Setter Property="FontSize"
Value="12" />
</Style>
</ResourceDictionary>
</UserControl.Resources>

<UserControl.Template>
<ControlTemplate TargetType="{x:Type UserControl}">
<Grid DataContext="{
Binding RelativeSource={
RelativeSource FindAncestor, AncestorType=local:IssueGroup}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>


<fa:ImageAwesome Height="15"
Grid.Column="0"
Icon="{Binding SeverityCode, Converter={StaticResource SeverityCodeToIconConverter}}"
Foreground="{Binding SeverityCode, Converter={StaticResource SeverityCodeToColorConverter}}">
</fa:ImageAwesome>
<TextBlock Text="{Binding Description, FallbackValue='Header description'}"
Grid.Column="1"
TextWrapping="WrapWithOverflow"
VerticalAlignment="Center"
Margin="15 5" />

<ContentPresenter Grid.Row="1"
Grid.Column="1"
Margin="15 5"
Visibility="{Binding NodeIds, Converter={StaticResource CollectionToVisibilityConverter}}"/>

<TextBlock Text="{Binding CallToAction, FallbackValue='Call to action'}"
Grid.Row="2"
Grid.Column="1"
TextWrapping="WrapWithOverflow"
FontWeight="Bold"
Margin="15 5" />

<Separator Grid.Row="3" Grid.ColumnSpan="2"/>
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
72 changes: 72 additions & 0 deletions src/LintingViewExtension/Controls/IssueGroup.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using Dynamo.Graph.Nodes;
using Dynamo.Linting.Interfaces;
using Dynamo.Linting.Rules;

namespace Dynamo.LintingViewExtension.Controls
{
/// <summary>
/// Interaction logic for IssueGroup.xaml
/// </summary>
public partial class IssueGroup : UserControl
{
#region DependencyProperties

internal IEnumerable<NodeModel> IssueNodes
{
get { return (IEnumerable<NodeModel>)GetValue(IssueNodesProperty); }
set { SetValue(IssueNodesProperty, value); }
}

public static readonly DependencyProperty IssueNodesProperty = DependencyProperty.Register(
nameof(IssueNodes),
typeof(IEnumerable<NodeModel>),
typeof(IssueGroup)
);

public string Description
{
get { return (string)GetValue(DescriptionProperty); }
set { SetValue(DescriptionProperty, value); }
}

public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
nameof(Description),
typeof(string),
typeof(IssueGroup)
);

public string CallToAction
{
get { return (string)GetValue(CallToActionProperty); }
set { SetValue(CallToActionProperty, value); }
}

public static readonly DependencyProperty CallToActionProperty = DependencyProperty.Register(
nameof(CallToAction),
typeof(string),
typeof(IssueGroup)
);

public SeverityCodesEnum SeverityCode
{
get { return (SeverityCodesEnum)GetValue(SeverityCodeProperty); }
set { SetValue(SeverityCodeProperty, value); }
}

public static readonly DependencyProperty SeverityCodeProperty = DependencyProperty.Register(
nameof(SeverityCode),
typeof(SeverityCodesEnum),
typeof(IssueGroup)
);

#endregion DependencyProperties

public IssueGroup()
{
InitializeComponent();
}
}
}
Loading

0 comments on commit cd60aef

Please sign in to comment.