Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
23 changes: 23 additions & 0 deletions src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1422,6 +1422,7 @@ private void DynamoLoadedViewExtensionHandler(ViewLoadedParams loadedParams, IEn
Log(ext.Name + ": " + exc.Message);
}
}
DisableExtensionTabsWhenIDSDKNotInitialized();
EnsureGraphPropertiesBinding();
}

Expand Down Expand Up @@ -3414,5 +3415,27 @@ internal bool DisableExtensionWhenNoNetworkMode(string extensionId, string exten

return false;
}

/// <summary>
/// Disables (but keeps visible) the Autodesk Assistant and MCP sidebar tabs when IDSDK is
/// not initialized, preventing the cascade of native error dialogs that occur when the user
/// opens the Assistant without Autodesk Identity installed.
/// </summary>
internal void DisableExtensionTabsWhenIDSDKNotInitialized()
{
if (dynamoViewModel.Model.AuthenticationManager.IsIDSDKInitialized())
return;

foreach (var extensionId in new[] { AutodeskAssistantExtensionId, McpViewExtensionId })
{
var tab = dynamoViewModel.SideBarTabItems.OfType<TabItem>()
.SingleOrDefault(t => string.Equals(t.Uid, extensionId, StringComparison.OrdinalIgnoreCase));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SingleOrDefault() throws InvalidOperationException if two tabs ever share a Uid ... rare, but possible when re-adding a tab. Better to be safe and not assume uniqueness. An exception here can crash the UI.

if (tab != null)
{
tab.IsEnabled = false;
Log($"Extension tab {tab.Header} disabled because IDSDK is not initialized");
}
Comment on lines +3438 to +3444
}
}
}
}
109 changes: 109 additions & 0 deletions test/DynamoCoreWpfTests/DynamoViewNoNetworkModeTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Dynamo.Controls;
using Dynamo.Core;
using Dynamo.Models;
using Dynamo.ViewModels;
using NUnit.Framework;
Expand Down Expand Up @@ -100,5 +101,113 @@ public void UnrecognizedExtensionIsNotDisabledWhenNoNetworkModeIsEnabled()

Assert.IsFalse(shouldDisable);
}

[Test]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests assume the IDSDK is unavailable, but on a test machine or a dev machine, it might be installed and fail.

Add Assume.That(!...IsIDSDKInitialized()) or Assert.Ignore

public void AssistantAndMcpTabsAreDisabledWhenIDSDKIsNotInitialized()
{
var pathResolver = new TestPathResolver();
DynamoModel modelWithUninitializedIDSDK = null;
DynamoViewModel viewModelWithUninitializedIDSDK = null;
DynamoView viewWithUninitializedIDSDK = null;

try
{
// IDSDKManager.IsIDSDKInitialized returns false when the native IDSDK library
// is not installed (e.g. test environments, VMs without Autodesk Identity).
modelWithUninitializedIDSDK = DynamoModel.Start(new DynamoModel.DefaultStartConfiguration()
{
PathResolver = pathResolver,
StartInTestMode = true,
GeometryFactoryPath = preloader.GeometryFactoryPath,
ProcessMode = Dynamo.Scheduler.TaskProcessMode.Synchronous,
NoNetworkMode = false,
AuthProvider = new IDSDKManager()
});

Comment on lines +128 to +129
viewModelWithUninitializedIDSDK = DynamoViewModel.Start(new DynamoViewModel.StartConfiguration()
{
DynamoModel = modelWithUninitializedIDSDK
});

viewWithUninitializedIDSDK = new DynamoView(viewModelWithUninitializedIDSDK);

// Simulate the extension having loaded its tab into the sidebar.
var assistantTab = new System.Windows.Controls.TabItem { Uid = DynamoView.AutodeskAssistantExtensionId };
var mcpTab = new System.Windows.Controls.TabItem { Uid = DynamoView.McpViewExtensionId };
viewModelWithUninitializedIDSDK.SideBarTabItems.Add(assistantTab);
viewModelWithUninitializedIDSDK.SideBarTabItems.Add(mcpTab);

viewWithUninitializedIDSDK.DisableExtensionTabsWhenIDSDKNotInitialized();

Assert.IsFalse(assistantTab.IsEnabled);
Assert.IsFalse(mcpTab.IsEnabled);
}
finally
{
if (viewWithUninitializedIDSDK != null && viewWithUninitializedIDSDK.IsLoaded)
{
viewWithUninitializedIDSDK.Close();
}

if (viewModelWithUninitializedIDSDK != null)
{
var shutdownParams = new DynamoViewModel.ShutdownParams(shutdownHost: false, allowCancellation: false);
viewModelWithUninitializedIDSDK.PerformShutdownSequence(shutdownParams);
}
}
}

[Test]
public void AssistantAndMcpTabsAreNotDisabledWhenIDSDKIsInitialized()
{
var pathResolver = new TestPathResolver();
DynamoModel modelWithNullAuthProvider = null;
DynamoViewModel viewModelWithNullAuthProvider = null;
DynamoView viewWithNullAuthProvider = null;

try
{
// When AuthProvider is null (host environment or no IDSDK configured),
// IsIDSDKInitialized() returns true — tabs should remain enabled.
modelWithNullAuthProvider = DynamoModel.Start(new DynamoModel.DefaultStartConfiguration()
{
PathResolver = pathResolver,
StartInTestMode = true,
GeometryFactoryPath = preloader.GeometryFactoryPath,
ProcessMode = Dynamo.Scheduler.TaskProcessMode.Synchronous,
NoNetworkMode = false
});

viewModelWithNullAuthProvider = DynamoViewModel.Start(new DynamoViewModel.StartConfiguration()
{
DynamoModel = modelWithNullAuthProvider
});

viewWithNullAuthProvider = new DynamoView(viewModelWithNullAuthProvider);

var assistantTab = new System.Windows.Controls.TabItem { Uid = DynamoView.AutodeskAssistantExtensionId };
var mcpTab = new System.Windows.Controls.TabItem { Uid = DynamoView.McpViewExtensionId };
viewModelWithNullAuthProvider.SideBarTabItems.Add(assistantTab);
viewModelWithNullAuthProvider.SideBarTabItems.Add(mcpTab);

viewWithNullAuthProvider.DisableExtensionTabsWhenIDSDKNotInitialized();

Assert.IsTrue(assistantTab.IsEnabled);
Assert.IsTrue(mcpTab.IsEnabled);
}
finally
{
if (viewWithNullAuthProvider != null && viewWithNullAuthProvider.IsLoaded)
{
viewWithNullAuthProvider.Close();
}

if (viewModelWithNullAuthProvider != null)
{
var shutdownParams = new DynamoViewModel.ShutdownParams(shutdownHost: false, allowCancellation: false);
viewModelWithNullAuthProvider.PerformShutdownSequence(shutdownParams);
}
}
}
}
}
Loading