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

Add summary view in configuration file page #2495

Merged
merged 18 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from 17 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 @@ -2,6 +2,8 @@
// Licensed under the MIT License.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DevHome.SetupFlow.Common.Exceptions;
Expand Down Expand Up @@ -51,6 +53,8 @@ public ConfigurationFileHelper(Guid activityId)
_activityId = activityId;
}

public IList<ConfigurationUnit> Units => _configSet?.Units;

/// <summary>
/// Open configuration set from the provided <paramref name="content"/>.
/// </summary>
Expand All @@ -71,6 +75,16 @@ public async Task OpenConfigurationSetAsync(string filePath, string content)
}
}

public async Task ResolveConfigurationUnitDetails()
{
if (_processor == null || _configSet == null)
{
throw new InvalidOperationException();
}

await _processor.GetSetDetailsAsync(_configSet, ConfigurationUnitDetailFlags.ReadOnly);
}

private async Task<ConfigurationSet> OpenConfigurationSetInternalAsync(ConfigurationProcessor processor, string filePath, string content)
{
var file = await StorageFile.GetFileFromPathAsync(filePath);
Expand Down
2 changes: 2 additions & 0 deletions tools/SetupFlow/DevHome.SetupFlow/Models/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public Configuration(string filePath)
/// </summary>
public string Name => _fileInfo.Name;

public string Path => _fileInfo.FullName;

/// <summary>
/// Gets the file content
/// </summary>
Expand Down
99 changes: 99 additions & 0 deletions tools/SetupFlow/DevHome.SetupFlow/Models/DSCConfigurationUnit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Collections.Generic;
using System.Linq;
using Microsoft.Management.Configuration;

namespace DevHome.SetupFlow.Models;

public class DSCConfigurationUnit
{
private const string DescriptionMetadataKey = "description";
private const string ModuleMetadataKey = "module";

public DSCConfigurationUnit(ConfigurationUnit unit)
{
// Constructor copies all the required data from the out-of-proc COM
// objects over to the current process. This ensures that we have this
// information available even if the out-of-proc COM objects are no
// longer available (e.g. AppInstaller service is no longer running).
Type = unit.Type;
Id = unit.Identifier;
Intent = unit.Intent.ToString();
Dependencies = [.. unit.Dependencies];

// Get description from settings
unit.Metadata.TryGetValue(DescriptionMetadataKey, out var descriptionObj);
Description = descriptionObj?.ToString() ?? string.Empty;

// Get module name from metadata
unit.Metadata.TryGetValue(ModuleMetadataKey, out var moduleObj);
ModuleName = moduleObj?.ToString() ?? string.Empty;

// Load dictionary values into list of key value pairs
Settings = unit.Settings.Select(s => new KeyValuePair<string, string>(s.Key, s.Value.ToString())).ToList();
Metadata = unit.Metadata.Select(m => new KeyValuePair<string, string>(m.Key, m.Value.ToString())).ToList();

// Load details if available
if (unit.Details != null)
{
UnitType = unit.Details.UnitType;
UnitDescription = unit.Details.UnitDescription;
UnitDocumentationUri = unit.Details.UnitDocumentationUri?.ToString();
ModuleName = unit.Details.ModuleName;
ModuleType = unit.Details.ModuleType;
ModuleSource = unit.Details.ModuleSource;
ModuleDescription = unit.Details.ModuleDescription;
ModuleDocumentationUri = unit.Details.ModuleDocumentationUri?.ToString();
PublishedModuleUri = unit.Details.PublishedModuleUri?.ToString();
Version = unit.Details.Version;
IsLocal = unit.Details.IsLocal;
Author = unit.Details.Author;
Publisher = unit.Details.Publisher;
IsPublic = unit.Details.IsPublic;
}
}

public string Type { get; }

public string Id { get; }

public string Description { get; }

public string Intent { get; }

public IList<string> Dependencies { get; }

public IList<KeyValuePair<string, string>> Settings { get; }

public IList<KeyValuePair<string, string>> Metadata { get; }

public string UnitType { get; }

public string UnitDescription { get; }

public string UnitDocumentationUri { get; }

public string ModuleName { get; }

public string ModuleType { get; }

public string ModuleSource { get; }

public string ModuleDescription { get; }

public string ModuleDocumentationUri { get; }

public string PublishedModuleUri { get; }

public string Version { get; }

public bool IsLocal { get; }

public string Author { get; }

public string Publisher { get; }

public bool IsPublic { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using DevHome.SetupFlow.Common.Configuration;
using DevHome.SetupFlow.Models;
using DevHome.SetupFlow.Services.WinGet;
using Windows.Storage;

Expand Down Expand Up @@ -32,6 +35,16 @@ public async Task ValidateConfigurationAsync(string filePath, Guid activityId)
await OpenConfigurationSetAsync(filePath, activityId);
}

/// <inheritdoc />
public async Task<IReadOnlyList<DSCConfigurationUnit>> GetConfigurationUnitDetailsAsync(Configuration configuration, Guid activityId)
{
var configFile = await OpenConfigurationSetAsync(configuration.Path, configuration.Content, activityId);
await configFile.ResolveConfigurationUnitDetails();
var configUnitsOutOfProc = configFile.Units;
var configUnitsInProc = configUnitsOutOfProc.Select(unit => new DSCConfigurationUnit(unit));
return configUnitsInProc.ToList();
}

/// <inheritdoc />
public async Task<ConfigurationFileHelper.ApplicationResult> ApplyConfigurationAsync(string filePath, Guid activityId)
{
Expand All @@ -48,10 +61,15 @@ public async Task ValidateConfigurationAsync(string filePath, Guid activityId)
/// <returns>Configuration file helper</returns>
private async Task<ConfigurationFileHelper> OpenConfigurationSetAsync(string filePath, Guid activityId)
{
var configFile = new ConfigurationFileHelper(activityId);
var file = await StorageFile.GetFileFromPathAsync(filePath);
var content = File.ReadAllText(file.Path);
await configFile.OpenConfigurationSetAsync(file.Path, content);
return await OpenConfigurationSetAsync(file.Path, content, activityId);
}

private async Task<ConfigurationFileHelper> OpenConfigurationSetAsync(string filePath, string content, Guid activityId)
{
var configFile = new ConfigurationFileHelper(activityId);
await configFile.OpenConfigurationSetAsync(filePath, content);
return configFile;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DevHome.SetupFlow.Common.Configuration;
using DevHome.SetupFlow.Models;
using DevHome.SetupFlow.Services.WinGet;

namespace DevHome.SetupFlow.Services;
Expand All @@ -23,6 +25,14 @@ public interface IDesiredStateConfiguration
/// <param name="activityId">Activity ID.</param>
public Task ValidateConfigurationAsync(string filePath, Guid activityId);

/// <summary>
/// Gets the details of the provided configuration file.
/// </summary>
/// <param name="configuration">Configuration</param>
/// <param name="activityId">Activity ID.</param>
/// <returns>List of configuration units</returns>
public Task<IReadOnlyList<DSCConfigurationUnit>> GetConfigurationUnitDetailsAsync(Configuration configuration, Guid activityId);

/// <summary>
/// Applies the provided configuration file.
/// </summary>
Expand Down
84 changes: 84 additions & 0 deletions tools/SetupFlow/DevHome.SetupFlow/Strings/en-us/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,90 @@
<value>Loading your environments</value>
<comment>Test that tells the user that we're still loading their environments. These environments can be virtual or remote machines</comment>
</data>
<data name="ConfigurationFile_SummaryView.Content" xml:space="preserve">
<value>Summary view</value>
<comment>Show the summary view of the configuration file</comment>
</data>
<data name="ConfigurationFile_CodeView.Content" xml:space="preserve">
<value>Code view</value>
<comment>Show the code view of the configuration file</comment>
</data>
<data name="ConfigurationUnit_Id.Key" xml:space="preserve">
<value>Id</value>
<comment>Id of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_Intent.Key" xml:space="preserve">
<value>Intent</value>
<comment>Intent of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_Dependencies.Text" xml:space="preserve">
<value>Dependencies</value>
<comment>Dependencies of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_ResourceMetadata.Text" xml:space="preserve">
<value>Resource metadata</value>
<comment>Resource metadata of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_Settings.Text" xml:space="preserve">
<value>Settings</value>
<comment>Settings of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_Details.Text" xml:space="preserve">
<value>Details</value>
<comment>Details of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_UnitType.Key" xml:space="preserve">
<value>unit type</value>
<comment>Unit type of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_UnitDescription.Key" xml:space="preserve">
<value>unit description</value>
AmelBawa-msft marked this conversation as resolved.
Show resolved Hide resolved
<comment>Unit description of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_UnitDocumentation.Key" xml:space="preserve">
<value>unit documentation</value>
<comment>Unit documentation of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_ModuleName.Key" xml:space="preserve">
<value>module name</value>
<comment>Module name of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_ModuleSource.Key" xml:space="preserve">
<value>module source</value>
<comment>Module source of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_ModuleDescription.Key" xml:space="preserve">
<value>module description</value>
<comment>Module description of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_ModuleDocumentationUri.Key" xml:space="preserve">
<value>module documentation uri</value>
<comment>Module documentation uri of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_PublishedModuleUri.Key" xml:space="preserve">
<value>module documentation uri</value>
<comment>Module documentation uri of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_Version.Key" xml:space="preserve">
<value>version</value>
<comment>Version of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_IsLocal.Key" xml:space="preserve">
<value>is local</value>
<comment>Check if the configuration unit is local on the machine</comment>
</data>
<data name="ConfigurationUnit_Author.Key" xml:space="preserve">
<value>author</value>
<comment>Author of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_Publisher.Key" xml:space="preserve">
<value>publisher</value>
<comment>Publisher of the configuration unit</comment>
</data>
<data name="ConfigurationUnit_IsPublic.Key" xml:space="preserve">
<value>is public</value>
<comment>Check if the configuration unit is public</comment>
</data>
<data name="CloneRepoNextStepsDescription" xml:space="preserve">
<value>Detected '{0}' while cloning '{1}'</value>
<comment>Locked={"{0}", "{1}"} Description letting users know what configuration was found and in what repo the file was found in. {0} is the file name with extension. {1} is the repo name including the owner.</comment>
Expand Down
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 CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
Expand Down Expand Up @@ -41,6 +42,9 @@ public partial class ConfigurationFileViewModel : SetupPageViewModelBase
[NotifyCanExecuteChangedFor(nameof(ConfigureAsNonAdminCommand))]
private bool _readAndAgree;

[ObservableProperty]
private IList<DSCConfigurationUnitViewModel> _configurationUnits;

public ConfigurationFileViewModel(
ISetupFlowStringResource stringResource,
IDesiredStateConfiguration dsc,
Expand Down Expand Up @@ -69,7 +73,7 @@ partial void OnReadAndAgreeChanged(bool value)
public string Content => Configuration.Content;

[RelayCommand(CanExecute = nameof(ReadAndAgree))]
public async Task ConfigureAsAdminAsync()
private async Task ConfigureAsAdminAsync()
{
foreach (var task in TaskList)
{
Expand All @@ -89,12 +93,29 @@ public async Task ConfigureAsAdminAsync()
}

[RelayCommand(CanExecute = nameof(ReadAndAgree))]
public async Task ConfigureAsNonAdminAsync()
private async Task ConfigureAsNonAdminAsync()
{
TelemetryFactory.Get<ITelemetry>().Log("ConfigurationButton_Click", LogLevel.Critical, new ConfigureCommandEvent(false), Orchestrator.ActivityId);
await Orchestrator.GoToNextPage();
}

[RelayCommand]
private async Task OnLoadedAsync()
{
try
{
if (Configuration != null && ConfigurationUnits == null)
{
var configUnits = await _dsc.GetConfigurationUnitDetailsAsync(Configuration, Orchestrator.ActivityId);
ConfigurationUnits = configUnits.Select(u => new DSCConfigurationUnitViewModel(u)).ToList();
}
}
catch (Exception e)
{
_log.Error($"Failed to get configuration unit details.", e);
}
}

/// <summary>
/// Open file picker to select a YAML configuration file.
/// </summary>
Expand Down
Loading
Loading