Display connection state in tab and add context menu entry for restarting connection (#15760)

## Summary of the Pull Request
When a connection is Closed, show an indicator in the respective tab.
When the active pane's connection is Closed, show a "Restart Connection"
action in the right-click context menu and in the tab context menu.

## Validation Steps Performed
- Force close a connection, check the indicator is shown in the tab.
- Right-click on pane shows the Restart Connection action if its
connection is closed
- Right-click on tab shows the Restart Connection action if the active
pane's connection is closed
- Indicator is cleared after connection is restarted (no panes in closed
state)

## PR Checklist
- [x] Closes #14909 
- [x] Tests added/passed
- [ ] Documentation updated
- [ ] Schema updated (if necessary)
This commit is contained in:
MPela
2023-09-19 19:01:29 +02:00
committed by GitHub
parent 3550e19751
commit 2e91e9c6de
9 changed files with 110 additions and 2 deletions

View File

@@ -1384,6 +1384,18 @@ Profile Pane::GetFocusedProfile()
return lastFocused ? lastFocused->_profile : nullptr;
}
// Method Description:
// - Returns true if the connection state of this pane is closed. If this Pane is not a leaf this will
// return false.
// Arguments:
// - <none>
// Return Value:
// - true if the connection state of this Pane is closed.
bool Pane::IsConnectionClosed() const
{
return _control && _control.ConnectionState() >= ConnectionState::Closed;
}
// Method Description:
// - Returns true if this pane was the last pane to be focused in a tree of panes.
// Arguments:

View File

@@ -75,6 +75,7 @@ public:
winrt::Microsoft::Terminal::Control::TermControl GetLastFocusedTerminalControl();
winrt::Microsoft::Terminal::Control::TermControl GetTerminalControl();
winrt::Microsoft::Terminal::Settings::Model::Profile GetFocusedProfile();
bool IsConnectionClosed() const;
// Method Description:
// - If this is a leaf pane, return its profile.

View File

@@ -891,4 +891,10 @@
<data name="CmdAppendCommandLineDesc" xml:space="preserve">
<value>If set, the command will be appended to the profile's default command instead of replacing it.</value>
</data>
<data name="RestartConnectionText" xml:space="preserve">
<value>Restart Connection</value>
</data>
<data name="RestartConnectionToolTip" xml:space="preserve">
<value>Restart the active pane connection</value>
</data>
</root>

View File

@@ -43,6 +43,12 @@
FontSize="12"
Glyph="&#xE72E;"
Visibility="{x:Bind TabStatus.IsReadOnlyActive, Mode=OneWay}" />
<FontIcon x:Name="HeaderClosedIcon"
Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="12"
Glyph="&#xEA39;"
Visibility="{x:Bind TabStatus.IsConnectionClosed, Mode=OneWay}" />
<FontIcon x:Name="HeaderBroadcastIcon"
Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"

View File

