diff --git a/src/DynamoCoreWpf/Extensions/ViewLoadedParams.cs b/src/DynamoCoreWpf/Extensions/ViewLoadedParams.cs
index 3acd33c21b5..7155ebfbf93 100644
--- a/src/DynamoCoreWpf/Extensions/ViewLoadedParams.cs
+++ b/src/DynamoCoreWpf/Extensions/ViewLoadedParams.cs
@@ -86,6 +86,15 @@ internal ViewLoadedParams(DynamoView dynamoV, DynamoViewModel dynamoVM) :
DynamoSelection.Instance.Selection.CollectionChanged += OnSelectionCollectionChanged;
}
+ ///
+ /// Indicates whether Autodesk Identity (IDSDK) is currently initialized. View extensions
+ /// that depend on Autodesk Identity (e.g. sign-in, Autodesk Assistant) can use this to keep
+ /// their own UI (buttons, panels) in sync with Dynamo's IDSDK gating, without duplicating
+ /// the native initialization check or triggering the warning dialog Dynamo shows on its own
+ /// sign-in path.
+ ///
+ public bool IsIDSDKInitialized => dynamoViewModel.IsIDSDKInitialized(showWarning: false);
+
///
/// Adds a menu item to the extensions menu
/// Items will be ordered alphabetically
@@ -114,16 +123,19 @@ public void AddExtensionMenuItem(MenuItem menuItem)
///
public void AddToExtensionsSideBar(IViewExtension viewExtension, ContentControl contentControl)
{
- bool added = dynamoView.AddOrFocusExtensionControl(viewExtension, contentControl);
+ var result = dynamoView.AddOrFocusExtensionControl(viewExtension, contentControl);
- if (added)
+ switch (result)
{
- dynamoViewModel.Model.Logger.Log($"{viewExtension.Name} : {Wpf.Properties.Resources.ExtensionAdded}");
- }
- else
- {
- dynamoViewModel.Model.Logger.Log($"{viewExtension.Name} : {Wpf.Properties.Resources.ExtensionAlreadyPresent}");
-
+ case DynamoView.ExtensionControlResult.Added:
+ dynamoViewModel.Model.Logger.Log($"{viewExtension.Name} : {Wpf.Properties.Resources.ExtensionAdded}");
+ break;
+ case DynamoView.ExtensionControlResult.AlreadyPresent:
+ dynamoViewModel.Model.Logger.Log($"{viewExtension.Name} : {Wpf.Properties.Resources.ExtensionAlreadyPresent}");
+ break;
+ case DynamoView.ExtensionControlResult.Blocked:
+ // Already logged by DisableExtensionWhenNoNetworkMode/DisableExtensionWhenIDSDKNotInitialized.
+ break;
}
}
diff --git a/src/DynamoCoreWpf/PublicAPI.Unshipped.txt b/src/DynamoCoreWpf/PublicAPI.Unshipped.txt
index f3201d6cf42..90409bffdaf 100644
--- a/src/DynamoCoreWpf/PublicAPI.Unshipped.txt
+++ b/src/DynamoCoreWpf/PublicAPI.Unshipped.txt
@@ -1,3 +1,4 @@
+Dynamo.Wpf.Extensions.ViewLoadedParams.IsIDSDKInitialized.get -> bool
Dynamo.Controls.NetworkStatusIconConverter
Dynamo.Controls.NetworkStatusIconConverter.Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) -> object
Dynamo.Controls.NetworkStatusIconConverter.ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) -> object
diff --git a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs
index 6f228b05de3..49a7e8df0bd 100644
--- a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs
+++ b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs
@@ -528,15 +528,29 @@ private void OnPythonEngineUpgradeToastRequested(string msg, bool stayOpen, stri
}));
}
+ ///
+ /// Result of , distinguishing a genuinely blocked
+ /// extension (NoNetworkMode/IDSDK) from one that was simply already open.
+ ///
+ internal enum ExtensionControlResult
+ {
+ Added,
+ AlreadyPresent,
+ Blocked
+ }
+
///
/// Adds an extension control or if it already exists it makes sure it is focused.
/// The control may be added as a window or a tab in the extension bar depending on settings.
///
/// View extension adding the content
/// Control being added
- /// True if the control was added, false if it already existed
- internal bool AddOrFocusExtensionControl(IViewExtension viewExtension, UIElement content)
+ internal ExtensionControlResult AddOrFocusExtensionControl(IViewExtension viewExtension, UIElement content)
{
+ if (DisableExtensionWhenNoNetworkMode(viewExtension.UniqueId, viewExtension.Name, "opened") ||
+ DisableExtensionWhenIDSDKNotInitialized(viewExtension.UniqueId, viewExtension.Name, "opened"))
+ return ExtensionControlResult.Blocked;
+
var window = ExtensionWindows.ContainsKey(viewExtension.Name) ? ExtensionWindows[viewExtension.Name] : null;
var tab = FindExtensionTab(viewExtension);
var addExtensionControl = window == null && tab == null;
@@ -589,7 +603,7 @@ internal bool AddOrFocusExtensionControl(IViewExtension viewExtension, UIElement
}
}
- return addExtensionControl;
+ return addExtensionControl ? ExtensionControlResult.Added : ExtensionControlResult.AlreadyPresent;
}
private ExtensionWindow AddExtensionWindow(IViewExtension viewExtension, UIElement content, WindowSettings windowSettings)
@@ -1414,8 +1428,18 @@ private void DynamoLoadedViewExtensionHandler(ViewLoadedParams loadedParams, IEn
continue;
}
+ // The extension is still allowed to run Loaded() below, so any UI it registers
+ // (menu items, toolbar buttons) stays visible; only the automatic re-open of a
+ // previously-open panel is skipped. Extensions that depend on IDSDK are expected to
+ // gate their own entry points via ViewLoadedParams.IsIDSDKInitialized.
+ var idsdkNotInitialized = DisableExtensionWhenIDSDKNotInitialized(ext.UniqueId, ext.Name, "re-opened");
+
ext.Loaded(loadedParams);
- ReOpenSavedExtensionOnDynamoStartup(ext);
+
+ if (!idsdkNotInitialized)
+ {
+ ReOpenSavedExtensionOnDynamoStartup(ext);
+ }
}
catch (Exception exc)
{
@@ -3414,5 +3438,24 @@ internal bool DisableExtensionWhenNoNetworkMode(string extensionId, string exten
return false;
}
+
+ ///
+ /// Prevents the Autodesk Assistant and MCP View extensions from being loaded or opened when
+ /// Autodesk Identity (IDSDK) is not initialized, so the native "Create Assistant" call chain
+ /// that requires Identity never fires and cannot cascade into a series of error dialogs.
+ ///
+ internal bool DisableExtensionWhenIDSDKNotInitialized(string extensionId, string extensionName, string action)
+ {
+ if ((string.Equals(extensionId, AutodeskAssistantExtensionId, StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(extensionId, McpViewExtensionId, StringComparison.OrdinalIgnoreCase)) &&
+ !dynamoViewModel.IsIDSDKInitialized(showWarning: false))
+ {
+ Log($"Package/Extension {extensionName} not {action} because Autodesk Identity (IDSDK) is not initialized");
+
+ return true;
+ }
+
+ return false;
+ }
}
}
diff --git a/test/DynamoCoreWpf2Tests/ViewExtensions/ViewExtensionTests.cs b/test/DynamoCoreWpf2Tests/ViewExtensions/ViewExtensionTests.cs
index 671b8ede44a..b2adbbc6ec7 100644
--- a/test/DynamoCoreWpf2Tests/ViewExtensions/ViewExtensionTests.cs
+++ b/test/DynamoCoreWpf2Tests/ViewExtensions/ViewExtensionTests.cs
@@ -4,6 +4,7 @@
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
+using Dynamo.Controls;
using Dynamo.Engine;
using Dynamo.Graph.Workspaces;
using Dynamo.Models;
@@ -410,7 +411,7 @@ public void LaunchTourClosesSidePanelViewExtensions()
var dockedExtension = new GuidedTourSidePanelTestViewExtension();
var added = View.AddOrFocusExtensionControl(dockedExtension, new UserControl());
- Assert.IsTrue(added);
+ Assert.AreEqual(DynamoView.ExtensionControlResult.Added, added);
var hasAddedExtensionTab = ViewModel.SideBarTabItems.OfType().Any(tab =>
tab.Tag is IViewExtension extension &&
diff --git a/test/DynamoCoreWpfTests/DynamoViewNoNetworkModeTests.cs b/test/DynamoCoreWpfTests/DynamoViewNoNetworkModeTests.cs
index 8ee1ff19d87..8f44cd63145 100644
--- a/test/DynamoCoreWpfTests/DynamoViewNoNetworkModeTests.cs
+++ b/test/DynamoCoreWpfTests/DynamoViewNoNetworkModeTests.cs
@@ -1,6 +1,9 @@
+using System;
+using System.Linq;
using Dynamo.Controls;
using Dynamo.Models;
using Dynamo.ViewModels;
+using Dynamo.Wpf.Extensions;
using NUnit.Framework;
using TestServices;
@@ -100,5 +103,38 @@ public void UnrecognizedExtensionIsNotDisabledWhenNoNetworkModeIsEnabled()
Assert.IsFalse(shouldDisable);
}
+
+ [Test]
+ public void AssistantTabCannotBeAddedViaSideBarWhenNoNetworkModeIsEnabled()
+ {
+ // Simulates the code path where an extension calls AddToExtensionsSideBar() after
+ // initial load (e.g. from IExtensionStorageAccess.WorkspaceOpened), which bypasses
+ // the DisableExtensionWhenNoNetworkMode guard in DynamoLoadedViewExtensionHandler.
+ // AddOrFocusExtensionControl must block these late attempts in NoNetworkMode.
+ //
+ // This is specifically exercising NoNetworkMode, not the IDSDK gate: the fixture's
+ // DynamoModel has no AuthProvider configured, so AuthenticationManager.IsIDSDKInitialized()
+ // is unconditionally true (see AuthenticationManager.IsIDSDKInitialized) and can't be
+ // the reason AddOrFocusExtensionControl returns Blocked here.
+ var stubExtension = new StubViewExtension(DynamoView.AutodeskAssistantExtensionId);
+ var result = View.AddOrFocusExtensionControl(stubExtension, null);
+
+ Assert.AreEqual(DynamoView.ExtensionControlResult.Blocked, result);
+ Assert.IsFalse(ViewModel.SideBarTabItems
+ .OfType()
+ .Any(t => string.Equals(t.Uid, DynamoView.AutodeskAssistantExtensionId,
+ StringComparison.OrdinalIgnoreCase)));
+ }
+
+ private class StubViewExtension : IViewExtension
+ {
+ public StubViewExtension(string uniqueId) { UniqueId = uniqueId; }
+ public string UniqueId { get; }
+ public string Name => "Stub";
+ public void Startup(ViewStartupParams p) { }
+ public void Loaded(ViewLoadedParams p) { }
+ public void Shutdown() { }
+ public void Dispose() { }
+ }
}
}