Skip to content

Commit

Permalink
Merge searching into main. (#2443)
Browse files Browse the repository at this point in the history
* Adding searching capability to the repo tool (#2245)

* Re-adding lost changes

* WIP

* Minor tweaks

* Cleaning up code.

* Fixing code issues with new()

* Reverting SDK version.

* Reverting idl change because it is another PR.

* Reverting package.appxmanifest change

* Adding search term placeholder text

* Removing a method.  Using GetValuesFor

* Removing a space

* Moving QI to where it is used

---------

Co-authored-by: Darren Hoehna <[email protected]>

* Comment changes. (#2310)

* Re-adding lost changes

* WIP

* Minor tweaks

* Cleaning up code.

* Fixing code issues with new()

* Reverting SDK version.

* Reverting idl change because it is another PR.

* Reverting package.appxmanifest change

* Adding search term placeholder text

* Removing a method.  Using GetValuesFor

* Removing a space

* Moving QI to where it is used

* Comment changes

---------

Co-authored-by: Darren Hoehna <[email protected]>

* FIxing some errors.  Making the UI closer to the mocks> (#2326)

Co-authored-by: Darren Hoehna <[email protected]>

* addRepo improvements (#2298)

* USing tags

* Can clone repos again.

* Changing visibility to bool.

* More changes

* Account combobox is reset.

* Adding some comments.

* Combobox placeholder

* Final touches

* Fixing a comment.

* Fixing SDk version

* Ignoring a test

* Update tools/SetupFlow/DevHome.SetupFlow/ViewModels/AddRepoViewModel.cs

Co-authored-by: Kristen Schau <[email protected]>

* Update tools/SetupFlow/DevHome.SetupFlow/ViewModels/AddRepoViewModel.cs

Co-authored-by: Kristen Schau <[email protected]>

* Update tools/SetupFlow/DevHome.SetupFlow/Views/AddRepoDialog.xaml

Co-authored-by: Kristen Schau <[email protected]>

* Changes

* Removing prefixes for uid

* Moving more things into the ViewModel.

* Getting loginUI and provider name not null.

* Ignoring anotehr test because making a new frame throws an exception.

* Adding -async

---------

Co-authored-by: Darren Hoehna <[email protected]>
Co-authored-by: Kristen Schau <[email protected]>

* Enabling Search inputs with IRepositoryProvider (#2244)

* Adding IRepositoryProvider2

* Adding a space between the >'s

* Modifying based on feedback.

* Moving around arguments

* Changes based on semi-API review

* Adding implementation

* HOlding onto the options

* Copying a com array

* Changing a name

* Back to a working build.

* WIP

* eeeyyy, it works.  Now need to add some smaller changes

* Cleaning up code

* Works and looks good

* Adding comments

* Fixing a typo

* Adding locks.  Getting search to work with one provider

* Changing back to IIterable

* Changing variable names

* Adding a comment.

* Adding another QI.  Removing duplicate code.

* Addressing comments.

* Updating version

* Removing plural

---------

Co-authored-by: Darren Hoehna <[email protected]>

* Updating version

* Changing version

---------

Co-authored-by: Darren Hoehna <[email protected]>
Co-authored-by: Kristen Schau <[email protected]>
  • Loading branch information
3 people authored Mar 21, 2024
1 parent 657e9b9 commit 4fe92fa
Show file tree
Hide file tree
Showing 12 changed files with 713 additions and 144 deletions.
2 changes: 1 addition & 1 deletion HyperVExtension/src/HyperVExtension/HyperVExtension.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.DevHome.SDK" Version="0.200.427" />
<PackageReference Include="Microsoft.Windows.DevHome.SDK" Version="0.300.443" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240227000" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
Expand Down
2 changes: 1 addition & 1 deletion common/DevHome.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.DevHome.SDK" Version="0.200.427" />
<PackageReference Include="Microsoft.Windows.DevHome.SDK" Version="0.300.443" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240227000" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Internal.Windows.DevHome.Helpers" Version="1.0.20240304-x1959" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ namespace winrt::Microsoft::Windows::DevHome::SDK::implementation
}
RepositoryResult::RepositoryResult(winrt::hresult const& e, hstring const& diagnosticText)
{
_Result = std::make_shared<winrt::Microsoft::Windows::DevHome::SDK::ProviderOperationResult>(winrt::Microsoft::Windows::DevHome::SDK::ProviderOperationStatus::Failure, winrt::hresult(e), winrt::to_hstring("Something went wrong"), diagnosticText);
_Repository = std::make_shared<winrt::Microsoft::Windows::DevHome::SDK::IRepository>();
_Result = std::make_shared<winrt::Microsoft::Windows::DevHome::SDK::ProviderOperationResult>(winrt::Microsoft::Windows::DevHome::SDK::ProviderOperationStatus::Failure, winrt::hresult(e), diagnosticText, diagnosticText);
}
winrt::Microsoft::Windows::DevHome::SDK::IRepository RepositoryResult::Repository()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace winrt::Microsoft::Windows::DevHome::SDK::implementation

RepositoryUriSupportResult::RepositoryUriSupportResult(winrt::hresult const& e, hstring const& diagnosticText)
{
_Result = std::make_shared<winrt::Microsoft::Windows::DevHome::SDK::ProviderOperationResult>(winrt::Microsoft::Windows::DevHome::SDK::ProviderOperationStatus::Failure, winrt::hresult(e), winrt::to_hstring("Something went wrong"), diagnosticText);
_Result = std::make_shared<winrt::Microsoft::Windows::DevHome::SDK::ProviderOperationResult>(winrt::Microsoft::Windows::DevHome::SDK::ProviderOperationStatus::Failure, winrt::hresult(e), diagnosticText, diagnosticText);
_IsSupported = false;
}

Expand Down
1 change: 1 addition & 0 deletions tools/SetupFlow/DevHome.SetupFlow/Models/Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ internal enum PageKind
AddViaUrl,
AddViaAccount,
Repositories,
SearchFields,
}
}
147 changes: 128 additions & 19 deletions tools/SetupFlow/DevHome.SetupFlow/Models/RepositoryProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AdaptiveCards.Rendering.WinUI3;
using DevHome.Common.Renderers;
Expand Down Expand Up @@ -59,8 +60,6 @@ public RepositoryProvider(IExtensionWrapper extensionWrapper)

public string ExtensionDisplayName => _extensionWrapper.Name;

private readonly object _getRepoLock = new();

/// <summary>
/// Starts the extension if it isn't running.
/// </summary>
Expand All @@ -85,6 +84,35 @@ public IRepositoryProvider GetProvider()
return _repositoryProvider;
}

public string GetAskChangeSearchFieldsLabel()
{
var repositoryProvider2 = _repositoryProvider as IRepositoryProvider2;
return repositoryProvider2?.AskToSearchLabel ?? string.Empty;
}

/// <summary>
/// Asks the provider for search terms for querying repositories.
/// </summary>
/// <returns>The names of the search fields.</returns>
public List<string> GetSearchTerms()
{
var repositoryProvider2 = _repositoryProvider as IRepositoryProvider2;
return repositoryProvider2?.SearchFieldNames.ToList() ?? new List<string>();
}

/// <summary>
/// Asks the provider for a list of suggestions, given values of other search terms.
/// </summary>
/// <param name="developerId">The logged in user.</param>
/// <param name="searchTerms">All information found in the search grid</param>
/// <param name="fieldName">The field to request data for</param>
/// <returns>A list of names that can be used for the field. An empty list is returned if the provider isn't found</returns>
public List<string> GetValuesFor(IDeveloperId developerId, Dictionary<string, string> searchTerms, string fieldName)
{
var repositoryProvider2 = _repositoryProvider as IRepositoryProvider2;
return repositoryProvider2?.GetValuesForSearchFieldAsync(searchTerms, fieldName, developerId).AsTask().Result.ToList() ?? new List<string>();
}

/// <summary>
/// Assigns handler as the event handler for the developerIdProvider.
/// </summary>
Expand Down Expand Up @@ -249,37 +277,118 @@ public IEnumerable<IDeveloperId> GetAllLoggedInAccounts()
return developerIdsResult.DeveloperIds;
}

/// <summary>
/// Gets all the repositories an account has for this provider.
/// </summary>
/// <param name="developerId">The account to search in.</param>
/// <returns>A collection of repositories. May be empty</returns>
public IEnumerable<IRepository> GetAllRepositories(IDeveloperId developerId)
public RepositorySearchInformation SearchForRepositories(IDeveloperId developerId, Dictionary<string, string> searchInputs)
{
IEnumerable<IRepository> repositoriesForAccount;
TelemetryFactory.Get<ITelemetry>().Log("RepoTool_SearchForRepos_Event", LogLevel.Critical, new GetReposEvent("CallingExtension", _repositoryProvider.DisplayName, developerId));

lock (_getRepoLock)
var repoSearchInformation = new RepositorySearchInformation();
try
{
if (!_repositories.TryGetValue(developerId, out repositoriesForAccount))
if (_repositoryProvider is IRepositoryProvider2 repositoryProvider2 &&
IsSearchingEnabled() && searchInputs != null)
{
TelemetryFactory.Get<ITelemetry>().Log("RepoTool_GetAllRepos_Event", LogLevel.Critical, new GetReposEvent("CallingExtension", _repositoryProvider.DisplayName, developerId));
var result = _repositoryProvider.GetRepositoriesAsync(developerId).AsTask().Result;
if (result.Result.Status != ProviderOperationStatus.Success)
var result = repositoryProvider2.GetRepositoriesAsync(searchInputs, developerId).AsTask().Result;
if (result.Result.Status == ProviderOperationStatus.Success)
{
_repositories.Add(developerId, new List<IRepository>());
repoSearchInformation.Repositories = result.Repositories;
repoSearchInformation.SelectionOptionsPlaceHolderText = result.SelectionOptionsName;
repoSearchInformation.SelectionOptionsLabel = result.SelectionOptionsLabel;
repoSearchInformation.SelectionOptions = result.SelectionOptions.ToList();
}
else
{
_repositories.Add(developerId, result.Repositories);
Log.Logger?.ReportError(Log.Component.RepoConfig, $"Could not get repositories. Message: {result.Result.DisplayMessage}", result.Result.ExtendedError);
}
}
else
{
// Fallback in case this is called with IRepositoryProvider.
RepositoriesResult result = _repositoryProvider.GetRepositoriesAsync(developerId).AsTask().Result;
if (result.Result.Status == ProviderOperationStatus.Success)
{
repoSearchInformation.Repositories = result.Repositories;
}
else
{
Log.Logger?.ReportError(Log.Component.RepoConfig, $"Could not get repositories. Message: {result.Result.DisplayMessage}", result.Result.ExtendedError);
}
}
}
catch (AggregateException aggregateException)
{
// Because tasks can be canceled DevHome should emit different logs.
if (aggregateException.InnerException is OperationCanceledException)
{
Log.Logger?.ReportInfo(Log.Component.RepoConfig, $"Get Repos operation was cancalled.");
}
else
{
Log.Logger?.ReportInfo(Log.Component.RepoConfig, aggregateException.ToString());
}
}
catch (Exception ex)
{
Log.Logger?.ReportError(Log.Component.RepoConfig, $"Could not get repositories. Message: {ex}");
}

_repositories[developerId] = repoSearchInformation.Repositories;

TelemetryFactory.Get<ITelemetry>().Log("RepoTool_SearchForRepos_Event", LogLevel.Critical, new GetReposEvent("FoundRepos", _repositoryProvider.DisplayName, developerId));
return repoSearchInformation;
}

public RepositorySearchInformation GetAllRepositories(IDeveloperId developerId)
{
TelemetryFactory.Get<ITelemetry>().Log("RepoTool_GetAllRepos_Event", LogLevel.Critical, new GetReposEvent("CallingExtension", _repositoryProvider.DisplayName, developerId));
var repoSearchInformation = new RepositorySearchInformation();
try
{
var result = _repositoryProvider.GetRepositoriesAsync(developerId).AsTask().Result;
if (result.Result.Status == ProviderOperationStatus.Success)
{
repoSearchInformation.Repositories = result.Repositories;
}
else
{
Log.Logger?.ReportError(Log.Component.RepoConfig, $"Could not get repositories. Message: {result.Result.DisplayMessage}", result.Result.ExtendedError);
}
}
catch (AggregateException aggregateException)
{
// Because tasks can be canceled DevHome should emit different logs.
if (aggregateException.InnerException is OperationCanceledException)
{
GlobalLog.Logger?.ReportInfo($"Get Repos operation was cancalled.");
}
else
{
GlobalLog.Logger?.ReportError($"{aggregateException}");
}
}
catch (Exception ex)
{
Log.Logger?.ReportError(Log.Component.RepoConfig, $"Could not get repositories. Message: {ex}");
}

// _repositories should have an entry for developerId by now.
repositoriesForAccount ??= _repositories[developerId];
_repositories[developerId] = repoSearchInformation.Repositories;

TelemetryFactory.Get<ITelemetry>().Log("RepoTool_GetAllRepos_Event", LogLevel.Critical, new GetReposEvent("FoundRepos", _repositoryProvider.DisplayName, developerId));
return repoSearchInformation;
}

/// <summary>
/// Checks if
/// 1. _repositoryProvider is IRepositoryProvider2,
/// 2. if it is, calls IsSearchingSupported.
/// </summary>
/// <returns>If the extension implements IRepositoryProvider2.</returns>
public bool IsSearchingEnabled()
{
if (_repositoryProvider is IRepositoryProvider2 repoProviderWithSearch)
{
return repoProviderWithSearch.IsSearchingSupported;
}

return repositoriesForAccount;
return false;
}
}
52 changes: 50 additions & 2 deletions tools/SetupFlow/DevHome.SetupFlow/Models/RepositoryProviders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,38 @@ public void StartIfNotRunning(string providerName)
}
}

