Skip to content

Commit adf19c1

Browse files
BornToBeRootclaude
andauthored
Feature: Improve run command design & behaviour (#3646)
* Feature: Run command for Subnet Calculator and Lookup - Subnet Calculator (subnetcalculator, subnet, ipcalc): "subnet 10.0.0.0/24" calculates the subnet, a new subnet mask or CIDR as second argument ("subnet 10.0.0.0/16 /24") opens Subnetting, a second subnet ("subnet 10.0.0.0/24 10.0.1.0/24") opens Wide Subnet. - Lookup: "lookup oui <query>" and "lookup port <query>". The type is the first word after the command (RunCommandDefinition.TypeBeforeTarget), the rest of the input is the query, so vendors can contain spaces. Without a query, the lookup is only shown. Suggestions offer the lookups after "lookup " and preselect the matching one while typing. - Commands can opt out of profiles (Subnet Calculator, Lookup), the syntax hint then has no "@<Profile>". - Subnet Calculator and Lookup host views handle requests and select the tab (SubnetCalculatorRequest, LookupRequest). - Fix: Subnetting got stuck if the new subnet mask was smaller than the one of the subnet or too large for the address family (e.g. /40 for IPv4). An error is shown instead; the run command validates the same range (Subnetmask.ConvertSubnetmaskOrCidrToCidr). - Parser tests, docs and changelog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: Recently run profiles first in the run command suggestions The recent commands are not shown while typing a profile ("@"), so the profiles of the command are ordered by their last use within the same rank (exact name, starts with, contains). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: Global hotkey to open the run command Settings > HotKeys: "Bring window to foreground and open the run command" (disabled by default, default Ctrl+Alt+P). Shows the window (also from the tray) and opens the run command dialog. Docs: hotkeys page (also English key names instead of "ALT + STRG"), run command page and changelog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Feature: Improve run command dialog & behaviour * Update next-release.md * Fix: input validation * Feature: Improve run command * Fix: Copilot feedback * Fix: Code review fixes * Fix: copilot feedback --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent db1106f commit adf19c1

100 files changed

Lines changed: 4206 additions & 435 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/dependabot.yml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,9 @@ updates:
2525
target-branch: main
2626
commit-message:
2727
prefix: "Dependency (dependabot/npm):"
28+
groups:
29+
# react and react-dom must have the exact same version (otherwise the website build fails)
30+
react:
31+
patterns:
32+
- "react"
33+
- "react-dom"
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System;
2+
using System.Windows;
3+
using System.Windows.Controls;
4+
using System.Windows.Threading;
5+
6+
namespace NETworkManager.Controls;
7+
8+
/// <summary>
9+
/// Attached property that keeps the text of an editable <see cref="ComboBox"/> that shows a history (e.g. the hosts of
10+
/// the Traceroute) when its selected entry is removed from the history.
11+
///
12+
/// The history is changed in place (<c>ListHelper.Modify</c>): the oldest entries are removed and, if the number of
13+
/// stored entries is 0, all of them. If the removed entry is the selected item (e.g. the host that was just used, or the
14+
/// host of another tab that shares the history), WPF clears the text of the ComboBox. The text is restored after the
15+
/// ComboBox has updated it. If the entry is only deselected because another text was typed, it is still in the list and
16+
/// nothing is changed.
17+
/// </summary>
18+
public static class ComboBoxHistoryBehavior
19+
{
20+
public static readonly DependencyProperty KeepTextWhenSelectedItemIsRemovedProperty =
21+
DependencyProperty.RegisterAttached(
22+
"KeepTextWhenSelectedItemIsRemoved",
23+
typeof(bool),
24+
typeof(ComboBoxHistoryBehavior),
25+
new PropertyMetadata(false, OnKeepTextWhenSelectedItemIsRemovedChanged));
26+
27+
public static void SetKeepTextWhenSelectedItemIsRemoved(UIElement element, bool value) =>
28+
element.SetValue(KeepTextWhenSelectedItemIsRemovedProperty, value);
29+
30+
public static bool GetKeepTextWhenSelectedItemIsRemoved(UIElement element) =>
31+
(bool)element.GetValue(KeepTextWhenSelectedItemIsRemovedProperty);
32+
33+
private static void OnKeepTextWhenSelectedItemIsRemovedChanged(DependencyObject d,
34+
DependencyPropertyChangedEventArgs e)
35+
{
36+
if (d is not ComboBox comboBox)
37+
return;
38+
39+
if ((bool)e.NewValue)
40+
comboBox.SelectionChanged += ComboBox_SelectionChanged;
41+
else
42+
comboBox.SelectionChanged -= ComboBox_SelectionChanged;
43+
}
44+
45+
private static void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
46+
{
47+
if (sender is not ComboBox { IsEditable: true } comboBox || comboBox.SelectedItem != null ||
48+
e.RemovedItems.Count == 0)
49+
return;
50+
51+
var removedItem = e.RemovedItems[0];
52+
53+
// Deselected because another text was typed: the entry is still in the list.
54+
if (comboBox.Items.Contains(removedItem))
55+
return;
56+
57+
var text = removedItem?.ToString();
58+
59+
if (string.IsNullOrEmpty(text))
60+
return;
61+
62+
// After the ComboBox has cleared its text (and only if it did)
63+
comboBox.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new Action(delegate
64+
{
65+
if (string.IsNullOrEmpty(comboBox.Text))
66+
comboBox.Text = text;
67+
}));
68+
}
69+
}

‎Source/NETworkManager.Controls/ObservableRangeCollection.cs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.ObjectModel;
33
using System.Collections.Specialized;
44
using System.ComponentModel;
5+
using System.Linq;
56

67
namespace NETworkManager.Controls;
78

@@ -23,9 +24,12 @@ public void ReplaceAll(IEnumerable<T> items)
2324
{
2425
CheckReentrancy();
2526

27+
// Read the items first: if a lazy sequence throws, the collection is unchanged (and in sync with the views).
28+
var newItems = items.ToList();
29+
2630
Items.Clear();
2731

28-
foreach (var item in items)
32+
foreach (var item in newItems)
2933
Items.Add(item);
3034

3135
OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count)));

0 commit comments

Comments
 (0)