Skip to content

Commit

Permalink
DYN-7268 Improve UX when IDSDK is not installed on system running Dyn…
Browse files Browse the repository at this point in the history
…amo #2 (#15799)
  • Loading branch information
zeusongit authored Feb 6, 2025
1 parent 41d8912 commit ec3ad20
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 70 deletions.
15 changes: 15 additions & 0 deletions src/DynamoCore/Core/AuthenticationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,20 @@ private void OnLoginStateChanged(LoginState status)
}
}

/// <summary>
/// Returns whether the IDSDK is initialized or not for Dynamo Sandbox, in host environment defaults to true.
/// </summary>
internal bool IsIDSDKInitialized()
{
if (authProvider is IDSDKManager idsdkProvider)
{
if (!idsdkProvider.IsIDSDKInitialized)
{
return false;
}
}
return true;
}

}
}
32 changes: 13 additions & 19 deletions src/DynamoCore/Core/IDSDKManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,27 @@ public class IDSDKManager : IOAuth2AuthProvider, IOAuth2AccessTokenProvider, IOA
public event Action<LoginState> LoginStateChanged;

/// <summary>
/// The event is fired when IDSDK initialization fails
/// </summary>
internal event EventHandler ErrorInitializingIDSDK;

/// <summary>
/// The flag is used to prevent multiple error messages from being shown, since initialization error can be thrown multiple times.
/// Returns the login status of the current session.
/// </summary>
internal bool isErrorInitializingMsgShown;
private void OnErrorInitializingIDSDK()
/// <returns>LoginState Enum value</returns>
public LoginState LoginState
{
ErrorInitializingIDSDK?.Invoke(this, EventArgs.Empty);
get
{
var result = IDSDK_IsLoggedIn();
return result ? LoginState.LoggedIn : LoginState.LoggedOut;
}
}

/// <summary>
/// Returns the login status of the current session.
/// Returns the status of IDSDK installation, will return false if IDSDK fails to initialize.
/// </summary>
/// <returns>LoginState Enum value</returns>
public LoginState LoginState
public bool IsIDSDKInitialized
{
get
{
var result = IDSDK_IsLoggedIn();
return result ? LoginState.LoggedIn : LoginState.LoggedOut;
return Initialize();
}
}