/// <summary>
/// Asks the provider for search terms for querying repositories.
/// </summary>
/// <param name="providerName">The provider to ask</param>
/// <returns>The names of the search fields. An empty string is returned if the provider isn't found.</returns>
public List<string> GetSearchTerms(string providerName)
{
if (_providers.TryGetValue(providerName, out var repoProvider))
{
return repoProvider.GetSearchTerms();
}

return new();
}

/// <summary>
/// Asks the provider for a list of suggestions, given values of other search terms.
/// </summary>
/// <param name="providerName">The provider to ask</param>
/// <param name="searchTerms">All information found in the search grid</param>
/// <param name="fieldName">The field to request data for</param>
/// <returns>A list of names that can be used for the field. An empty list is returned if the provider isn't found</returns>
public List<string> GetValuesFor(string providerName, IDeveloperId developerId, Dictionary<string, string> searchTerms, string fieldName)
{
if (_providers.TryGetValue(providerName, out var repoProvider))
{
return repoProvider.GetValuesFor(developerId, searchTerms, fieldName);
}

return new();
}

/// <summary>
/// Goes through all providers to figure out if they can make a repo from a Uri.
/// </summary>
Expand Down Expand Up @@ -164,15 +196,31 @@ public AuthenticationExperienceKind GetAuthenticationExperienceKind(string provi
return _providers.GetValueOrDefault(providerName)?.GetAuthenticationExperienceKind() ?? AuthenticationExperienceKind.CardSession;
}