@@ -4810,8 +4810,7 @@ namespace winrt::TerminalApp::implementation
const bool withSelection)
{
// withSelection can be used to add actions that only appear if there's
// selected text, like "search the web". In this initial draft, it's not
// actually augmented by the TerminalPage, so it's left commented out.
// selected text, like "search the web"
const auto& menu{ sender.try_as<MUX::Controls::CommandBarFlyout>() };
if (!menu)
@@ -4864,6 +4863,14 @@ namespace winrt::TerminalApp::implementation
makeItem(RS_(L"PaneClose"), L"\xE89F", ActionAndArgs{ ShortcutAction::ClosePane, nullptr });
}
if (const auto pane{ _GetFocusedTabImpl()->GetActivePane() })
{
if (pane->IsConnectionClosed())
{
makeItem(RS_(L"RestartConnectionText"), L"\xE72C", ActionAndArgs{ ShortcutAction::RestartConnection, nullptr });
}
}
if (withSelection)
{
makeItem(RS_(L"SearchWebText"), L"\xF6FA", ActionAndArgs{ ShortcutAction::SearchForText, nullptr });

View File

@@ -15,6 +15,7 @@ using namespace winrt;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Core;
using namespace winrt::Microsoft::Terminal::Control;
using namespace winrt::Microsoft::Terminal::TerminalConnection;
using namespace winrt::Microsoft::Terminal::Settings::Model;
using namespace winrt::Microsoft::UI::Xaml::Controls;
using namespace winrt::Windows::System;
@@ -35,6 +36,7 @@ namespace winrt::TerminalApp::implementation
_activePane = nullptr;
_closePaneMenuItem.Visibility(WUX::Visibility::Collapsed);
_restartConnectionMenuItem.Visibility(WUX::Visibility::Collapsed);
auto firstId = _nextPaneId;
@@ -890,6 +892,7 @@ namespace winrt::TerminalApp::implementation
control.TitleChanged(events.titleToken);
control.TabColorChanged(events.colorToken);
control.SetTaskbarProgress(events.taskbarToken);
control.ConnectionStateChanged(events.stateToken);
control.ReadOnlyChanged(events.readOnlyToken);
control.FocusFollowMouseRequested(events.focusToken);
@@ -949,6 +952,14 @@ namespace winrt::TerminalApp::implementation
}
});
events.stateToken = control.ConnectionStateChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThis.get() })
{
tab->_UpdateConnectionClosedState();
}
});
events.readOnlyToken = control.ReadOnlyChanged([dispatcher, weakThis](auto&&, auto&&) -> winrt::fire_and_forget {
co_await wil::resume_foreground(dispatcher);
if (auto tab{ weakThis.get() })
@@ -1054,6 +1065,40 @@ namespace winrt::TerminalApp::implementation
_TaskbarProgressChangedHandlers(nullptr, nullptr);
}
// Method Description:
// - Set an indicator on the tab if any pane is in a closed connection state.
// - Show/hide the Restart Connection context menu entry depending on active pane's state.
// Arguments:
// - <none>
// Return Value:
// - <none>
void TerminalTab::_UpdateConnectionClosedState()
{
ASSERT_UI_THREAD();
if (_rootPane)
{
const bool isClosed = _rootPane->WalkTree([&](const auto& p) {
return p->IsConnectionClosed();
});
_tabStatus.IsConnectionClosed(isClosed);
}
if (_activePane)
{
_restartConnectionMenuItem.Visibility(_activePane->IsConnectionClosed() ?
WUX::Visibility::Visible :
WUX::Visibility::Collapsed);
}
}
void TerminalTab::_RestartActivePaneConnection()
{
ActionAndArgs restartConnection{ ShortcutAction::RestartConnection, nullptr };
_dispatch.DoAction(*this, restartConnection);
}
// Method Description:
// - Mark the given pane as the active pane in this tab. All other panes
// will be marked as inactive. We'll also update our own UI state to
@@ -1072,6 +1117,7 @@ namespace winrt::TerminalApp::implementation
// Update our own title text to match the newly-active pane.
UpdateTitle();
_UpdateProgressState();
_UpdateConnectionClosedState();
// We need to move the pane to the top of our mru list
// If its already somewhere in the list, remove it first
@@ -1393,6 +1439,28 @@ namespace winrt::TerminalApp::implementation
Automation::AutomationProperties::SetHelpText(findMenuItem, findToolTip);
}
Controls::MenuFlyoutItem restartConnectionMenuItem = _restartConnectionMenuItem;
{
// "Restart Connection"
Controls::FontIcon restartConnectionSymbol;
restartConnectionSymbol.FontFamily(Media::FontFamily{ L"Segoe Fluent Icons, Segoe MDL2 Assets" });
restartConnectionSymbol.Glyph(L"\xE72C");
restartConnectionMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_RestartActivePaneConnection();
}
});
restartConnectionMenuItem.Text(RS_(L"RestartConnectionText"));
restartConnectionMenuItem.Icon(restartConnectionSymbol);
const auto restartConnectionToolTip = RS_(L"RestartConnectionToolTip");
WUX::Controls::ToolTipService::SetToolTip(restartConnectionMenuItem, box_value(restartConnectionToolTip));
Automation::AutomationProperties::SetHelpText(restartConnectionMenuItem, restartConnectionToolTip);
}
// Build the menu
Controls::MenuFlyout contextMenuFlyout;
Controls::MenuFlyoutSeparator menuSeparator;
@@ -1403,6 +1471,7 @@ namespace winrt::TerminalApp::implementation
contextMenuFlyout.Items().Append(moveTabToNewWindowMenuItem);
contextMenuFlyout.Items().Append(exportTabMenuItem);
contextMenuFlyout.Items().Append(findMenuItem);
contextMenuFlyout.Items().Append(restartConnectionMenuItem);
contextMenuFlyout.Items().Append(menuSeparator);
// GH#5750 - When the context menu is dismissed with ESC, toss the focus

View File

@@ -109,6 +109,7 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<Pane> _zoomedPane{ nullptr };
Windows::UI::Xaml::Controls::MenuFlyoutItem _closePaneMenuItem;
Windows::UI::Xaml::Controls::MenuFlyoutItem _restartConnectionMenuItem;
winrt::hstring _lastIconPath{};
std::optional<winrt::Windows::UI::Color> _runtimeTabColor{};
@@ -125,6 +126,7 @@ namespace winrt::TerminalApp::implementation
winrt::event_token titleToken;
winrt::event_token colorToken;
winrt::event_token taskbarToken;
winrt::event_token stateToken;
winrt::event_token readOnlyToken;
winrt::event_token focusToken;
@@ -171,6 +173,9 @@ namespace winrt::TerminalApp::implementation
void _UpdateProgressState();
void _UpdateConnectionClosedState();
void _RestartActivePaneConnection();
void _DuplicateTab();
virtual winrt::Windows::UI::Xaml::Media::Brush _BackgroundBrush() override;

View File

@@ -12,6 +12,7 @@ namespace winrt::TerminalApp::implementation
TerminalTabStatus() = default;
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
WINRT_OBSERVABLE_PROPERTY(bool, IsConnectionClosed, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, IsPaneZoomed, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingActive, _PropertyChangedHandlers);
WINRT_OBSERVABLE_PROPERTY(bool, IsProgressRingIndeterminate, _PropertyChangedHandlers);

View File

@@ -7,6 +7,7 @@ namespace TerminalApp
{
TerminalTabStatus();
Boolean IsConnectionClosed { get; set; };
Boolean IsPaneZoomed { get; set; };
Boolean IsProgressRingActive { get; set; };
Boolean IsProgressRingIndeterminate { get; set; };