diff --git a/BusLane.Tests/Views/AlertsDialogTests.cs b/BusLane.Tests/Views/AlertsDialogTests.cs
new file mode 100644
index 0000000..d60394b
--- /dev/null
+++ b/BusLane.Tests/Views/AlertsDialogTests.cs
@@ -0,0 +1,32 @@
+namespace BusLane.Tests.Views;
+
+using FluentAssertions;
+
+public class AlertsDialogTests
+{
+ [Fact]
+ public void AlertsDialog_UsesSharedDialogScaffold()
+ {
+ // Arrange
+ var xaml = File.ReadAllText(GetDialogPath());
+
+ // Assert
+ xaml.Should().Contain("Classes=\"dialog-header\"");
+ xaml.Should().Contain("Classes=\"dialog-body\"");
+ xaml.Should().Contain("Classes=\"dialog-footer\"");
+ }
+
+ private static string GetDialogPath()
+ {
+ return Path.GetFullPath(Path.Combine(
+ AppContext.BaseDirectory,
+ "..",
+ "..",
+ "..",
+ "..",
+ "BusLane",
+ "Views",
+ "Dialogs",
+ "AlertsDialog.axaml"));
+ }
+}
diff --git a/BusLane.Tests/Views/AppThemeResourceTests.cs b/BusLane.Tests/Views/AppThemeResourceTests.cs
new file mode 100644
index 0000000..b773715
--- /dev/null
+++ b/BusLane.Tests/Views/AppThemeResourceTests.cs
@@ -0,0 +1,67 @@
+namespace BusLane.Tests.Views;
+
+using FluentAssertions;
+
+public class AppThemeResourceTests
+{
+ [Fact]
+ public void AppResources_DefineSharedDashboardSurfaceTokens()
+ {
+ // Arrange
+ var xaml = File.ReadAllText(GetAppPath());
+
+ // Assert
+ xaml.Should().Contain("x:Key=\"LayerBackground\"");
+ xaml.Should().Contain("x:Key=\"DashboardTileBackground\"");
+ xaml.Should().Contain("x:Key=\"AccentBrandSubtle\"");
+ }
+
+ [Fact]
+ public void AppStyles_DefineSharedToggleAndMenuStyles()
+ {
+ // Arrange
+ var xaml = File.ReadAllText(GetStylesPath());
+
+ // Assert
+ xaml.Should().Contain("".Length)];
}
+
+ private static bool HasClass(XElement element, string className)
+ {
+ var classes = element.Attribute("Classes")?.Value;
+ return classes?
+ .Split(' ', StringSplitOptions.RemoveEmptyEntries)
+ .Contains(className, StringComparer.Ordinal) == true;
+ }
}
diff --git a/BusLane.Tests/Views/ConnectionLibraryDialogTests.cs b/BusLane.Tests/Views/ConnectionLibraryDialogTests.cs
new file mode 100644
index 0000000..d57339b
--- /dev/null
+++ b/BusLane.Tests/Views/ConnectionLibraryDialogTests.cs
@@ -0,0 +1,99 @@
+namespace BusLane.Tests.Views;
+
+using FluentAssertions;
+
+public class ConnectionLibraryDialogTests
+{
+ [Fact]
+ public void ConnectionLibraryDialog_UsesSharedDialogRegions()
+ {
+ // Arrange
+ var xaml = File.ReadAllText(GetDialogPath());
+
+ // Assert
+ xaml.Should().Contain("Classes=\"dialog-header\"");
+ xaml.Should().Contain("Classes=\"dialog-body\"");
+ }
+
+ [Fact]
+ public void ConnectionLibraryDialog_SeparatesQuickActionsFromFormSurface()
+ {
+ // Arrange
+ var xaml = File.ReadAllText(GetDialogPath());
+
+ // Assert
+ xaml.Should().Contain("Classes=\"connection-library-command-bar\"");
+ xaml.Should().NotContain("Background=\"{DynamicResource SurfaceSubtle}\"");
+ }
+
+ [Fact]
+ public void ConnectionLibraryDialog_LeftAlignsBackupPassphraseSection()
+ {
+ // Arrange
+ var xaml = File.ReadAllText(GetDialogPath());
+ var passphraseIndex = xaml.IndexOf("Text=\"Backup passphrase\"", StringComparison.Ordinal);
+
+ // Assert
+ passphraseIndex.Should().BeGreaterThanOrEqualTo(0);
+
+ // Act
+ var blockStart = xaml.LastIndexOf("");
+ }
+
+ [Fact]
+ public void EntityTreeViews_UseSharedSearchSurfaceClass()
+ {
+ // Assert
+ File.ReadAllText(GetConnectionTreePath()).Should().Contain("Classes=\"pane-search-surface\"");
+ File.ReadAllText(GetAzureTreePath()).Should().Contain("Classes=\"pane-search-surface\"");
+ }
+
+ private static string GetStylesPath()
+ {
+ return Path.GetFullPath(Path.Combine(
+ AppContext.BaseDirectory,
+ "..",
+ "..",
+ "..",
+ "..",
+ "BusLane",
+ "Styles",
+ "AppStyles.axaml"));
+ }
+
+ private static string GetConnectionTreePath()
+ {
+ return Path.GetFullPath(Path.Combine(
+ AppContext.BaseDirectory,
+ "..",
+ "..",
+ "..",
+ "..",
+ "BusLane",
+ "Views",
+ "Controls",
+ "EntityTreeView.axaml"));
+ }
+
+ private static string GetAzureTreePath()
+ {
+ return Path.GetFullPath(Path.Combine(
+ AppContext.BaseDirectory,
+ "..",
+ "..",
+ "..",
+ "..",
+ "BusLane",
+ "Views",
+ "Controls",
+ "AzureEntityTreeView.axaml"));
+ }
+}
diff --git a/BusLane.Tests/Views/MessagesPanelViewTests.cs b/BusLane.Tests/Views/MessagesPanelViewTests.cs
new file mode 100644
index 0000000..f08d7e3
--- /dev/null
+++ b/BusLane.Tests/Views/MessagesPanelViewTests.cs
@@ -0,0 +1,69 @@
+namespace BusLane.Tests.Views;
+
+using FluentAssertions;
+
+public class MessagesPanelViewTests
+{
+ [Fact]
+ public void MessagesPanel_UsesInlineCommandBarSurface()
+ {
+ // Arrange
+ var xaml = File.ReadAllText(GetMessagesPanelPath());
+
+ // Assert
+ xaml.Should().Contain("Classes=\"message-command-bar\"");
+ xaml.Should().Contain("Classes=\"message-search-surface\"");
+ }
+
+ [Fact]
+ public void MessagesPanel_DoesNotUseCenteredLoadingCardCopy()
+ {
+ // Arrange
+ var xaml = File.ReadAllText(GetMessagesPanelPath());
+
+ // Assert
+ xaml.Should().NotContain("Please wait while we fetch the messages...");
+ xaml.Should().Contain("Classes=\"inline-loading-surface\"");
+ }
+
+ [Fact]
+ public void MessagesPanel_DisablesMessageListsWhileLoading()
+ {
+ // Arrange
+ var xaml = File.ReadAllText(GetMessagesPanelPath());
+
+ // Act
+ var disabledListCount = CountOccurrences(xaml, "IsEnabled=\"{Binding !CurrentMessageOps.IsLoadingMessages}\"");
+
+ // Assert
+ disabledListCount.Should().Be(2);
+ }
+
+ private static string GetMessagesPanelPath()
+ {
+ return Path.GetFullPath(Path.Combine(
+ AppContext.BaseDirectory,
+ "..",
+ "..",
+ "..",
+ "..",
+ "BusLane",
+ "Views",
+ "Controls",
+ "MessagesPanelView.axaml"));
+ }
+
+ private static int CountOccurrences(string text, string value)
+ {
+ var count = 0;
+ var index = 0;
+
+ while ((index = text.IndexOf(value, index, StringComparison.Ordinal)) >= 0)
+ {
+ count++;
+ index += value.Length;
+ }
+
+ return count;
+ }
+}
diff --git a/BusLane.Tests/Views/NamespaceDashboardViewTests.cs b/BusLane.Tests/Views/NamespaceDashboardViewTests.cs
new file mode 100644
index 0000000..cfb1874
--- /dev/null
+++ b/BusLane.Tests/Views/NamespaceDashboardViewTests.cs
@@ -0,0 +1,116 @@
+namespace BusLane.Tests.Views;
+
+using FluentAssertions;
+
+public class NamespaceDashboardViewTests
+{
+ [Fact]
+ public void Dashboard_UsesDefinedSurfaceTokens()
+ {
+ // Arrange
+ var appXaml = File.ReadAllText(GetAppPath());
+ var stylesXaml = File.ReadAllText(GetStylesPath());
+
+ // Assert
+ appXaml.Should().Contain("x:Key=\"LayerBackground\"");
+ appXaml.Should().Contain("x:Key=\"DashboardTileBackground\"");
+ stylesXaml.Should().Contain("
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
@@ -1286,6 +1599,28 @@
+
+
+
+
+
+
diff --git a/BusLane/Views/Controls/AzureEntityTreeView.axaml b/BusLane/Views/Controls/AzureEntityTreeView.axaml
index d2ead32..62462bc 100644
--- a/BusLane/Views/Controls/AzureEntityTreeView.axaml
+++ b/BusLane/Views/Controls/AzureEntityTreeView.axaml
@@ -15,36 +15,35 @@
-
-
-
-
-
-
+ Classes="pane-search-surface">
+
+
+
+
+
+
+
+
-
-
+
+
+
@@ -53,31 +52,33 @@
IsExpanded="{Binding CurrentNavigation.IsQueuesSectionExpanded}"
Margin="4,2,4,0">
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
@@ -193,31 +194,33 @@
IsExpanded="{Binding CurrentNavigation.IsTopicsSectionExpanded}"
Margin="4,0,4,0">
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
diff --git a/BusLane/Views/Controls/EntityTreeView.axaml b/BusLane/Views/Controls/EntityTreeView.axaml
index 8615ac4..27df978 100644
--- a/BusLane/Views/Controls/EntityTreeView.axaml
+++ b/BusLane/Views/Controls/EntityTreeView.axaml
@@ -15,36 +15,35 @@
-
-
-
-
-
-
+ Classes="pane-search-surface">
+
+
+
+
+
+
+
+
-
-
+
+
+
@@ -54,31 +53,33 @@
IsExpanded="{Binding CurrentNavigation.IsQueuesSectionExpanded}"
Margin="4,2,4,0">
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
@@ -196,31 +197,33 @@
IsExpanded="{Binding CurrentNavigation.IsTopicsSectionExpanded}"
Margin="4,0,4,0">
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
diff --git a/BusLane/Views/Controls/MessagePaginationFooterView.axaml b/BusLane/Views/Controls/MessagePaginationFooterView.axaml
index 0cf6fc8..5484895 100644
--- a/BusLane/Views/Controls/MessagePaginationFooterView.axaml
+++ b/BusLane/Views/Controls/MessagePaginationFooterView.axaml
@@ -6,9 +6,9 @@
@@ -28,18 +28,18 @@
diff --git a/BusLane/Views/Controls/MessagesPanelView.axaml b/BusLane/Views/Controls/MessagesPanelView.axaml
index d0af194..80f09a4 100644
--- a/BusLane/Views/Controls/MessagesPanelView.axaml
+++ b/BusLane/Views/Controls/MessagesPanelView.axaml
@@ -14,7 +14,7 @@
-
+
@@ -94,11 +94,7 @@
+ Classes="message-search-surface">
@@ -159,9 +155,7 @@
-
-
+
+
+
+
+
+
+
+
@@ -235,12 +245,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -341,13 +317,29 @@
-
-
+
+
+
+
+
+
+
+
+ SelectedItem="{Binding CurrentMessageOps.SelectedMessage}"
+ IsEnabled="{Binding !CurrentMessageOps.IsLoadingMessages}"
+ Background="Transparent"
+ Padding="8"
+ ScrollViewer.HorizontalScrollBarVisibility="Disabled">
-
-
-
-
-
-
-
+
-
+
@@ -146,9 +114,8 @@
-
+
+
+
+
+
diff --git a/BusLane/Views/Dialogs/AlertsDialog.axaml b/BusLane/Views/Dialogs/AlertsDialog.axaml
index c9490f9..22ec85a 100644
--- a/BusLane/Views/Dialogs/AlertsDialog.axaml
+++ b/BusLane/Views/Dialogs/AlertsDialog.axaml
@@ -15,9 +15,7 @@
+ Classes="dialog-header">
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
@@ -245,7 +241,7 @@
-
@@ -393,7 +389,7 @@
-
@@ -476,11 +472,9 @@
-
@@ -537,7 +531,7 @@
-
+
+ Classes="dialog-footer">
diff --git a/BusLane/Views/Dialogs/ConnectionLibraryDialog.axaml b/BusLane/Views/Dialogs/ConnectionLibraryDialog.axaml
index 4265cd1..39b92a0 100644
--- a/BusLane/Views/Dialogs/ConnectionLibraryDialog.axaml
+++ b/BusLane/Views/Dialogs/ConnectionLibraryDialog.axaml
@@ -13,27 +13,32 @@
-
-
+
+ Classes="dialog-header">
-
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -104,263 +128,254 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+ Margin="0,4,0,0">
-
-
+
-
-
+
-
+
-
-
+
+
-
-
+
+
-
-
-
+
+
-
diff --git a/BusLane/Views/Dialogs/SendMessageDialog.axaml b/BusLane/Views/Dialogs/SendMessageDialog.axaml
index a473b6a..f3173bb 100644
--- a/BusLane/Views/Dialogs/SendMessageDialog.axaml
+++ b/BusLane/Views/Dialogs/SendMessageDialog.axaml
@@ -12,130 +12,131 @@
HorizontalAlignment="Center"
Width="900"
MaxHeight="760">
-
+
-
-
-
-
-
-
-
-
-
-
+ Classes="dialog-header">
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
-
-
-
+
-
-
-
-
+
+
+
+
+
@@ -158,27 +159,29 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
@@ -339,12 +342,12 @@
-
-
+
+
-
-
-
+
+
+
@@ -409,17 +412,14 @@
-
-
-
+
+
+
+
+ Classes="dialog-footer">
@@ -44,11 +45,12 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
@@ -222,7 +225,7 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+