Expand Down Expand Up @@ -167,7 +165,7 @@ private bool IDSDK_Login()
}
else
{
if (Initialize())
if (IsIDSDKInitialized)
{
idsdk_status_code statusCode = Client.Login();
if (Client.IsSuccess(statusCode))
Expand All @@ -180,7 +178,7 @@ private bool IDSDK_Login()
}
private bool IDSDK_IsLoggedIn()
{
if (Initialize())
if (IsIDSDKInitialized)
{
bool ret = Client.IsLoggedIn();
return ret;
Expand Down Expand Up @@ -244,7 +242,6 @@ private bool Initialize()
{
if (Client.IsInitialized())
{
isErrorInitializingMsgShown = false;
return true;
}

Expand All @@ -264,7 +261,6 @@ private bool Initialize()
Client.LoginCompleteEvent += AuthCompleteEventHandler;
ret = SetProductConfigs(Configurations.DynamoAsString, server, client_id);
Client.SetServer(server);
isErrorInitializingMsgShown = false;
return ret;
}
}
Expand All @@ -274,8 +270,6 @@ private bool Initialize()
{
DynamoConsoleLogger.OnLogMessageToDynamoConsole("An error occurred while initializing Auth Service (IDSDK).");
}

OnErrorInitializingIDSDK();
return false;
}
private bool Deinitialize()
Expand Down
1 change: 1 addition & 0 deletions src/DynamoCore/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ Dynamo.Core.IDSDKManager
Dynamo.Core.IDSDKManager.Dispose() -> void
Dynamo.Core.IDSDKManager.GetAccessToken() -> string
Dynamo.Core.IDSDKManager.IDSDKManager() -> void
Dynamo.Core.IDSDKManager.IsIDSDKInitialized.get -> bool
Dynamo.Core.IDSDKManager.IsLoggedIn() -> bool
Dynamo.Core.IDSDKManager.Login() -> bool
Dynamo.Core.IDSDKManager.LoginState.get -> Greg.AuthProviders.LoginState
Expand Down
2 changes: 2 additions & 0 deletions src/DynamoCoreWpf/Controls/ShortcutToolbar.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ private void exportMenu_MouseLeave(object sender, System.Windows.Input.MouseEven

private void LoginButton_OnClick(object sender, RoutedEventArgs e)
{
if(!DynamoViewModel.IsIDSDKInitialized()) return;
if (authManager.LoginState == LoginState.LoggedIn)
{
var button = (Button)sender;
Expand All @@ -149,6 +150,7 @@ private void LoginButton_OnClick(object sender, RoutedEventArgs e)

private void LogoutOption_Click(object sender, RoutedEventArgs e)
{
if (!DynamoViewModel.IsIDSDKInitialized()) return;
if (authManager.LoginState == LoginState.LoggedIn)
{
var result = Wpf.Utilities.MessageBoxService.Show(Application.Current?.MainWindow, Wpf.Properties.Resources.SignOutConfirmationDialogText, Wpf.Properties.Resources.SignOutConfirmationDialogTitle,MessageBoxButton.OKCancel, new List<string>() { "Sign Out", "Cancel"}, MessageBoxImage.Information);
Expand Down
29 changes: 13 additions & 16 deletions src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -863,10 +863,7 @@ protected DynamoViewModel(StartConfiguration startConfiguration)

FileTrustViewModel = new FileTrustWarningViewModel();
MLDataPipelineExtension = model.ExtensionManager.Extensions.OfType<DynamoMLDataPipelineExtension>().FirstOrDefault();
if (Model.AuthenticationManager?.AuthProvider is IDSDKManager idsdkProvider)
{
idsdkProvider.ErrorInitializingIDSDK += OnErrorInitializingIDSDK;
}
IsIDSDKInitialized();
}

private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
Expand Down Expand Up @@ -1088,18 +1085,22 @@ internal void OnNodeViewReady(object nodeView)
}

/// <summary>
/// The event handler for cases when IDSDK fails to initialize, probably because of missing Adsk Identity Manager.
/// A flag is used to show the error message only once per session.
/// Returns whether the IDSDK is initialized or not for Dynamo Sandbox, in host environment defaults to true.
/// If showWarning is true, a warning message will be shown to the user if the IDSDK is not initialized.
/// If owner is not null, the warning message will be shown as a dialog with the owner as the parent.
/// </summary>
private void OnErrorInitializingIDSDK(object sender, EventArgs e)
internal bool IsIDSDKInitialized(bool showWarning = true, Window owner = null)
{
if (Model.AuthenticationManager?.AuthProvider is IDSDKManager idsdkProvider)
if (!Model.AuthenticationManager.IsIDSDKInitialized())
{
if (idsdkProvider.isErrorInitializingMsgShown) return;

DynamoMessageBox.Show(Owner, WpfResources.IDSDKErrorMessage, WpfResources.IDSDKErrorMessageTitle, true, MessageBoxButton.OK, MessageBoxImage.Information);
idsdkProvider.isErrorInitializingMsgShown = true;
if (showWarning)
{
var ownerWindow = owner ?? Owner ?? System.Windows.Application.Current.MainWindow;
DynamoMessageBox.Show(ownerWindow, WpfResources.IDSDKErrorMessage, WpfResources.IDSDKErrorMessageTitle, true, MessageBoxButton.OK, MessageBoxImage.Information);
}
return false;
}
return true;
}

#region Event handler destroy/create
Expand All @@ -1123,10 +1124,6 @@ protected virtual void UnsubscribeAllEvents()

DynamoSelection.Instance.Selection.CollectionChanged -= SelectionOnCollectionChanged;
UsageReportingManager.Instance.PropertyChanged -= CollectInfoManager_PropertyChanged;
if (Model.AuthenticationManager?.AuthProvider is IDSDKManager idsdkProvider)
{
idsdkProvider.ErrorInitializingIDSDK -= OnErrorInitializingIDSDK;
}
}

private void InitializeRecentFiles()
Expand Down
11 changes: 9 additions & 2 deletions src/DynamoCoreWpf/ViewModels/Core/PortViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -502,8 +502,15 @@ private void AutoCompleteCluster(object parameter)

if (wsViewModel.DynamoViewModel.IsDNAClusterPlacementEnabled)
{
MLNodeClusterAutoCompletionResponse results = wsViewModel.NodeAutoCompleteSearchViewModel.GetMLNodeClusterAutocompleteResults();
wsViewModel.OnRequestNodeAutoCompleteViewExtension(results);
try
{
MLNodeClusterAutoCompletionResponse results = wsViewModel.NodeAutoCompleteSearchViewModel.GetMLNodeClusterAutocompleteResults();
wsViewModel.OnRequestNodeAutoCompleteViewExtension(results);
}
catch (Exception e)
{
// Log the exception and show a notification to the user
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ internal PackageManagerClientViewModel(DynamoViewModel dynamoViewModel, PackageM

private void ToggleLoginState()
{
if(!this.DynamoViewModel.IsIDSDKInitialized()) return;
if (AuthenticationManager.LoginState == LoginState.LoggedIn)
{
AuthenticationManager.Logout();
Expand All @@ -301,6 +302,7 @@ private bool CanToggleLoginState()

public void PublishCurrentWorkspace(object m)
{
if (!this.DynamoViewModel.IsIDSDKInitialized(true, ViewModelOwner)) return;
var ws = (CustomNodeWorkspaceModel)DynamoViewModel.CurrentSpace;

CustomNodeDefinition currentFunDef;
Expand Down Expand Up @@ -346,6 +348,7 @@ public bool CanPublishCurrentWorkspace(object m)

public void PublishNewPackage(object m)
{
if (!this.DynamoViewModel.IsIDSDKInitialized(true, ViewModelOwner)) return;
var termsOfUseCheck = new TermsOfUseHelper(new TermsOfUseHelperParams
{
PackageManagerClient = Model,
Expand All @@ -365,6 +368,7 @@ public bool CanPublishNewPackage(object m)

public void PublishCustomNode(Function m)
{
if (!this.DynamoViewModel.IsIDSDKInitialized(true, ViewModelOwner)) return;
CustomNodeInfo currentFunInfo;
if (DynamoViewModel.Model.CustomNodeManager.TryGetNodeInfo(
m.Definition.FunctionId,
Expand Down Expand Up @@ -394,6 +398,7 @@ public bool CanPublishCustomNode(Function m)

public void PublishSelectedNodes(object m)
{
if (!this.DynamoViewModel.IsIDSDKInitialized(true, ViewModelOwner)) return;
var nodeList = DynamoSelection.Instance.Selection
.Where(x => x is Function)
.Cast<Function>()
Expand Down Expand Up @@ -453,12 +458,14 @@ public bool CanPublishSelectedNodes(object m)

private void ShowNodePublishInfo()
{
if (!this.DynamoViewModel.IsIDSDKInitialized(true, ViewModelOwner)) return;
var newPkgVm = new PublishPackageViewModel(DynamoViewModel);
DynamoViewModel.OnRequestPackagePublishDialog(newPkgVm);
}

private void ShowNodePublishInfo(ICollection<Tuple<CustomNodeInfo, CustomNodeDefinition>> funcDefs)
{
if (!this.DynamoViewModel.IsIDSDKInitialized(true, ViewModelOwner)) return;
foreach (var f in funcDefs)
{
var pkg = PackageManagerExtension.PackageLoader.GetOwnerPackage(f.Item1);
Expand Down Expand Up @@ -513,6 +520,7 @@ public List<PackageManagerSearchElement> ListAll()
/// <returns></returns>
public List<PackageManagerSearchElement> GetInfectedPackages()
{
if (!this.DynamoViewModel.IsIDSDKInitialized(true, ViewModelOwner)) return null;
InfectedPackageList = new List<PackageManagerSearchElement>();
var latestPkgs = Model.GetUsersLatestPackages();
if (latestPkgs != null && latestPkgs.maintains?.Count > 0)
Expand All @@ -537,6 +545,7 @@ public List<PackageManagerSearchElement> GetInfectedPackages()
public void DownloadAndInstallPackage(IPackageInfo packageInfo, string downloadPath = null)
{
// User needs to accept terms of use before any packages can be downloaded from package manager
if (!this.DynamoViewModel.IsIDSDKInitialized(true, ViewModelOwner)) return;
var prefSettings = DynamoViewModel.Model.PreferenceSettings;
var touAccepted = prefSettings.PackageDownloadTouAccepted;
if (!touAccepted)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ private void PublishNewPackage()

private void ExecuteWithTou(Action acceptanceCallback)
{
if (!dynamoViewModel.IsIDSDKInitialized(true, packageManagerClientViewModel.ViewModelOwner)) return;
// create TermsOfUseHelper object to check asynchronously whether the Terms of Use has
// been accepted, and if so, continue to execute the provided Action.
var termsOfUseCheck = new TermsOfUseHelper(new TermsOfUseHelperParams
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2277,6 +2277,7 @@ private void AddDllFile(string filename)
/// Delegate used to submit the publish online request</summary>
private void Submit()
{
if (!dynamoViewModel.IsIDSDKInitialized(true, Owner)) return;
MessageBoxResult response = DynamoModel.IsTestMode ? MessageBoxResult.OK : MessageBoxService.Show(Owner, Resources.PrePackagePublishMessage, Resources.PrePackagePublishTitle, MessageBoxButton.OKCancel, MessageBoxImage.Information);
if (response == MessageBoxResult.Cancel)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,11 +429,15 @@ internal void ShowNodeAutocompleMLResults()
private MLNodeAutoCompletionResponse GetMLNodeAutocompleteResults(string requestJSON)
{
MLNodeAutoCompletionResponse results = null;
var authProvider = dynamoViewModel.Model.AuthenticationManager.AuthProvider;

if (authProvider is IOAuth2AuthProvider oauth2AuthProvider && authProvider is IOAuth2AccessTokenProvider tokenprovider)
try
{
try
var authProvider = dynamoViewModel.Model.AuthenticationManager.AuthProvider;
if (!dynamoViewModel.IsIDSDKInitialized())
{
throw new Exception("IDSDK missing or failed initialization.");
}

if (authProvider is IOAuth2AuthProvider oauth2AuthProvider && authProvider is IOAuth2AccessTokenProvider tokenprovider)
{
var uri = DynamoUtilities.PathHelper.GetServiceBackendAddress(this, nodeAutocompleteMLEndpoint);
var client = new RestClient(uri);
Expand All @@ -450,11 +454,11 @@ private MLNodeAutoCompletionResponse GetMLNodeAutocompleteResults(string request
//TODO maybe worth moving to system.text json in phases?
results = JsonConvert.DeserializeObject<MLNodeAutoCompletionResponse>(response.Content);
}
catch (Exception ex)
{
dynamoViewModel.Model.Logger.Log(ex.Message);
throw new Exception("Authentication failed.");
}
}
catch (Exception ex)
{
dynamoViewModel.Model.Logger.Log(ex.Message);
throw new Exception("Authentication failed.");
}

return results;
Expand All @@ -464,37 +468,48 @@ private MLNodeAutoCompletionResponse GetMLNodeAutocompleteResults(string request
internal MLNodeClusterAutoCompletionResponse GetMLNodeClusterAutocompleteResults()
{
MLNodeClusterAutoCompletionResponse results = null;
try
{
var MLRequest = GenerateRequestForMLAutocomplete();
string jsonRequest = JsonConvert.SerializeObject(MLRequest);

var MLRequest = GenerateRequestForMLAutocomplete();
string jsonRequest = JsonConvert.SerializeObject(MLRequest);

var authProvider = dynamoViewModel.Model.AuthenticationManager.AuthProvider;
var authProvider = dynamoViewModel.Model.AuthenticationManager.AuthProvider;
if (!dynamoViewModel.IsIDSDKInitialized())
{
throw new Exception("IDSDK missing or failed initialization.");
}

if (authProvider is IOAuth2AuthProvider oauth2AuthProvider && authProvider is IOAuth2AccessTokenProvider tokenprovider)
{
try
if (authProvider is IOAuth2AuthProvider oauth2AuthProvider && authProvider is IOAuth2AccessTokenProvider tokenprovider)
{
var uri = DynamoUtilities.PathHelper.GetServiceBackendAddress(this, nodeClusterAutocompleteMLEndpoint);
var client = new RestClient(uri);
var request = new RestRequest(string.Empty, Method.Post);
var tkn = tokenprovider?.GetAccessToken();
if (string.IsNullOrEmpty(tkn))
try
{
throw new Exception("Authentication required.");
}
request.AddHeader("Authorization", $"Bearer {tkn}");
request = request.AddJsonBody(jsonRequest);
request.RequestFormat = DataFormat.Json;
RestResponse response = client.Execute(request);
var uri = DynamoUtilities.PathHelper.GetServiceBackendAddress(this, nodeClusterAutocompleteMLEndpoint);
var client = new RestClient(uri);
var request = new RestRequest(string.Empty, Method.Post);
var tkn = tokenprovider?.GetAccessToken();
if (string.IsNullOrEmpty(tkn))

Check notice on line 490 in src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs

View check run for this annotation

DynamoDS Chorus / security/gitleaks

http-header-authorization

HTTP Header Authorization: possible secret committed to source code

Check notice on line 490 in src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs

View check run for this annotation

DynamoDS Chorus / security/gitleaks

http-header-authorization

HTTP Header Authorization: possible secret committed to source code
{
throw new Exception("Authentication required.");
}
request.AddHeader("Authorization", $"Bearer {tkn}");
request = request.AddJsonBody(jsonRequest);
request.RequestFormat = DataFormat.Json;
RestResponse response = client.Execute(request);

results = JsonConvert.DeserializeObject<MLNodeClusterAutoCompletionResponse>(response.Content);
}
catch (Exception ex)
{
dynamoViewModel.Model.Logger.Log(ex.Message);
throw new Exception("Authentication failed.");
results = JsonConvert.DeserializeObject<MLNodeClusterAutoCompletionResponse>(response.Content);
}
catch (Exception ex)
{
dynamoViewModel.Model.Logger.Log(ex.Message);
throw new Exception("Authentication failed.");
}
}
}
catch (Exception ex)
{
dynamoViewModel.Model.Logger.Log(ex.Message);
throw new Exception("Authentication failed.");
}

return results;
}
Expand Down

0 comments on commit ec3ad20

Please sign in to comment.