public RepositorySearchInformation SearchForRepos(string providerName, IDeveloperId developerId, Dictionary<string, string> searchInputs)
{
Log.Logger?.ReportInfo(Log.Component.RepoConfig, $"Getting all repositories for repository provider {providerName}");
return _providers.GetValueOrDefault(providerName)?.SearchForRepositories(developerId, searchInputs) ?? new RepositorySearchInformation();
}

/// <summary>
/// Gets all the repositories for an account and provider. The account will be logged in if they aren't already.
/// </summary>
/// <param name="providerName">The specific provider. Must match the display name of a provider</param>
/// <param name="developerId">The account to look for. May not be logged in.</param>
/// <returns>All the repositories for an account and provider.</returns>
public IEnumerable<IRepository> GetAllRepositories(string providerName, IDeveloperId developerId)
public RepositorySearchInformation GetAllRepositories(string providerName, IDeveloperId developerId)
{
Log.Logger?.ReportInfo(Log.Component.RepoConfig, $"Getting all repositories for repository provider {providerName}");
return _providers.GetValueOrDefault(providerName)?.GetAllRepositories(developerId) ?? new List<IRepository>();
return _providers.GetValueOrDefault(providerName)?.GetAllRepositories(developerId) ?? new RepositorySearchInformation();
}

public bool IsSearchingEnabled(string providerName)
{
return _providers.GetValueOrDefault(providerName)?.IsSearchingEnabled() ?? false;
}

public string GetAskChangeSearchFieldsLabel(string providerName)
{
return _providers.GetValueOrDefault(providerName)?.GetAskChangeSearchFieldsLabel() ?? string.Empty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Windows.DevHome.SDK;

namespace DevHome.SetupFlow.Models;

public class RepositorySearchInformation
{
public IEnumerable<IRepository> Repositories { get; set; } = Enumerable.Empty<IRepository>();

public string SelectionOptionsPlaceHolderText { get; set; } = string.Empty;

public List<string> SelectionOptions { get; set; } = new List<string>();

public string SelectionOptionsLabel { get; set; } = string.Empty;
}
Loading

0 comments on commit 4fe92fa

Please sign in to comment.