diff --git a/.github/workflows/close_stale_issues.yml b/.github/workflows/close_stale_issues.yml index 4a03b5870f2..5be33ab496a 100644 --- a/.github/workflows/close_stale_issues.yml +++ b/.github/workflows/close_stale_issues.yml @@ -20,7 +20,6 @@ jobs: - name: Summary # Print markdown list of closed issues or "No Issues" message if no issues were closed env: ISSUES_URL: ${{ format('{0}/{1}/issues', github.server_url, github.repository) }} - CLOSED_ISSUES: ${{ steps.close_issues.outputs.closed-issues-prs }} run: | echo '# Closed Issues' >> $GITHUB_STEP_SUMMARY - echo '${{ env.CLOSED_ISSUES }}' | jq --raw-output ' if (. == []) then "- No Issues." else .[] | "- \(.title) - [#\(.number)](\(${{ env.ISSUES_URL }})/\(.number))" end' >> $GITHUB_STEP_SUMMARY + echo '${{ steps.close_issues.outputs.closed-issues-prs }}' | jq --raw-output 'if (. == []) then "- No Issues." else .[] | "- \(.title) - [#\(.number)](\(env.ISSUES_URL)/\(.number))" end' >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e56b89d23ef..5e90bee85a3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -46,7 +46,7 @@ jobs: # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - name: Install dependencies for windows runtime - run: dotnet restore $Env:GITHUB_WORKSPACE\Dynamo\src\Dynamo.All.sln --runtime=win10-x64 + run: dotnet restore $Env:GITHUB_WORKSPACE\Dynamo\src\Dynamo.All.sln --runtime=win-x64 - name: Build Dynamo with MSBuild for Windows run: | echo "***Continue with the build, Good luck developer!***" diff --git a/.github/workflows/dynamoAllNet6.0_build.yml b/.github/workflows/dynamoAllNet6.0_build.yml index f8965faa87a..d3be844e7a5 100644 --- a/.github/workflows/dynamoAllNet6.0_build.yml +++ b/.github/workflows/dynamoAllNet6.0_build.yml @@ -19,7 +19,7 @@ jobs: - name: Install dependencies for windows runtime run: | - dotnet restore $Env:GITHUB_WORKSPACE\Dynamo\src\Dynamo.All.sln /p:Configuration=Release --runtime=win10-x64 + dotnet restore $Env:GITHUB_WORKSPACE\Dynamo\src\Dynamo.All.sln /p:Configuration=Release --runtime=win-x64 - name: Build Dynamo with MSBuild for Windows run: | echo "***Continue with the build, Good luck developer!***" diff --git a/.github/workflows/dynamoAllNet8.0_build.yml b/.github/workflows/dynamoAllNet8.0_build.yml new file mode 100644 index 00000000000..fc030856092 --- /dev/null +++ b/.github/workflows/dynamoAllNet8.0_build.yml @@ -0,0 +1,40 @@ +# Build Dynamo using latest VS and DotNET +name: DynamoAllNet8.0-Build +on: [push,pull_request] +jobs: + build: + runs-on: windows-latest + steps: + - name: Checkout Dynamo Repo + uses: actions/checkout@v4 + with: + path: Dynamo + repository: DynamoDS/Dynamo + - name: Setup dotnet + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '8.0.x' + - name: Disable problem matcher + run: echo "::remove-matcher owner=csc::" + + - name: Install dependencies for windows runtime + run: | + dotnet restore $Env:GITHUB_WORKSPACE\Dynamo\src\Dynamo.All.sln /p:Configuration=Release --runtime=win-x64 -p:DotNet=net8.0 + - name: Build Dynamo with MSBuild for Windows + run: | + echo "***Continue with the build, Good luck developer!***" + cd "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\" + .\MSBuild.exe $Env:GITHUB_WORKSPACE\Dynamo\src\Dynamo.All.sln /p:Configuration=Release /p:DotNet=net8.0 + # look for Dynamo + - name: Navigate to Dynamo Windows Folder + run: | + cd "$Env:GITHUB_WORKSPACE\Dynamo\bin\AnyCPU\Release" + echo "***Locating DynamoCLI for Windows!***" + test ".\DynamoCLI.exe" && echo "DynamoCLI exists!" + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: DynamoSandbox + path: ${{ github.workspace }}\Dynamo\bin\AnyCPU\Release + if-no-files-found: warn + retention-days: 3 diff --git a/.github/workflows/dynamoBinDiff.yml b/.github/workflows/dynamoBinDiff.yml index 92108408997..440094f431f 100644 --- a/.github/workflows/dynamoBinDiff.yml +++ b/.github/workflows/dynamoBinDiff.yml @@ -18,7 +18,7 @@ jobs: run: echo "::remove-matcher owner=csc::" - name: Install dependencies for windows runtime run: | - dotnet restore $Env:GITHUB_WORKSPACE\net60_Win_Dynamo\src\Dynamo.All.sln /p:Configuration=Release --runtime=win10-x64 + dotnet restore $Env:GITHUB_WORKSPACE\net60_Win_Dynamo\src\Dynamo.All.sln /p:Configuration=Release --runtime=win-x64 - name: Build Dynamo current branch with MSBuild for NET60-Windows run: | echo "***Continue with the build, Good luck developer!***" @@ -53,7 +53,7 @@ jobs: run: echo "::remove-matcher owner=csc::" - name: Install dependencies for windows runtime run: | - dotnet restore $Env:GITHUB_WORKSPACE\master_net60_Win_Dynamo\src\Dynamo.All.sln /p:Configuration=Release --runtime=win10-x64 + dotnet restore $Env:GITHUB_WORKSPACE\master_net60_Win_Dynamo\src\Dynamo.All.sln /p:Configuration=Release --runtime=win-x64 - name: Build Dynamo master branch with MSBuild for NET60-Windows run: | echo "***Continue with the build, Good luck developer!***" diff --git a/.github/workflows/dynamoNet6.0_build.yml b/.github/workflows/dynamoNet6.0_build.yml index 034aa66856b..f52c91e31fb 100644 --- a/.github/workflows/dynamoNet6.0_build.yml +++ b/.github/workflows/dynamoNet6.0_build.yml @@ -19,7 +19,7 @@ jobs: - name: Install dependencies for windows runtime run: | - dotnet restore $Env:GITHUB_WORKSPACE\Dynamo\src\DynamoCore.sln /p:Configuration=Release --runtime=win10-x64 + dotnet restore $Env:GITHUB_WORKSPACE\Dynamo\src\DynamoCore.sln /p:Configuration=Release --runtime=win-x64 - name: Build Dynamo with MSBuild for Windows run: | echo "***Continue with the build, Good luck developer!***" diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000000..9462831e8e9 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,12 @@ + + + + $(MSBuildThisFileDirectory)src\ + + diff --git a/src/Config/CS_SDK.props b/src/Config/CS_SDK.props index 580774f221b..3f3c1037183 100644 --- a/src/Config/CS_SDK.props +++ b/src/Config/CS_SDK.props @@ -4,8 +4,11 @@ Debug AnyCPU x64 + + + net6.0 16.0 - net6.0 + $(DotNet) 512 false false @@ -49,7 +52,7 @@ false - win10-x64 + win-x64 $(DefineConstants);_WINDOWS diff --git a/src/DynamoCLI/CommandLineRunner.cs b/src/DynamoCLI/CommandLineRunner.cs index 8b9a26547c0..b10f511bed6 100644 --- a/src/DynamoCLI/CommandLineRunner.cs +++ b/src/DynamoCLI/CommandLineRunner.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.IO; @@ -46,7 +46,7 @@ private static XmlDocument RunCommandLineArgs(DynamoModel model, StartupUtils.Co Console.WriteLine("geometryFilePath option is only available when running DynamoWPFCLI, not DynamoCLI"); } - model.HostAnalyticsInfo = cmdLineArgs.AnalyticsInfo; + DynamoModel.HostAnalyticsInfo = cmdLineArgs.AnalyticsInfo; cmdLineArgs.ImportedPaths.ToList().ForEach(path => { diff --git a/src/DynamoCore/DynamoCore.csproj b/src/DynamoCore/DynamoCore.csproj index 58ebc55c3b6..0e1dba3383d 100644 --- a/src/DynamoCore/DynamoCore.csproj +++ b/src/DynamoCore/DynamoCore.csproj @@ -28,8 +28,8 @@ - - + + diff --git a/src/DynamoCore/Extensions/ReadyParams.cs b/src/DynamoCore/Extensions/ReadyParams.cs index bf0a25c58ab..8de32c8fe06 100644 --- a/src/DynamoCore/Extensions/ReadyParams.cs +++ b/src/DynamoCore/Extensions/ReadyParams.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using Dynamo.Graph.Workspaces; @@ -78,7 +78,7 @@ public virtual ICommandExecutive CommandExecutive /// /// HostInfo object, Useful to determine what host context Dynamo is running in. /// - internal HostAnalyticsInfo HostInfo => dynamoModel.HostAnalyticsInfo; + internal HostAnalyticsInfo HostInfo => DynamoModel.HostAnalyticsInfo; /// diff --git a/src/DynamoCore/Extensions/StartupParams.cs b/src/DynamoCore/Extensions/StartupParams.cs index 3820c74ca7d..033a800e4f5 100644 --- a/src/DynamoCore/Extensions/StartupParams.cs +++ b/src/DynamoCore/Extensions/StartupParams.cs @@ -120,7 +120,7 @@ internal StartupParams(DynamoModel dynamoModel) pathManager = dynamoModel.PathManager; libraryLoader = new ExtensionLibraryLoader(dynamoModel); customNodeManager = dynamoModel.CustomNodeManager; - dynamoVersion = new Version(dynamoModel.Version); + dynamoVersion = new Version(DynamoModel.Version); preferences = dynamoModel.PreferenceSettings; linterManager = dynamoModel.LinterManager; IsGeometryLibraryLoaded = dynamoModel.IsASMLoaded; diff --git a/src/DynamoCore/Logging/AnalyticsService.cs b/src/DynamoCore/Logging/AnalyticsService.cs index 9af4b8333c7..500796725dc 100644 --- a/src/DynamoCore/Logging/AnalyticsService.cs +++ b/src/DynamoCore/Logging/AnalyticsService.cs @@ -1,4 +1,3 @@ -using Dynamo.Graph.Workspaces; using Dynamo.Models; using Autodesk.Analytics.ADP; using Autodesk.Analytics.Core; @@ -9,49 +8,29 @@ namespace Dynamo.Logging /// /// Utility class to support analytics tracking. /// - class AnalyticsService + internal class AnalyticsService { // Use the Analytics.Core interface so that we do not have to load the ADP assembly at this time. private static IAnalyticsUI adpAnalyticsUI; /// - /// Starts the client when DynamoModel is created. This method initializes + /// Indicates that we don't want to shut down analytics when DynamoModel shuts down. + /// Sometimes we want to keep Analytics service running even when we don't have a DynamoModel started. + /// + internal static bool KeepAlive { get; set; } + + /// + /// Starts the Analytics client. This method initializes /// the Analytics service and application life cycle start is tracked. /// - /// DynamoModel - /// Analytics won't be started if IsHeadless, but ADP may be loaded to be disabled. - /// Analytics won't be started if isTestMode, ADP will not be loaded. - internal static void Start(DynamoModel model, bool isHeadless, bool isTestMode) + internal static void Start() { - if (isTestMode) - { - if (Analytics.DisableAnalytics) - { - model.Logger.Log("Incompatible configuration: [IsTestMode] and [Analytics disabled] "); - } - return; - } - - if (isHeadless) - { - return; - } - // Initialize the concrete class only when we initialize the Service. // This will also load the Analytics.Net.ADP assembly // We must initialize the ADPAnalyticsUI instance before the Analytics.Start call. adpAnalyticsUI = new ADPAnalyticsUI(); - Analytics.Start(new DynamoAnalyticsClient(model)); - model.WorkspaceAdded += OnWorkspaceAdded; - } - - static void OnWorkspaceAdded(WorkspaceModel obj) - { - if (obj is CustomNodeWorkspaceModel) - Analytics.TrackScreenView("CustomWorkspace"); - else - Analytics.TrackScreenView("Workspace"); + Analytics.Start(new DynamoAnalyticsClient(DynamoModel.HostAnalyticsInfo)); } /// @@ -99,7 +78,10 @@ internal static bool IsADPAvailable() /// internal static void ShutDown() { - Analytics.ShutDown(); + if (!KeepAlive) + { + Analytics.ShutDown(); + } } /// @@ -113,6 +95,7 @@ internal static void ShowADPConsentDialog(IntPtr? host) adpAnalyticsUI.ShowOptInDialog(System.Threading.Thread.CurrentThread.CurrentUICulture.Name, false, host); } } + internal static string GetUserIDForSession() { if (Analytics.client is DynamoAnalyticsClient dac) diff --git a/src/DynamoCore/Logging/DynamoAnalyticsClient.cs b/src/DynamoCore/Logging/DynamoAnalyticsClient.cs index 7c72eff1b74..0e8471136ce 100644 --- a/src/DynamoCore/Logging/DynamoAnalyticsClient.cs +++ b/src/DynamoCore/Logging/DynamoAnalyticsClient.cs @@ -1,9 +1,10 @@ using System; using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; using Autodesk.Analytics.ADP; using Autodesk.Analytics.Core; using Autodesk.Analytics.Events; -using Dynamo.Interfaces; using Dynamo.Models; using Microsoft.Win32; @@ -17,7 +18,7 @@ public DynamoAnalyticsSession() SessionId = Guid.NewGuid().ToString(); } - public void Start(DynamoModel model) + public void Start() { StabilityCookie.Startup(); } @@ -68,8 +69,11 @@ public static String GetUserID() /// /// Dynamo specific implementation of IAnalyticsClient /// - class DynamoAnalyticsClient : IAnalyticsClient, IDisposable + internal class DynamoAnalyticsClient : IAnalyticsClient, IDisposable { + private readonly ManualResetEventSlim serviceInitialized = new ManualResetEventSlim(false); + private readonly object trackEventLockObj = new object(); + /// /// A dummy IDisposable class /// @@ -84,8 +88,6 @@ public void Dispose() { } private const string ANALYTICS_PROPERTY = "UA-52186525-1"; #endif - private readonly IPreferences preferences = null; - public static IDisposable Disposable { get { return new Dummy(); } } private readonly ProductInfo product; @@ -107,29 +109,24 @@ public bool ReportingAnalytics } /// - /// Constructs DynamoAnalyticsClient with given DynamoModel + /// Constructs DynamoAnalyticsClient from existing HostAnalyticsInfo /// - /// DynamoModel - public DynamoAnalyticsClient(DynamoModel dynamoModel) + public DynamoAnalyticsClient(HostAnalyticsInfo hostAnalyticsInfo) { - //Set the preferences, so that we can get live value of analytics - //reporting approved status. - preferences = dynamoModel.PreferenceSettings; - if (Session == null) Session = new DynamoAnalyticsSession(); //Setup Analytics service, and StabilityCookie. - Session.Start(dynamoModel); + Session.Start(); //Dynamo app version. - var appversion = dynamoModel.AppVersion; + var appversion = DynamoModel.AppVersion; - var hostName = string.IsNullOrEmpty(dynamoModel.HostName) ? "Dynamo" : dynamoModel.HostName; + var hostName = string.IsNullOrEmpty(hostAnalyticsInfo.HostName) ? "Dynamo" : hostAnalyticsInfo.HostName; - hostInfo = new HostContextInfo() { ParentId = dynamoModel.HostAnalyticsInfo.ParentId, SessionId = dynamoModel.HostAnalyticsInfo.SessionId }; + hostInfo = new HostContextInfo() { ParentId = hostAnalyticsInfo.ParentId, SessionId = hostAnalyticsInfo.SessionId }; string buildId = String.Empty, releaseId = String.Empty; - if (Version.TryParse(dynamoModel.Version, out Version version)) + if (Version.TryParse(DynamoModel.Version, out Version version)) { buildId = $"{version.Major}.{version.Minor}.{version.Build}"; // BuildId has the following format major.minor.build, ex: 2.5.1 releaseId = $"{version.Major}.{version.Minor}.0"; // ReleaseId has the following format: major.minor.0; ex: 2.5.0 @@ -148,16 +145,9 @@ private void RegisterADPTracker(Service service) } } - /// - /// Starts the client when DynamoModel is created. This method initializes - /// the Analytics service and application life cycle start is tracked. - /// - public void Start() + private void StartInternal() { - // Start Analytics service regardless of optin status. - // Each track event will be enabled/disabled based on the corresponding optin status. - // Ex. ADP will manage optin status internally - if (preferences != null && !Analytics.DisableAnalytics) + if (!Analytics.DisableAnalytics) { //Register trackers var service = Service.Instance; @@ -167,102 +157,214 @@ public void Start() RegisterADPTracker(service); //If not ReportingAnalytics, then set the idle time as infinite so idle state is not recorded. - Service.StartUp(product, new UserInfo(Session.UserId), hostInfo, TimeSpan.FromMinutes(30)); - TrackPreferenceInternal("ReportingAnalytics", "", ReportingAnalytics ? 1 : 0); + Service.StartUp(product, new UserInfo(Session.UserId), hostInfo, TimeSpan.FromMinutes(30)); } + + serviceInitialized.Set(); + } + /// + /// Starts the client when DynamoModel is created. This method initializes + /// the Analytics service and application life cycle start is tracked. + /// + public void Start() + { + // Start Analytics service regardless of optin status. + // Each track event will be enabled/disabled based on the corresponding optin status. + // Ex. ADP will manage optin status internally + Task.Run(() => StartInternal()); + + TrackPreference("ReportingAnalytics", "", ReportingAnalytics ? 1 : 0); } public void ShutDown() { + if (!Analytics.DisableAnalytics) serviceInitialized.Wait(); Dispose(); } public void TrackEvent(Actions action, Categories category, string description, int? value) { - if (!ReportingAnalytics) return; + if (Analytics.DisableAnalytics) return; - var e = AnalyticsEvent.Create(category.ToString(), action.ToString(), description, value); - e.Track(); + Task.Run(() => + { + serviceInitialized.Wait(); + + lock(trackEventLockObj) + { + if (!ReportingAnalytics) return; + + var e = AnalyticsEvent.Create(category.ToString(), action.ToString(), description, value); + e.Track(); + } + }); } public void TrackPreference(string name, string stringValue, int? metricValue) { - if (!ReportingAnalytics) return; + if (Analytics.DisableAnalytics) return; - TrackPreferenceInternal(name, stringValue, metricValue); - } + Task.Run(() => + { + serviceInitialized.Wait(); - private void TrackPreferenceInternal(string name, string stringValue, int? metricValue) - { - var e = AnalyticsEvent.Create(Categories.Preferences.ToString(), name, stringValue, metricValue); - e.Track(); + lock (trackEventLockObj) + { + if (!ReportingAnalytics) return; + + var e = AnalyticsEvent.Create(Categories.Preferences.ToString(), name, stringValue, metricValue); + e.Track(); + } + }); } public void TrackTimedEvent(Categories category, string variable, TimeSpan time, string description = "") { - if (!ReportingAnalytics) return; + if (Analytics.DisableAnalytics) return; - var e = new TimedEvent(time) + Task.Run(() => { - Category = category.ToString(), - VariableName = variable, - Description = description - }; - e.Track(); + serviceInitialized.Wait(); + + lock (trackEventLockObj) + { + if (!ReportingAnalytics) return; + + var e = new TimedEvent(time) + { + Category = category.ToString(), + VariableName = variable, + Description = description + }; + e.Track(); + } + }); } public void TrackScreenView(string viewName) { - if (!ReportingAnalytics) return; + if (Analytics.DisableAnalytics) return; - var e = new ScreenViewEvent(viewName); - e.Track(); + Task.Run(() => + { + serviceInitialized.Wait(); + + lock (trackEventLockObj) + { + if (!ReportingAnalytics) return; + + var e = new ScreenViewEvent(viewName); + e.Track(); + } + }); } public void TrackException(Exception ex, bool isFatal) { - if (!ReportingAnalytics) return; + if (Analytics.DisableAnalytics) return; + + Task.Run(() => + { + serviceInitialized.Wait(); + + lock (trackEventLockObj) + { + if (!ReportingAnalytics) return; - Service.TrackException(ex, isFatal); + Service.TrackException(ex, isFatal); + } + }); } + [Obsolete("Method will become private in Dynamo 4.0, please use CreateTaskTimedEvent")] public IDisposable CreateTimedEvent(Categories category, string variable, string description, int? value) - { - if (!ReportingAnalytics) return Disposable; + { + serviceInitialized.Wait(); - var e = new TimedEvent() + lock (trackEventLockObj) { - Category = category.ToString(), - VariableName = variable, - Description = description, - Value = value - }; - //Timed event does not need startup tracking. - return e; + if (!ReportingAnalytics) return Disposable; + + var e = new TimedEvent() + { + Category = category.ToString(), + VariableName = variable, + Description = description, + Value = value + }; + //Timed event does not need startup tracking. + return e; + } + } + + public Task CreateTaskTimedEvent(Categories category, string variable, string description, int? value) + { + if (Analytics.DisableAnalytics) return Task.FromResult(Disposable); + + return Task.Run(() => CreateTimedEvent(category, variable, description, value)); } + [Obsolete("Property will become private in Dynamo 4.0, please use CreateTaskCommandEvent")] public IDisposable CreateCommandEvent(string name, string description, int? value) { - if (!ReportingAnalytics) return Disposable; + serviceInitialized.Wait(); + + lock (trackEventLockObj) + { + if (!ReportingAnalytics) return Disposable; - var e = new CommandEvent(name) { Description = description, Value = value }; - e.Track(); - return e; + var e = new CommandEvent(name) { Description = description, Value = value }; + e.Track(); + return e; + } + } + + public Task CreateTaskCommandEvent(string name, string description, int? value) + { + if (Analytics.DisableAnalytics) return Task.FromResult(Disposable); + + return Task.Run(() => CreateCommandEvent(name, description, value)); } + public void EndEventTask(Task taskToEnd) + { + if (Analytics.DisableAnalytics) return; + + Task.Run(() => + { + lock(trackEventLockObj) + { + taskToEnd.Wait(); + taskToEnd.Result.Dispose(); + } + }); + } + + [Obsolete("Property will become private in Dynamo 4.0, please use TrackTaskFileOperationEvent")] public IDisposable TrackFileOperationEvent(string filepath, Actions operation, int size, string description) { + serviceInitialized.Wait(); if (!ReportingAnalytics) return Disposable; - var e = new FileOperationEvent() + lock(trackEventLockObj) { - FilePath = filepath, - FileSize = size, - FileAction = FileAction(operation), - Description = description - }; - e.Track(); - return e; + var e = new FileOperationEvent() + { + FilePath = filepath, + FileSize = size, + FileAction = FileAction(operation), + Description = description + }; + e.Track(); + return e; + } + } + + public Task TrackTaskFileOperationEvent(string filepath, Actions operation, int size, string description) + { + if (Analytics.DisableAnalytics) return Task.FromResult(Disposable); + + return Task.Run(() => TrackFileOperationEvent(filepath, operation, size, description)); } private FileOperationEvent.Actions FileAction(Actions operation) diff --git a/src/DynamoCore/Logging/IAnalyticsSession.cs b/src/DynamoCore/Logging/IAnalyticsSession.cs index 6d0fe530914..da823da1ffb 100644 --- a/src/DynamoCore/Logging/IAnalyticsSession.cs +++ b/src/DynamoCore/Logging/IAnalyticsSession.cs @@ -1,5 +1,4 @@ -using System; -using Dynamo.Models; +using System; namespace Dynamo.Logging { @@ -21,11 +20,10 @@ public interface IAnalyticsSession : IDisposable string SessionId { get; } /// - /// Starts the session for the given DynamoModel. + /// Starts the session. /// The Session is closed when Dispose() is called. /// - /// DynamoModel - void Start(DynamoModel model); + void Start(); /// /// Returns a logger to record usage. /// diff --git a/src/DynamoCore/Models/DynamoModel.cs b/src/DynamoCore/Models/DynamoModel.cs index 50a365b7492..fdf829cd882 100644 --- a/src/DynamoCore/Models/DynamoModel.cs +++ b/src/DynamoCore/Models/DynamoModel.cs @@ -199,7 +199,7 @@ internal LuceneSearchUtility LuceneUtility /// /// This version of Dynamo. /// - public string Version + public static string Version { get { return DefaultUpdateManager.GetProductVersion().ToString(); } } @@ -218,7 +218,7 @@ public string Version /// /// Host analytics info /// - public HostAnalyticsInfo HostAnalyticsInfo { get; set; } + public static HostAnalyticsInfo HostAnalyticsInfo { get; set; } /// /// Boolean indication of launching Dynamo in service mode, this mode is optimized for minimal launch time, mostly leveraged by CLI or WPF CLI. @@ -288,7 +288,7 @@ public string Version /// /// The application version string for analytics reporting APIs /// - internal virtual string AppVersion + internal static string AppVersion { get { @@ -734,20 +734,7 @@ protected DynamoModel(IStartConfiguration config) // or the feature flags client for web traffic reason. if (!IsServiceMode && !areAnalyticsDisabledFromConfig && !Analytics.DisableAnalytics) { - // Start the Analytics service only when a session is not present. - // In an integrator host, as splash screen can be closed without shutting down the ViewModel, the analytics service is not stopped. - // So we don't want to start it when splash screen or dynamo window is launched again. - if (Analytics.client == null) - { - AnalyticsService.Start(this, IsHeadless, IsTestMode); - } - else if (Analytics.client is DynamoAnalyticsClient dac) - { - if (dac.Session == null) - { - AnalyticsService.Start(this, IsHeadless, IsTestMode); - } - } + HandleAnalytics(); //run process startup/reading on another thread so we don't block dynamo startup. //if we end up needing to control aspects of dynamo model or view startup that we can't make @@ -1026,6 +1013,38 @@ protected DynamoModel(IStartConfiguration config) DynamoReady(new ReadyParams(this)); } + private void HandleAnalytics() + { + if (IsTestMode) + { + if (Analytics.DisableAnalytics) + { + Logger.Log("Incompatible configuration: [IsTestMode] and [Analytics disabled] "); + } + return; + } + + if (IsHeadless) + { + return; + } + + // Start the Analytics service only when a session is not present. + // In an integrator host, as splash screen can be closed without shutting down the ViewModel, the analytics service is not stopped. + // So we don't want to start it when splash screen or dynamo window is launched again. + if (Analytics.client == null) + { + AnalyticsService.Start(); + } + else if (Analytics.client is DynamoAnalyticsClient dac) + { + if (dac.Session == null) + { + AnalyticsService.Start(); + } + } + } + private void SearchModel_ItemProduced(NodeModel node) { ExecuteCommand(new CreateNodeCommand(node, 0, 0, true, true)); @@ -1611,6 +1630,7 @@ private void InitializeNodeLibrary() DumpLibrarySnapshot(functionGroups); #endif + // Load local custom nodes and locally imported libraries foreach (var path in pathManager.DefinitionDirectories) { diff --git a/src/DynamoCore/Models/DynamoModelEvents.cs b/src/DynamoCore/Models/DynamoModelEvents.cs index 7a76d0379c7..2860fd24ad4 100644 --- a/src/DynamoCore/Models/DynamoModelEvents.cs +++ b/src/DynamoCore/Models/DynamoModelEvents.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using Dynamo.Graph; using Dynamo.Extensions; +using Dynamo.Logging; namespace Dynamo.Models { @@ -158,6 +159,11 @@ protected virtual void OnWorkspaceAdded(WorkspaceModel obj) var handler = WorkspaceAdded; if (handler != null) handler(obj); + if (obj is CustomNodeWorkspaceModel) + Analytics.TrackScreenView("CustomWorkspace"); + else + Analytics.TrackScreenView("Workspace"); + WorkspaceEvents.OnWorkspaceAdded(obj.Guid, obj.Name, obj.GetType()); } diff --git a/src/DynamoCore/Models/RecordableCommands.cs b/src/DynamoCore/Models/RecordableCommands.cs index 557827372e8..44355e6cf15 100644 --- a/src/DynamoCore/Models/RecordableCommands.cs +++ b/src/DynamoCore/Models/RecordableCommands.cs @@ -528,7 +528,7 @@ protected override void SerializeCore(XmlElement element) internal override void TrackAnalytics() { // Log file open action and the number of nodes in the opened workspace - Dynamo.Logging.Analytics.TrackFileOperationEvent( + Dynamo.Logging.Analytics.TrackTaskFileOperationEvent( FilePath, Logging.Actions.Open, dynamoModel.CurrentWorkspace.Nodes.Count()); @@ -628,7 +628,7 @@ protected override void SerializeCore(XmlElement element) internal override void TrackAnalytics() { // Log file open action and the number of nodes in the opened workspace - Dynamo.Logging.Analytics.TrackFileOperationEvent( + Dynamo.Logging.Analytics.TrackTaskFileOperationEvent( FilePath, Logging.Actions.Open, dynamoModel.CurrentWorkspace.Nodes.Count()); @@ -705,7 +705,7 @@ protected override void SerializeCore(XmlElement element) internal override void TrackAnalytics() { // Log file open action and the number of nodes in the opened workspace - Dynamo.Logging.Analytics.TrackFileOperationEvent( + Dynamo.Logging.Analytics.TrackTaskFileOperationEvent( "In memory json file", Logging.Actions.Open, dynamoModel.CurrentWorkspace.Nodes.Count()); @@ -1795,7 +1795,7 @@ protected override void SerializeCore(XmlElement element) internal override void TrackAnalytics() { - Dynamo.Logging.Analytics.TrackCommandEvent( + Dynamo.Logging.Analytics.TrackTaskCommandEvent( CmdOperation.ToString()); // "Undo" or "Redo" } diff --git a/src/DynamoCoreWpf/DynamoCoreWpf.csproj b/src/DynamoCoreWpf/DynamoCoreWpf.csproj index 1412882a168..10d0ffd0db0 100644 --- a/src/DynamoCoreWpf/DynamoCoreWpf.csproj +++ b/src/DynamoCoreWpf/DynamoCoreWpf.csproj @@ -129,7 +129,7 @@ - + @@ -150,7 +150,7 @@ - ..\..\extern\Microsoft.Xaml.Behaviors\$(TargetFramework)\Dynamo.Microsoft.Xaml.Behaviors.dll + ..\..\extern\Microsoft.Xaml.Behaviors\net6.0-windows\Dynamo.Microsoft.Xaml.Behaviors.dll diff --git a/src/DynamoCoreWpf/Utilities/CrashReportTool.cs b/src/DynamoCoreWpf/Utilities/CrashReportTool.cs index 67249bb0f70..40f742d1a25 100644 --- a/src/DynamoCoreWpf/Utilities/CrashReportTool.cs +++ b/src/DynamoCoreWpf/Utilities/CrashReportTool.cs @@ -228,9 +228,9 @@ internal static bool ShowCrashErrorReportWindow(DynamoViewModel viewModel, Crash string appConfig = ""; if (model != null) { - var appName = GetHostAppName(model); - appConfig = $""; } @@ -271,18 +271,14 @@ internal static bool ShowCrashErrorReportWindow(DynamoViewModel viewModel, Crash return false; } - internal static string GetHostAppName(DynamoModel model) + internal static string GetHostAppName() { //default to app name being process name, but prefer HostAnalyticsInfo.HostName //then legacy Model.HostName var appName = Process.GetCurrentProcess().ProcessName; - if (!string.IsNullOrEmpty(model.HostAnalyticsInfo.HostName)) + if (!string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName)) { - appName = model.HostAnalyticsInfo.HostName; - } - else if (!string.IsNullOrEmpty(model.HostName)) - { - appName = model.HostName; + appName = DynamoModel.HostAnalyticsInfo.HostName; } return appName; diff --git a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs index 5985e801a57..d1f5ff0b286 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs @@ -479,7 +479,7 @@ public ObservableCollection RecentFiles public string Version { - get { return model.Version; } + get { return DynamoModel.Version; } } public string HostVersion @@ -2817,7 +2817,7 @@ public void SaveImage(object parameters) { OnRequestSaveImage(this, new ImageSaveEventArgs(parameters.ToString())); - Dynamo.Logging.Analytics.TrackCommandEvent("ImageCapture", + Dynamo.Logging.Analytics.TrackTaskCommandEvent("ImageCapture", "NodeCount", CurrentSpace.Nodes.Count()); } @@ -3292,7 +3292,7 @@ private void ExportToSTL(object parameter) { BackgroundPreviewViewModel.ExportToSTL(_fileDialog.FileName, HomeSpace.Name); - Dynamo.Logging.Analytics.TrackCommandEvent("ExportToSTL"); + Dynamo.Logging.Analytics.TrackTaskCommandEvent("ExportToSTL"); } } diff --git a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs index aa64e8920fe..38e8fb18017 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs @@ -1681,7 +1681,7 @@ private void DoGraphAutoLayout(object o) Model.DoGraphAutoLayout(); DynamoViewModel.RaiseCanExecuteUndoRedo(); - Dynamo.Logging.Analytics.TrackCommandEvent("GraphLayout"); + Dynamo.Logging.Analytics.TrackTaskCommandEvent("GraphLayout"); } private static bool CanDoGraphAutoLayout(object o) @@ -1753,7 +1753,7 @@ internal void CollapseSelectedNodes() DynamoViewModel.Model.CustomNodeManager.Collapse(selectedNodes, selectedNotes, Model, DynamoModel.IsTestMode, args)); - Dynamo.Logging.Analytics.TrackCommandEvent("NewCustomNode", + Dynamo.Logging.Analytics.TrackTaskCommandEvent("NewCustomNode", "NodeCount", selectedNodes.Count()); } diff --git a/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs b/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs index 4c3b2a1fa65..e7bbbf1395d 100644 --- a/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Menu/PreferencesViewModel.cs @@ -1050,7 +1050,7 @@ public bool IsDynamoRevit { // HostAnalyticsInfo is not set when this is invoked?? //return this.dynamoViewModel.Model.HostAnalyticsInfo.HostName.Equals("Dynamo Revit"); - var host = this.dynamoViewModel.Model.HostAnalyticsInfo.HostName; + var host = DynamoModel.HostAnalyticsInfo.HostName; if (host != null) { diff --git a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerClientViewModel.cs b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerClientViewModel.cs index dea21f98741..7ac62388b67 100644 --- a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerClientViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerClientViewModel.cs @@ -894,7 +894,7 @@ internal async void ExecutePackageDownload(string name, PackageVersion package, // Determine if there are any dependencies that are made with a newer version // of Dynamo (this includes the root package) - var dynamoVersion = VersionUtilities.PartialParse(DynamoViewModel.Model.Version); + var dynamoVersion = VersionUtilities.PartialParse(DynamoModel.Version); var futureDeps = newPackageHeaders.Where(dep => VersionUtilities.PartialParse(dep.engine_version) > dynamoVersion); // If any of the required packages use a newer version of Dynamo, show a dialog to the user diff --git a/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs b/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs index 512cd8693c9..1e00d55d0f7 100644 --- a/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs @@ -213,7 +213,7 @@ internal MLNodeAutoCompletionRequest GenerateRequestForMLAutocomplete() request.Port.ListAtLevel = portInfo.Level; // Set host info - var hostName = string.IsNullOrEmpty(dynamoViewModel.Model.HostAnalyticsInfo.HostName) ? dynamoViewModel.Model.HostName : dynamoViewModel.Model.HostAnalyticsInfo.HostName; + var hostName = string.IsNullOrEmpty(DynamoModel.HostAnalyticsInfo.HostName) ? dynamoViewModel.Model.HostName : DynamoModel.HostAnalyticsInfo.HostName; var hostNameEnum = GetHostNameEnum(hostName); if (hostNameEnum != HostNames.None) diff --git a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs index 318cca4b224..153b1af1e9d 100644 --- a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs @@ -1506,7 +1506,7 @@ private void DynamoViewModelRequestShowPackageManagerSearch(object s, EventArgs if (!DisplayTermsOfUseForAcceptance()) return; // Terms of use not accepted. - var cmd = Analytics.TrackCommandEvent("SearchPackage"); + var cmd = Analytics.TrackTaskCommandEvent("SearchPackage"); // The package search view model is shared and can be shared by resources at the moment // If it hasn't been initialized yet, we do that here @@ -1527,7 +1527,7 @@ private void DynamoViewModelRequestShowPackageManagerSearch(object s, EventArgs WindowStartupLocation = WindowStartupLocation.CenterOwner }; - _searchPkgsView.Closed += (sender, args) => { _searchPkgsView = null; cmd.Dispose(); }; + _searchPkgsView.Closed += (sender, args) => { _searchPkgsView = null; Analytics.EndTaskCommandEvent(cmd); }; _searchPkgsView.Show(); if (_searchPkgsView.IsLoaded && IsLoaded) _searchPkgsView.Owner = this; diff --git a/src/DynamoCoreWpf/Views/Menu/PreferencesView.xaml.cs b/src/DynamoCoreWpf/Views/Menu/PreferencesView.xaml.cs index 9b3e0f85fbf..90e976e3d10 100644 --- a/src/DynamoCoreWpf/Views/Menu/PreferencesView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Menu/PreferencesView.xaml.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; @@ -36,7 +37,7 @@ public partial class PreferencesView : Window // Used for tracking the manage package command event // This is not a command any more but we keep it // around in a compatible way for now - private IDisposable managePackageCommandEvent; + private Task managePackageCommandEvent; //This list will be passed everytime that we create a new GroupStyle so the custom colors can remain internal ObservableCollection stylesCustomColors; @@ -367,7 +368,7 @@ private void InstalledPackagesExpander_OnExpanded(object sender, RoutedEventArgs { if (e.OriginalSource == e.Source) { - managePackageCommandEvent = Analytics.TrackCommandEvent("ManagePackage"); + managePackageCommandEvent = Analytics.TrackTaskCommandEvent("ManagePackage"); } } @@ -375,7 +376,7 @@ private void InstalledPackagesExpander_OnCollapsed(object sender, RoutedEventArg { if (e.OriginalSource == e.Source) { - managePackageCommandEvent?.Dispose(); + Analytics.EndTaskCommandEvent(managePackageCommandEvent); } } diff --git a/src/DynamoCoreWpf/Views/SplashScreen/SplashScreen.xaml.cs b/src/DynamoCoreWpf/Views/SplashScreen/SplashScreen.xaml.cs index 2a56843cc30..db0c28c3298 100644 --- a/src/DynamoCoreWpf/Views/SplashScreen/SplashScreen.xaml.cs +++ b/src/DynamoCoreWpf/Views/SplashScreen/SplashScreen.xaml.cs @@ -83,7 +83,7 @@ public DynamoView DynamoView // When view model is closed, we need to close the splash screen if it is displayed. viewModel.RequestClose += SplashScreenRequestClose; authManager = viewModel.Model.AuthenticationManager; - hostAnalyticsInfo = viewModel.Model.HostAnalyticsInfo; + hostAnalyticsInfo = DynamoModel.HostAnalyticsInfo; } } diff --git a/src/DynamoManipulation/DynamoManipulation.csproj b/src/DynamoManipulation/DynamoManipulation.csproj index 3fd119cd57e..fce8a5a9727 100644 --- a/src/DynamoManipulation/DynamoManipulation.csproj +++ b/src/DynamoManipulation/DynamoManipulation.csproj @@ -40,7 +40,7 @@ - + diff --git a/src/Libraries/Analysis/Analysis.csproj b/src/Libraries/Analysis/Analysis.csproj index 4455b184bfe..b2fa05a286e 100644 --- a/src/Libraries/Analysis/Analysis.csproj +++ b/src/Libraries/Analysis/Analysis.csproj @@ -18,7 +18,7 @@ - + {7858fa8c-475f-4b8e-b468-1f8200778cf8} DynamoCore diff --git a/src/Libraries/CoreNodes/CoreNodes.csproj b/src/Libraries/CoreNodes/CoreNodes.csproj index 50f972b1c2e..c23822eea93 100644 --- a/src/Libraries/CoreNodes/CoreNodes.csproj +++ b/src/Libraries/CoreNodes/CoreNodes.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/Libraries/DSOffice/DSOffice.csproj b/src/Libraries/DSOffice/DSOffice.csproj index c66bda5be3a..d01d11d7444 100644 --- a/src/Libraries/DSOffice/DSOffice.csproj +++ b/src/Libraries/DSOffice/DSOffice.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/Libraries/DSOfficeUtilities/DSOfficeUtilities.csproj b/src/Libraries/DSOfficeUtilities/DSOfficeUtilities.csproj index 1a58e9b98a9..8a40de6fe32 100644 --- a/src/Libraries/DSOfficeUtilities/DSOfficeUtilities.csproj +++ b/src/Libraries/DSOfficeUtilities/DSOfficeUtilities.csproj @@ -22,7 +22,7 @@ tlbimp False - + {2DF8D04C-5BFA-101B-BDE5-00AA0044DE52} 2 8 diff --git a/src/Libraries/DynamoUnits/UnitsCore.csproj b/src/Libraries/DynamoUnits/UnitsCore.csproj index f85ce46e588..43309c7e8aa 100644 --- a/src/Libraries/DynamoUnits/UnitsCore.csproj +++ b/src/Libraries/DynamoUnits/UnitsCore.csproj @@ -40,6 +40,7 @@ + diff --git a/src/Libraries/GeometryColor/GeometryColor.csproj b/src/Libraries/GeometryColor/GeometryColor.csproj index d8998af4b2a..37a39a5cf33 100644 --- a/src/Libraries/GeometryColor/GeometryColor.csproj +++ b/src/Libraries/GeometryColor/GeometryColor.csproj @@ -14,7 +14,7 @@ MSB3539;CS1591;NUnit2005;NUnit2007;CS0618;CS0612;CS0672 - + diff --git a/src/Libraries/GeometryUI/GeometryUI.csproj b/src/Libraries/GeometryUI/GeometryUI.csproj index 39758013410..0bedc465b8b 100644 --- a/src/Libraries/GeometryUI/GeometryUI.csproj +++ b/src/Libraries/GeometryUI/GeometryUI.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/Libraries/GeometryUIWpf/GeometryUIWpf.csproj b/src/Libraries/GeometryUIWpf/GeometryUIWpf.csproj index 387cdb40dd0..c96a3793440 100644 --- a/src/Libraries/GeometryUIWpf/GeometryUIWpf.csproj +++ b/src/Libraries/GeometryUIWpf/GeometryUIWpf.csproj @@ -21,7 +21,7 @@ - + diff --git a/src/Libraries/PythonNodeModelsWpf/PythonNode.cs b/src/Libraries/PythonNodeModelsWpf/PythonNode.cs index 1130a7f6974..f2e60676e61 100644 --- a/src/Libraries/PythonNodeModelsWpf/PythonNode.cs +++ b/src/Libraries/PythonNodeModelsWpf/PythonNode.cs @@ -183,7 +183,7 @@ private void EditScriptContent(object sender, EventArgs e) { try { - using (var cmd = Dynamo.Logging.Analytics.TrackCommandEvent("PythonEdit")) + using (var cmd = Dynamo.Logging.Analytics.TrackTaskCommandEvent("PythonEdit")) { if (editWindow != null) { diff --git a/src/Libraries/Tesellation/Tessellation.csproj b/src/Libraries/Tesellation/Tessellation.csproj index e4f3e5dc809..a5dccde4a12 100644 --- a/src/Libraries/Tesellation/Tessellation.csproj +++ b/src/Libraries/Tesellation/Tessellation.csproj @@ -14,7 +14,7 @@ MSB3539;CS1591;NUnit2005;NUnit2007;CS0618;CS0612;CS0672 - + diff --git a/src/LibraryViewExtensionWebView2/LibraryViewExtensionWebView2.csproj b/src/LibraryViewExtensionWebView2/LibraryViewExtensionWebView2.csproj index 428eed2ece2..10118881162 100644 --- a/src/LibraryViewExtensionWebView2/LibraryViewExtensionWebView2.csproj +++ b/src/LibraryViewExtensionWebView2/LibraryViewExtensionWebView2.csproj @@ -181,7 +181,7 @@ - ..\..\extern\Microsoft.Xaml.Behaviors\$(TargetFramework)\Dynamo.Microsoft.Xaml.Behaviors.dll + ..\..\extern\Microsoft.Xaml.Behaviors\net6.0-windows\Dynamo.Microsoft.Xaml.Behaviors.dll diff --git a/src/NodeServices/Analytics.cs b/src/NodeServices/Analytics.cs index 2031ec5c7cc..052b1bd21b7 100644 --- a/src/NodeServices/Analytics.cs +++ b/src/NodeServices/Analytics.cs @@ -1,4 +1,6 @@ using System; +using System.Threading; +using System.Threading.Tasks; namespace Dynamo.Logging { @@ -38,9 +40,6 @@ internal static void Start(IAnalyticsClient client) internal static void ShutDown() { if (client != null) client.ShutDown(); - - IDisposable disposable = client as IDisposable; - if (disposable != null) disposable.Dispose(); client = null; } @@ -153,6 +152,25 @@ public static IDisposable CreateTimedEvent(Categories category, string variable, return client.CreateTimedEvent(category, variable, description, value); } + /// + /// Creates a new task timed event with start state and tracks its start. + /// After the task is completed, disposing the returned event will record the event completion. + /// + /// Event category + /// Timed varaible name + /// Event description + /// A metric value associated with the event + /// Task defined by an IDisposable event + public static Task CreateTaskTimedEvent(Categories category, string variable, string description = "", int? value = null) + { + if (client == null) + { + return Task.FromResult(new Dummy() as IDisposable); + } + + return client.CreateTaskTimedEvent(category, variable, description, value); + } + /// /// Creates a new command event of the given name. Start of the /// command is tracked. When the event is disposed, it's completion is tracked. @@ -160,7 +178,7 @@ public static IDisposable CreateTimedEvent(Categories category, string variable, /// Command name /// Event description /// A metric value associated with the event - /// Event as IDisposable + /// Task defined by an IDisposable event public static IDisposable TrackCommandEvent(string name, string description = "", int? value = null) { if (client == null) return new Dummy(); @@ -168,6 +186,29 @@ public static IDisposable TrackCommandEvent(string name, string description = "" return client.CreateCommandEvent(name, description, value); } + /// + /// Creates a new command event task of the given name. Start of the + /// command is tracked. When the task is completed and the event is disposed, it's completion is tracked. + /// + /// Command name + /// Event description + /// A metric value associated with the event + /// Task defined by an IDisposable event + public static Task TrackTaskCommandEvent(string name, string description = "", int? value = null) + { + if (client == null) + { + return Task.FromResult(new Dummy() as IDisposable); + } + + return client.CreateTaskCommandEvent(name, description, value); + } + + public static void EndTaskCommandEvent(Task taskEvent) + { + client?.EndEventTask(taskEvent); + } + /// /// Creates a new file operation event and tracks the start of the event. /// Disposing the returned event will record its completion. @@ -184,6 +225,25 @@ public static IDisposable TrackFileOperationEvent(string filepath, Actions opera return client.TrackFileOperationEvent(filepath, operation, size, description); } + /// + /// Creates a new task file operation event and tracks the start of the event. + /// After the task is completed, disposing the returned event will record its completion. + /// + /// File path + /// File operation + /// Size parameter + /// Event description + /// Task defined by an IDisposable event + public static Task TrackTaskFileOperationEvent(string filepath, Actions operation, int size, string description = "") + { + if (client == null) + { + return Task.FromResult(new Dummy() as IDisposable); + } + + return client.TrackTaskFileOperationEvent(filepath, operation, size, description); + } + /// /// Logs usage data /// diff --git a/src/NodeServices/IAnalyticsClient.cs b/src/NodeServices/IAnalyticsClient.cs index ff9591f40df..b0fbeb0d529 100644 --- a/src/NodeServices/IAnalyticsClient.cs +++ b/src/NodeServices/IAnalyticsClient.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace Dynamo.Logging { @@ -516,6 +517,17 @@ public interface IAnalyticsClient /// Event as IDisposable IDisposable CreateTimedEvent(Categories category, string variable, string description, int? value); + /// + /// Creates a new task timed event with start state and tracks its start. + /// After task is compoleted, disposing the returnd event will record the event completion. + /// + /// Event category + /// Timed varaible name + /// Event description + /// A metric value associated with the event + /// Event as IDisposable + Task CreateTaskTimedEvent(Categories category, string variable, string description, int? value); + /// /// Creates a new command event of the given name. Start of the /// command is tracked. When the event is disposed, it's completion is tracked. @@ -526,6 +538,22 @@ public interface IAnalyticsClient /// Event as IDisposable IDisposable CreateCommandEvent(string name, string description, int? value); + /// + /// Creates a new task command event of the given name. Start of the + /// command is tracked. When the task is completed and the event is disposed, it's completion is tracked. + /// + /// Command name + /// Event description + /// A metric value associated with the event + /// Event as IDisposable + Task CreateTaskCommandEvent(string name, string description, int? value); + + /// + /// Waits for the given task to end so that it can dispose the event and + /// complete the tracking. + /// + void EndEventTask(Task taskToEnd); + /// /// Creates a new file operation event and tracks the start of the event. /// Disposing the returned event will record its completion. @@ -537,6 +565,17 @@ public interface IAnalyticsClient /// Event as IDisposable IDisposable TrackFileOperationEvent(string filepath, Actions operation, int size, string description); + /// + /// Creates a new file operation task event and tracks the start of the event. + /// After the task is completed, disposing the returned event will record its completion. + /// + /// File path + /// File operation + /// Size parameter + /// Event description + /// Event as IDisposable + Task TrackTaskFileOperationEvent(string filepath, Actions operation, int size, string description); + /// /// Logs usage data /// diff --git a/src/Tools/Md2Html/Md2Html.csproj b/src/Tools/Md2Html/Md2Html.csproj index 93db771aa16..da8b3cf2bd3 100644 --- a/src/Tools/Md2Html/Md2Html.csproj +++ b/src/Tools/Md2Html/Md2Html.csproj @@ -27,8 +27,8 @@ - - - + + + diff --git a/src/Tools/NodeDocumentationMarkdownGenerator/NodeDocumentationMarkdownGenerator.csproj b/src/Tools/NodeDocumentationMarkdownGenerator/NodeDocumentationMarkdownGenerator.csproj index 4879875bcf5..09c6da26df5 100644 --- a/src/Tools/NodeDocumentationMarkdownGenerator/NodeDocumentationMarkdownGenerator.csproj +++ b/src/Tools/NodeDocumentationMarkdownGenerator/NodeDocumentationMarkdownGenerator.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/build.xml b/src/build.xml index 3c864ffe5bc..5212c9c9237 100644 --- a/src/build.xml +++ b/src/build.xml @@ -5,7 +5,8 @@ Dynamo.All.sln Any CPU - win10-x64 + net6.0 + win-x64 $(MSBuildProjectDirectory)\..\tools\Nuget\NuGet.exe @@ -21,7 +22,7 @@ - + diff --git a/test/DynamoCoreTests/AnalyticsTests.cs b/test/DynamoCoreTests/AnalyticsTests.cs index c733b200ad7..4c19c6282e6 100644 --- a/test/DynamoCoreTests/AnalyticsTests.cs +++ b/test/DynamoCoreTests/AnalyticsTests.cs @@ -133,7 +133,7 @@ public DynamoAnalyticsTests() protected override Mock MockClient() { - var client = new Mock(CurrentDynamoModel) { CallBase = true }; + var client = new Mock(DynamoModel.HostAnalyticsInfo) { CallBase = true }; var session = MockAnalyticsSession(); client.Setup(c => c.Session).Returns(session); return client.As(); @@ -144,7 +144,7 @@ private IAnalyticsSession MockAnalyticsSession() var session = new Mock(); session.Setup(s => s.UserId).Returns("DynamoTestUser"); session.Setup(s => s.SessionId).Returns("UniqueSession"); - session.Setup(s => s.Start(It.IsAny())).Callback(SetupServices); + session.Setup(s => s.Start()).Callback(SetupServices); return session.Object; } diff --git a/test/DynamoCoreWpfTests/CrashReportingTests.cs b/test/DynamoCoreWpfTests/CrashReportingTests.cs index ec061cd4db9..44578c0296e 100644 --- a/test/DynamoCoreWpfTests/CrashReportingTests.cs +++ b/test/DynamoCoreWpfTests/CrashReportingTests.cs @@ -196,17 +196,13 @@ public void TestCERTool() public void TestAppNameSentToCER() { CurrentDynamoModel.HostName = null; - var name = CrashReportTool.GetHostAppName(CurrentDynamoModel); + var name = CrashReportTool.GetHostAppName(); //if both hostname and hostinfo.hostname are null, then use proc name. Assert.True(name.Contains("testhost") || name.Contains("nunit-agent")); - CurrentDynamoModel.HostName = "dynamotestmock"; - name = CrashReportTool.GetHostAppName(CurrentDynamoModel); - //use hostname over proc name - Assert.AreEqual(CurrentDynamoModel.HostName, name); - CurrentDynamoModel.HostAnalyticsInfo = new HostAnalyticsInfo(){HostName = "123"}; - name = CrashReportTool.GetHostAppName(CurrentDynamoModel); + DynamoModel.HostAnalyticsInfo = new HostAnalyticsInfo(){HostName = "123"}; + name = CrashReportTool.GetHostAppName(); //prefer hostinfo.hostname over others. - Assert.AreEqual(CurrentDynamoModel.HostAnalyticsInfo.HostName, name); + Assert.AreEqual(DynamoModel.HostAnalyticsInfo.HostName, name); } } } diff --git a/test/DynamoCoreWpfTests/SerializationTests.cs b/test/DynamoCoreWpfTests/SerializationTests.cs index e1bc89b0a97..aae2f7e7de8 100644 --- a/test/DynamoCoreWpfTests/SerializationTests.cs +++ b/test/DynamoCoreWpfTests/SerializationTests.cs @@ -474,7 +474,6 @@ public string GetJsonPropertydName(string propertyName) } [Test] - [Category("Failure")] public void JSONisSameBeforeAndAfterSaveWithDummyNodes() { var testFileWithDummyNode = @"core\dummy_node\2080_JSONTESTCRASH undo_redo.dyn"; diff --git a/test/Libraries/AnalysisTests/AnalysisTests.csproj b/test/Libraries/AnalysisTests/AnalysisTests.csproj index 0dff2f73d13..2fe8926ce2f 100644 --- a/test/Libraries/AnalysisTests/AnalysisTests.csproj +++ b/test/Libraries/AnalysisTests/AnalysisTests.csproj @@ -10,7 +10,7 @@ AnalysisTests - + diff --git a/test/Libraries/CommandLineTests/CommandLineTests.cs b/test/Libraries/CommandLineTests/CommandLineTests.cs index 7c3a153659c..e2e16ae5bc3 100644 --- a/test/Libraries/CommandLineTests/CommandLineTests.cs +++ b/test/Libraries/CommandLineTests/CommandLineTests.cs @@ -95,7 +95,7 @@ public void CanSetHostNameWithCommandLineRunner() string commandstring = $"-o {openpath} --HostName {hostName}"; runner.Run(CommandstringToArgs(commandstring)); - Assert.AreEqual(this.CurrentDynamoModel.HostAnalyticsInfo.HostName, "DynamoFormIt"); + Assert.AreEqual(Dynamo.Models.DynamoModel.HostAnalyticsInfo.HostName, "DynamoFormIt"); } [Test] @@ -107,7 +107,7 @@ public void CanSetParentIdWithCommandLineRunner() string commandstring = $"-o {openpath} -p {parentId}"; runner.Run(CommandstringToArgs(commandstring)); - Assert.AreEqual(this.CurrentDynamoModel.HostAnalyticsInfo.ParentId, "RVT&2022&MUI64&22.0.2.392"); + Assert.AreEqual(Dynamo.Models.DynamoModel.HostAnalyticsInfo.ParentId, "RVT&2022&MUI64&22.0.2.392"); } [Test] @@ -119,7 +119,7 @@ public void CanSetSessionIdWithCommandLineRunner() string commandstring = $"-o {openpath} -s {sessionId}"; runner.Run(CommandstringToArgs(commandstring)); - Assert.AreEqual(this.CurrentDynamoModel.HostAnalyticsInfo.SessionId, "ABCDEFG"); + Assert.AreEqual(Dynamo.Models.DynamoModel.HostAnalyticsInfo.SessionId, "ABCDEFG"); } [Test] diff --git a/test/Libraries/DynamoPythonTests/DynamoPythonTests.csproj b/test/Libraries/DynamoPythonTests/DynamoPythonTests.csproj index 27289c45177..61ca139c0a8 100644 --- a/test/Libraries/DynamoPythonTests/DynamoPythonTests.csproj +++ b/test/Libraries/DynamoPythonTests/DynamoPythonTests.csproj @@ -18,7 +18,7 @@ - + diff --git a/test/Libraries/GeometryColorTests/GeometryColorTests.csproj b/test/Libraries/GeometryColorTests/GeometryColorTests.csproj index 73cfce41973..89fd223ae16 100644 --- a/test/Libraries/GeometryColorTests/GeometryColorTests.csproj +++ b/test/Libraries/GeometryColorTests/GeometryColorTests.csproj @@ -10,7 +10,7 @@ DisplayTests - + diff --git a/test/Libraries/TestServices/TestServices.csproj b/test/Libraries/TestServices/TestServices.csproj index e7978075a5b..baa200a0fcd 100644 --- a/test/Libraries/TestServices/TestServices.csproj +++ b/test/Libraries/TestServices/TestServices.csproj @@ -10,7 +10,7 @@ TestServices - + diff --git a/test/Libraries/WorkflowTests/WorkflowTests.csproj b/test/Libraries/WorkflowTests/WorkflowTests.csproj index d7c49682326..915e21a7c65 100644 --- a/test/Libraries/WorkflowTests/WorkflowTests.csproj +++ b/test/Libraries/WorkflowTests/WorkflowTests.csproj @@ -14,7 +14,7 @@ - + diff --git a/test/core/dummy_node/2080_JSONTESTCRASH undo_redo.dyn b/test/core/dummy_node/2080_JSONTESTCRASH undo_redo.dyn index f968441f2a1..81485a7590b 100644 --- a/test/core/dummy_node/2080_JSONTESTCRASH undo_redo.dyn +++ b/test/core/dummy_node/2080_JSONTESTCRASH undo_redo.dyn @@ -53,6 +53,7 @@ "Connectors": [], "Dependencies": [], "NodeLibraryDependencies": [], + "EnableLegacyPolyCurveBehavior": true, "Thumbnail": "", "GraphDocumentationURL": null, "Author": "None provided",