Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wizard error handling added and Rate link updated #2832

Merged
merged 8 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,12 @@ protected override void OnPageVisible(object sender, StatusbarEventArgs e)

ThreadHelper.JoinableTaskFactory.Run(async () =>
{
viewModel.WizardEventArgs.PickServerDatabaseDialog = this;
await wizardViewModel.Bll.ReverseEngineerCodeFirstAsync(null, viewModel.WizardEventArgs);
await InvokeWithErrorHandlingAsync(async () =>
{
viewModel.WizardEventArgs.PickServerDatabaseDialog = this;
await wizardViewModel.Bll.ReverseEngineerCodeFirstAsync(null, viewModel.WizardEventArgs);
return true;
});
});

foreach (var option in viewModel.WizardEventArgs.Configurations)
Expand Down
26 changes: 19 additions & 7 deletions src/GUI/EFCorePowerTools/Wizard/Wiz2_PickTablesDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,10 @@ protected override void OnPageVisible(object sender, StatusbarEventArgs e)
{
var viewModel = wizardViewModel;
IsPageLoaded = viewModel.IsPage2Initialized;
var isDataLoaded = wizardViewModel.ObjectTree.Types.Any();
var wea = viewModel.WizardEventArgs;
if (wea.Options.UiHint != viewModel.UiHint)
{
IsPageLoaded = false;
isDataLoaded = false;
wea.Options.UiHint = viewModel.UiHint;
wea.UserOptions.UiHint = viewModel.UiHint;
wea.Options.ConnectionString = viewModel.SelectedDatabaseConnection.ConnectionString;
Expand All @@ -64,21 +62,35 @@ protected override void OnPageVisible(object sender, StatusbarEventArgs e)

ThreadHelper.JoinableTaskFactory.Run(async () =>
{
var dbinfo = await RevEngWizardHandler.GetDatabaseInfoAsync(wea.Options);
wea.DbInfo = dbinfo;
await InvokeWithErrorHandlingAsync(async () =>
{
var dbinfo = await RevEngWizardHandler.GetDatabaseInfoAsync(wea.Options);
wea.DbInfo = dbinfo;
return true;
});
});
}

if (!IsPageLoaded && !isDataLoaded)
if (!IsPageLoaded && !wizardViewModel.ObjectTree.Types.Any())
{
wea.PickTablesDialog = this;

var isSuccessful = false;
ThreadHelper.JoinableTaskFactory.Run(async () =>
{
await wizardViewModel.Bll.LoadDataBaseObjectsAsync(wea.Options, wea.DbInfo, wea.NamingOptionsAndPath, wea);
NextButton.IsEnabled = true;
viewModel.ObjectTree.Types.Clear(); // Initialize to known state (empty)
isSuccessful = await InvokeWithErrorHandlingAsync(async () =>
{
return await wizardViewModel.Bll.LoadDataBaseObjectsAsync(wea.Options, wea.DbInfo, wea.NamingOptionsAndPath, wea);
});

NextButton.IsEnabled = isSuccessful;
});
}
else
{
NextButton.IsEnabled = true;
}
}

private void NextButton_Click(object sender, RoutedEventArgs e)
Expand Down
96 changes: 63 additions & 33 deletions src/GUI/EFCorePowerTools/Wizard/Wiz3_EfCoreModelDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,27 @@ protected override void OnPageVisible(object sender, StatusbarEventArgs e)
var wea = wizardViewModel.WizardEventArgs;
wea.ModelingOptionsDialog = this;

var isSuccessful = false;
ThreadHelper.JoinableTaskFactory.Run(async () =>
{
var neededPackages = await wea.Project.GetNeededPackagesAsync(wea.Options);
wea.Options.InstallNuGetPackage = neededPackages
.Exists(p => p.DatabaseTypes.Contains(wea.Options.DatabaseType) && !p.Installed);
isSuccessful = await InvokeWithErrorHandlingAsync(async () =>
{
var neededPackages = await wea.Project.GetNeededPackagesAsync(wea.Options);
wea.Options.InstallNuGetPackage = neededPackages
.Exists(p => p.DatabaseTypes.Contains(wea.Options.DatabaseType) && !p.Installed);

await wizardViewModel.Bll.GetModelOptionsAsync(wea.Options, wea.Project.Name, wea);
var result = await wizardViewModel.Bll.GetModelOptionsAsync(wea.Options, wea.Project.Name, wea);

if (wea.NewOptions)
{
// HACK Work around for issue with web app project system on initial run
wea.UserOptions = null;
}
if (wea.NewOptions)
{
// HACK Work around for issue with web app project system on initial run
wea.UserOptions = null;
}

return result;
});

NextButton.IsEnabled = true;
NextButton.IsEnabled = isSuccessful;
});

FirstTextBox.Focus();
Expand Down Expand Up @@ -118,49 +124,73 @@ private void GenerateFiles_Click(object sender, RoutedEventArgs e)

