Files
terminal/src/cascadia/TerminalSettingsEditor/Profiles_Appearance.cpp
Carlos Zamora ca70e49cdf Add telemetry for settings UI traffic (#19156)
Adds a telemetry provider to the Terminal.Settings.Editor project as
well as new telemetry events to track traffic through the settings UI.
Specifically, the following events were added:
- `NavigatedToPage`: Event emitted when the user navigates to a page in
the settings UI
- Has a `PageId` parameter that includes the identifier of the page that
was navigated to
- (conditionally added when PageId = `page.editColorScheme`)
`SchemeName` parameter tracks the name of the color scheme that's being
edited
   - conditionally added when PageId = `page.extensions`:
- `ExtensionPackageCount`: The number of extension packages displayed
- `ProfilesModifiedCount`: The number of profiles modified by enabled
extensions
- `ProfilesAddedCount`: The number of profiles added by enabled
extensions
- `ColorSchemesAddedCount`: The number of color schemes added by enabled
extensions
   - conditionally added when PageId = `page.extensions.extensionView`:
- `FragmentSource`: The source of the fragment included in this
extension package
- `FragmentCount`: The number of fragments included in this extension
package
      - `Enabled`: The enabled status of the extension
- (conditionally added when PageID = `page.newTabMenu`) if the page is
representing a folder view
   - conditionally added when PageID = `page.profile.*`:
- `IsProfileDefaults`: if the modified profile is the profile.defaults
object
      - `ProfileGuid`: the guid of the profile that was navigated to
      - `ProfileSource`: the source of the profile that was navigated to
- conditionally added when PageID = `page.profile` (aka the base profile
page):
         - `Orphaned`: tracks if the profile was orphaned
         - `Hidden`: tracks if the profile is hidden
- (conditionally added when PageID = `page.profile.appearance`)
`HasBackgroundImage`: `if the profile has a background image defined`
- (conditionally added when PageID = `page.profile.appearance`)
`HasUnfocusedAppearance`: `if the profile has an unfocused appearance
defined`
- `AddNewProfile`: Event emitted when the user adds a new profile
`IsExtensionView` parameter tracks if the page is representing a view of
an extension
- Has a `Type` parameter that represents the type of the creation method
(i.e. empty profile, duplicate)
- `ResetApplicationState`: Event emitted when the user resets their
application state (via the UI)
- `ResetToDefaultSettings`: Event emitted when the user resets their
settings to their default value (via the UI)
- `OpenJson`: Event emitted when the user clicks the Open JSON button in
the settings UI
- Has a `SettingsTarget` parameter that represents the target settings
file (i.e. settings.json vs defaults.json)
- `CreateUnfocusedAppearance`: Event emitted when the user creates an
unfocused appearance for a profile
- `IsProfileDefaults`: if the modified profile is the profile.defaults
object
   - `ProfileGuid`: the guid of the profile that was navigated to
   - `ProfileSource`: the source of the profile that was navigated to
- `DeleteProfile`: Event emitted when the user deletes a profile
- also includes `ProfileGuid`, `ProfileSource`, `Orphaned` from the
`NavigatedToPage` section above

The page ids can be reused later as a serialized reference to the page.
We already use the one for the extensions page for the "new" badge.

(cherry picked from commit 7578209be5)
Service-Card-Id: PVTI_lADOAF3p4s4Axadtzgc2p-8
Service-Version: 1.23
2025-08-25 11:23:24 -05:00

105 lines
5.1 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "Profiles_Appearance.h"
#include "ProfileViewModel.h"
#include "PreviewConnection.h"
#include "Profiles_Appearance.g.cpp"
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Navigation;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Profiles_Appearance::Profiles_Appearance()
{
InitializeComponent();
_previewConnection = winrt::make_self<PreviewConnection>();
}
void Profiles_Appearance::OnNavigatedTo(const NavigationEventArgs& e)
{
const auto args = e.Parameter().as<Editor::NavigateToProfileArgs>();
_Profile = args.Profile();
_windowRoot = args.WindowRoot();
if (!_previewControl)
{
const auto settings = _Profile.TermSettings();
_previewConnection->DisplayPowerlineGlyphs(_Profile.DefaultAppearance().HasPowerlineCharacters());
_previewControl = Control::TermControl(settings, settings, *_previewConnection);
_previewControl.IsEnabled(false);
_previewControl.AllowFocusWhenDisabled(false);
_previewControl.CursorVisibility(Microsoft::Terminal::Control::CursorDisplayState::Shown);
ControlPreview().Child(_previewControl);
}
// Subscribe to some changes in the view model
// These changes should force us to update our own set of "Current<Setting>" members,
// and propagate those changes to the UI
_ViewModelChangedRevoker = _Profile.PropertyChanged(winrt::auto_revoke, { this, &Profiles_Appearance::_onProfilePropertyChanged });
// The Appearances object handles updating the values in the settings UI, but
// we still need to listen to the changes here just to update the preview control
_AppearanceViewModelChangedRevoker = _Profile.DefaultAppearance().PropertyChanged(winrt::auto_revoke, { this, &Profiles_Appearance::_onProfilePropertyChanged });
TraceLoggingWrite(
g_hTerminalSettingsEditorProvider,
"NavigatedToPage",
TraceLoggingDescription("Event emitted when the user navigates to a page in the settings UI"),
TraceLoggingValue("profile.appearance", "PageId", "The identifier of the page that was navigated to"),
TraceLoggingValue(_Profile.IsBaseLayer(), "IsProfileDefaults", "If the modified profile is the profile.defaults object"),
TraceLoggingValue(static_cast<GUID>(_Profile.Guid()), "ProfileGuid", "The guid of the profile that was navigated to"),
TraceLoggingValue(_Profile.Source().c_str(), "ProfileSource", "The source of the profile that was navigated to"),
TraceLoggingValue(_Profile.DefaultAppearance().BackgroundImageSettingsVisible(), "HasBackgroundImage", "If the profile has a background image defined"),
TraceLoggingValue(_Profile.HasUnfocusedAppearance(), "HasUnfocusedAppearance", "If the profile has an unfocused appearance defined"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
void Profiles_Appearance::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
{
_ViewModelChangedRevoker.revoke();
_AppearanceViewModelChangedRevoker.revoke();
}
void Profiles_Appearance::CreateUnfocusedAppearance_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*e*/)
{
TraceLoggingWrite(
g_hTerminalSettingsEditorProvider,
"CreateUnfocusedAppearance",
TraceLoggingDescription("Event emitted when the user creates an unfocused appearance for a profile"),
TraceLoggingValue(_Profile.IsBaseLayer(), "IsProfileDefaults", "If the modified profile is the profile.defaults object"),
TraceLoggingValue(static_cast<GUID>(_Profile.Guid()), "ProfileGuid", "The guid of the profile that was navigated to"),
TraceLoggingValue(_Profile.Source().c_str(), "ProfileSource", "The source of the profile that was navigated to"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
_Profile.CreateUnfocusedAppearance();
}
void Profiles_Appearance::DeleteUnfocusedAppearance_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*e*/)
{
_Profile.DeleteUnfocusedAppearance();
}
void Profiles_Appearance::_onProfilePropertyChanged(const IInspectable&, const PropertyChangedEventArgs&)
{
if (!_updatePreviewControl)
{
_updatePreviewControl = std::make_shared<ThrottledFuncTrailing<>>(
winrt::Windows::System::DispatcherQueue::GetForCurrentThread(),
std::chrono::milliseconds{ 100 },
[this]() {
const auto settings = _Profile.TermSettings();
_previewConnection->DisplayPowerlineGlyphs(_Profile.DefaultAppearance().HasPowerlineCharacters());
_previewControl.UpdateControlSettings(settings, settings);
});
}
_updatePreviewControl->Run();
}
}