if (IsPageDirty)
{
var isSuccessful2 = false;
ThreadHelper.JoinableTaskFactory.Run(async () =>
{
isRunningAgain = true;
await wizardViewModel.Bll.GetModelOptionsAsync(wea.Options, wea.Project.Name, wea);
if (wea.NewOptions)
isSuccessful2 = await InvokeWithErrorHandlingAsync(async () =>
{
// HACK Work around for issue with web app project system on initial run
wea.UserOptions = null;
}
isRunningAgain = true;
var result = await wizardViewModel.Bll.GetModelOptionsAsync(wea.Options, wea.Project.Name, wea);
if (wea.NewOptions)
{
// HACK Work around for issue with web app project system on initial run
wea.UserOptions = null;
}

return result;
});

NextButton.IsEnabled = isSuccessful2;
});
}

wizardViewModel.GenerateStatus = string.Empty;
wizardViewModel.Bll.GetModelOptionsPostDialog(options, project.Name, wea, wizardViewModel.Model);
cancelButton.IsEnabled = false; // Once processed we can't cancel - only finish
NextButton.IsEnabled = true;
var errorMessage = string.Empty;

this.applyPresets(wizardViewModel.Model);

var isSuccessful = false;
ThreadHelper.JoinableTaskFactory.Run(async () =>
{
await wizardViewModel.Bll.SaveOptionsAsync(project, optionsPath, options, userOptions, new Tuple<List<Schema>, string>(options.CustomReplacers, namingOptionsAndPath.Item2));
isSuccessful = await InvokeWithErrorHandlingAsync(async () =>
{
await wizardViewModel.Bll.SaveOptionsAsync(project, optionsPath, options, userOptions, new Tuple<List<Schema>, string>(options.CustomReplacers, namingOptionsAndPath.Item2));

await RevEngWizardHandler.InstallNuGetPackagesAsync(project, onlyGenerate, options, forceEdit, wea);
await RevEngWizardHandler.InstallNuGetPackagesAsync(project, onlyGenerate, options, forceEdit, wea);

var neededPackages = await wea.Project.GetNeededPackagesAsync(wea.Options);
var missingProviderPackage = neededPackages.Find(p => p.DatabaseTypes.Contains(options.DatabaseType) && p.IsMainProviderPackage && !p.Installed)?.PackageId;
if (options.InstallNuGetPackage || options.SelectedToBeGenerated == 2)
{
missingProviderPackage = null;
}
var neededPackages = await wea.Project.GetNeededPackagesAsync(wea.Options);
var missingProviderPackage = neededPackages.Find(p => p.DatabaseTypes.Contains(options.DatabaseType) && p.IsMainProviderPackage && !p.Installed)?.PackageId;
if (options.InstallNuGetPackage || options.SelectedToBeGenerated == 2)
{
missingProviderPackage = null;
}

wea.ReverseEngineerStatus = await wizardViewModel.Bll.GenerateFilesAsync(project, options, missingProviderPackage, onlyGenerate, neededPackages, true);
wea.ReverseEngineerStatus = await wizardViewModel.Bll.GenerateFilesAsync(project, options, missingProviderPackage, onlyGenerate, neededPackages, true);

var postRunFile = Path.Combine(Path.GetDirectoryName(optionsPath), "efpt.postrun.cmd");
if (File.Exists(postRunFile))
{
Process.Start($"\"{postRunFile}\"");
}
var postRunFile = Path.Combine(Path.GetDirectoryName(optionsPath), "efpt.postrun.cmd");
if (File.Exists(postRunFile))
{
Process.Start($"\"{postRunFile}\"");
}

return true;
});

NextButton.IsEnabled = isSuccessful;
});

Statusbar.Status.ShowStatus();
wizardViewModel.GenerateStatus = wea.ReverseEngineerStatus;
if (string.IsNullOrEmpty(errorMessage))
{
Statusbar.Status.ShowStatus();
wizardViewModel.GenerateStatus = wea.ReverseEngineerStatus;
}
else
{
wizardViewModel.GenerateStatus = $"❌ {errorMessage}";
}

Telemetry.TrackEvent("PowerTools.ReverseEngineer");
}
Expand Down Expand Up @@ -210,7 +240,7 @@ private void OpenBrowserHelp(object sender, RoutedEventArgs e)

private void OpenBrowserRate(object sender, RoutedEventArgs e)
{
OpenBrowserWithLink("https://marketplace.visualstudio.com/items?itemName=ErikEJ.EFCorePowerTools&amp;ssr=false#review-details");
OpenBrowserWithLink("https://marketplace.visualstudio.com/items?itemName=ErikEJ.EFCorePowerTools&ssr=false#review-details");
}
}
}
19 changes: 10 additions & 9 deletions src/GUI/EFCorePowerTools/Wizard/Wiz4_StatusDialog.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
KeepAlive="True"
WindowTitle="{x:Static locale:ReverseEngineerLocale.ChooseDatabaseConnection}">


<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding Page4LoadedCommand}" />
Expand All @@ -38,20 +39,20 @@
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" >Reverse Engineer Status</Label>
<TextBox Grid.Row="1"
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" >Reverse Engineer Status</Label>
<TextBox Grid.Row="1"
Padding="5" Margin="5"
TextChanged="TextChangedEventHandler"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto"
Text="{Binding GenerateStatus, Mode=TwoWay}">
</TextBox>
</Grid>
</TextBox>
</Grid>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" >
<Button Style="{StaticResource NavButton}" Content="{x:Static locale:ReverseEngineerLocale.NavigationPrevious}" x:Name="PreviousButton" Click="BackButton_Click" />
<Button Style="{StaticResource NavButton}" Content="{x:Static locale:ReverseEngineerLocale.NavigationNext}" IsEnabled="False"/>
Expand Down
9 changes: 9 additions & 0 deletions src/GUI/EFCorePowerTools/Wizard/Wiz4_StatusDialog.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ protected override void OnPageVisible(object sender, StatusbarEventArgs e)
{
IsPageLoaded = wizardViewModel.IsPage4Initialized;

if (wizardViewModel.ErrorMessage != null)
{
wizardViewModel.GenerateStatus = wizardViewModel.ErrorMessage;
Statusbar.Status.ShowStatusError("Error occurred");
PreviousButton.IsEnabled = false;
FinishButton.IsEnabled = true;
return;
}

if (!IsPageLoaded)
{
// When generating we'll initialize the page to known state
Expand Down
1 change: 1 addition & 0 deletions src/GUI/EFCorePowerTools/Wizard/WizardDialogBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public WizardDialogBox(IReverseEngineerBll bll, EventArgs e, IWizardViewModel vi

if (e is WizardEventArgs wizardArgs)
{
wizardArgs.IsInvokedByWizard = true;
wizardViewModel.WizardEventArgs = wizardArgs;
wizardViewModel.UiHint = wizardArgs.UiHint;
wizardViewModel.Filename = wizardArgs.Filename;
Expand Down
19 changes: 18 additions & 1 deletion src/GUI/EFCorePowerTools/Wizard/WizardResultPageFunction.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Diagnostics;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Navigation;
using EFCorePowerTools.Contracts.Wizard;
Expand All @@ -21,6 +23,21 @@ public class WizardResultPageFunction : PageFunction<WizardResult>
protected IMessenger Messenger { get; set; }
public bool IsPageLoaded { get; set; }

public async Task<bool> InvokeWithErrorHandlingAsync(Func<Task<bool>> callbackAsync)
{
if (!await callbackAsync())
{
var viewModel = (WizardDataViewModel)DataContext;
var wizardPage4 = new Wiz4_StatusDialog(viewModel, wizardView);
wizardPage4.Return += WizardPage_Return;
NavigationService?.Navigate(wizardPage4);
viewModel.ErrorMessage = viewModel.WizardEventArgs.StatusbarMessage;
return false;
}

return true;
}

#pragma warning disable SA1201 // Elements should appear in the correct order
public WizardResultPageFunction(WizardDataViewModel wizardViewModel, IWizardView wizardView)
#pragma warning restore SA1201 // Elements should appear in the correct order
Expand Down
13 changes: 11 additions & 2 deletions src/GUI/Shared/Handlers/ReverseEngineer/RevEngWizardHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,8 @@ await VS.MessageBox.ShowAsync(
Telemetry.TrackFrameworkUse(nameof(ReverseEngineerHandler), options.CodeGenerationMode);
Telemetry.TrackEngineUse(options.DatabaseType, revEngResult.DatabaseEdition, revEngResult.DatabaseVersion, revEngResult.DatabaseLevel, revEngResult.DatabaseEditionId);

return statusMessage.ToString();
var messageForStatusPage = statusMessage.ToString();
return string.IsNullOrEmpty(messageForStatusPage) ? "Successfully completed" : messageForStatusPage;
}

private static async Task<List<TableModel>> GetDacpacTablesAsync(string dacpacPath, CodeGenerationMode codeGenerationMode)
Expand Down Expand Up @@ -770,7 +771,15 @@ public async Task<bool> LoadDataBaseObjectsAsync(ReverseEngineerOptions options,
}
catch (InvalidOperationException ex)
{
VSHelper.ShowError($"{ex.Message}");
if (wizardArgs.IsInvokedByWizard)
{
wizardArgs.StatusbarMessage = ex.Message;
}
else
{
VSHelper.ShowError($"{ex.Message}");
}

return false;
}
finally
Expand Down
2 changes: 2 additions & 0 deletions src/GUI/Shared/ViewModels/WizardDataViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -707,5 +707,7 @@ public string GenerateStatus
this.RaisePropertyChanged("GenerateStatus");
}
}

public string ErrorMessage { get; internal set; }
}
}