Server configuration list in DataGrid.

Sorting already works out of the box.
This commit is contained in:
eelke 2025-10-26 17:13:31 +01:00
parent 26259543b3
commit 4b8a346cfb
9 changed files with 87 additions and 75 deletions

View file

@ -23,7 +23,7 @@ public sealed class ConnectionStringService : IConnectionStringService
public static ConnectionStringService CreateDefault()
=> new(new IConnectionStringCodec[] { new LibpqCodec(), new NpgsqlCodec(), new UrlCodec(), new JdbcCodec() });
public Result<ConnStringFormat> DetectFormat(string input)
public Result<ConnStringFormat> DetectFormat(string? input)
{
if (string.IsNullOrWhiteSpace(input))
return Result.Fail<ConnStringFormat>("Empty input");

View file

@ -8,11 +8,11 @@ namespace pgLabII.PgUtils.ConnectionStrings;
/// </summary>
public interface IConnectionStringService
{
Result<ConnStringFormat> DetectFormat(string input);
Result<ConnStringFormat> DetectFormat(string? input);
Result<ConnectionDescriptor> ParseToDescriptor(string input);
Result<string> FormatFromDescriptor(ConnectionDescriptor descriptor, ConnStringFormat targetFormat);
Result<string> Convert(string input, ConnStringFormat targetFormat);
}
}

View file

@ -39,7 +39,7 @@ namespace pgLabII.Migrations
b.HasKey("Id");
b.ToTable("Documents");
b.ToTable("Documents", (string)null);
});
modelBuilder.Entity("pgLabII.Model.EditHistoryEntry", b =>
@ -69,7 +69,7 @@ namespace pgLabII.Migrations
b.HasIndex("DocumentId", "Timestamp");
b.ToTable("EditHistory");
b.ToTable("EditHistory", (string)null);
});
modelBuilder.Entity("pgLabII.Model.ServerConfigurationEntity", b =>
@ -112,7 +112,7 @@ namespace pgLabII.Migrations
b.HasKey("Id");
b.ToTable("ServerConfigurations");
b.ToTable("ServerConfigurations", (string)null);
});
modelBuilder.Entity("pgLabII.Model.EditHistoryEntry", b =>

View file

@ -14,6 +14,5 @@ public class ServerConfigurationEntity
public bool ColorEnabled { get; set; } = true;
public int ColorArgb { get; set; } = unchecked((int)0xFF_33_33_33); // default dark gray
public string UserName { get; set; } = "";
public string Password { get; set; } = "";
public string Password { get; set; } = "";
}

View file

@ -28,14 +28,14 @@ public partial class EditServerConfigurationViewModel : ViewModelBase
public ServerConfigurationViewModel Configuration { get; set; }
// Connection string IO
[Reactive] public partial string InputConnectionString { get; set; }
[Reactive] public partial string? InputConnectionString { get; set; }
[Reactive] public partial ForcedFormatOption ForcedFormat { get; set; }
[ObservableAsProperty] private ConnStringFormat? _detectedFormat;
[Reactive] public partial ConnStringFormat OutputFormat { get; set; }
[Reactive] public partial string OutputConnectionString { get; set; }
[Reactive] public partial string? OutputConnectionString { get; set; }
public ReactiveCommand<Unit, Unit> ParseConnectionStringCommand { get; }
public ReactiveCommand<Unit, Unit> GenerateConnectionStringCommand { get; }
@ -69,7 +69,7 @@ public partial class EditServerConfigurationViewModel : ViewModelBase
InitializeFromCopy();
}
private ConnStringFormat? DetectFormat(ForcedFormatOption format, string input)
private ConnStringFormat? DetectFormat(ForcedFormatOption format, string? input)
{
if (format != ForcedFormatOption.Auto)
return null;

View file

@ -3,11 +3,12 @@ using Avalonia.Media;
using Npgsql;
using pgLabII.Model;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
namespace pgLabII.ViewModels;
// UI ViewModel that wraps the persistence entity
public class ServerConfigurationViewModel : ReactiveObject
public partial class ServerConfigurationViewModel : ReactiveObject
{
private readonly ServerConfigurationEntity _entity;
@ -16,7 +17,7 @@ public class ServerConfigurationViewModel : ReactiveObject
_entity = entity ?? throw new ArgumentNullException(nameof(entity));
EditCommand = ReactiveCommand.Create(() =>
{
var window = new Views.EditServerConfigurationWindow(new(this)) { New = false };
var window = new Views.EditServerConfigurationWindow(new(this));
window.Show();
});
ExploreCommand = ReactiveCommand.Create(() =>
@ -24,6 +25,10 @@ public class ServerConfigurationViewModel : ReactiveObject
var window = new Views.SingleDatabaseWindow(entity);
window.Show();
});
_backgroundBrushHelper = this.WhenAnyValue(x => x.ColorEnabled, x => x.Color,
(enabled, color) => enabled ? new SolidColorBrush(color) : null)
.ToProperty(this, x => x.BackgroundBrush);
}
public ServerConfigurationEntity Entity => _entity;
@ -67,7 +72,7 @@ public class ServerConfigurationViewModel : ReactiveObject
public bool ColorEnabled
{
get => _entity.ColorEnabled;
set { if (_entity.ColorEnabled != value) { _entity.ColorEnabled = value; this.RaisePropertyChanged(); this.RaisePropertyChanged(nameof(BackgroundBrush)); } }
set { if (_entity.ColorEnabled != value) { _entity.ColorEnabled = value; this.RaisePropertyChanged(); } }
}
public Color Color
@ -80,12 +85,12 @@ public class ServerConfigurationViewModel : ReactiveObject
{
_entity.ColorArgb = argb;
this.RaisePropertyChanged();
this.RaisePropertyChanged(nameof(BackgroundBrush));
}
}
}
public IBrush? BackgroundBrush => ColorEnabled ? new SolidColorBrush(Color) : null;
//public IBrush? BackgroundBrush => ColorEnabled ? new SolidColorBrush(Color) : null;
[ObservableAsProperty] private IBrush? _backgroundBrush;
public string UserName
{
@ -115,6 +120,7 @@ public class ServerConfigurationViewModel : ReactiveObject
}
}
public ReactiveCommand<Unit, Unit> EditCommand { get; }
public ReactiveCommand<Unit, Unit> ExploreCommand { get; }

View file

@ -3,11 +3,14 @@ using ReactiveUI;
using System.Reactive;
using Avalonia.Media;
using pgLabII.Views;
using ReactiveUI.SourceGenerators;
namespace pgLabII.ViewModels;
public class ServerListViewModel : ViewModelBase
public partial class ServerListViewModel : ViewModelBase
{
[Reactive] public partial ServerConfigurationViewModel? SelectedServerConfiguration { get; set; }
public ObservableCollection<ServerConfigurationViewModel> ServerConfigurations { get; } =
[
new (new()
@ -18,7 +21,7 @@ public class ServerListViewModel : ViewModelBase
Port = 5418,
InitialDatabase = "postgres",
UserName = "postgres",
Password = "admin",
Password = "admin"
})
{
Color = Colors.Aquamarine,
@ -31,22 +34,48 @@ public class ServerListViewModel : ViewModelBase
}),
];
public ReactiveCommand<ServerConfigurationViewModel, Unit> RemoveServerCommand { get; }
public ReactiveCommand<ServerConfigurationViewModel?, Unit> ExploreServerCommand { get; }
public ReactiveCommand<ServerConfigurationViewModel?, Unit> EditServerCommand { get; }
public ReactiveCommand<ServerConfigurationViewModel?, Unit> RemoveServerCommand { get; }
public ReactiveCommand<Unit, Unit> AddServerCommand { get; }
public ServerListViewModel()
{
RemoveServerCommand = ReactiveCommand.Create<ServerConfigurationViewModel, Unit>((sc) =>
ExploreServerCommand = ReactiveCommand.Create<ServerConfigurationViewModel?, Unit>((sc) =>
{
ServerConfigurations.Remove(sc);
var conf = sc ?? SelectedServerConfiguration;
if (conf is null)
return Unit.Default;
var window = new Views.SingleDatabaseWindow(conf.Entity);
window.Show();
return Unit.Default;
});
EditServerCommand = ReactiveCommand.Create<ServerConfigurationViewModel?, Unit>((sc) =>
{
var conf = sc ?? SelectedServerConfiguration;
if (conf is null)
return Unit.Default;
EditServerConfigurationWindow window = new(new(conf));
window.Show();
return Unit.Default;
});
RemoveServerCommand = ReactiveCommand.Create<ServerConfigurationViewModel?, Unit>((sc) =>
{
var conf = sc ?? SelectedServerConfiguration;
if (conf is null)
return Unit.Default;
ServerConfigurations.Remove(conf);
return Unit.Default;
});
AddServerCommand = ReactiveCommand.Create(() =>
{
EditServerConfigurationViewModel vm = new();
EditServerConfigurationWindow window = new() { DataContext = vm, New = true };
EditServerConfigurationWindow window = new(new());
window.Show();
});
}

View file

@ -32,6 +32,5 @@ public partial class EditServerConfigurationWindow : ReactiveWindow<EditServerCo
});
}
public bool New { get; set; }
}

View file

@ -15,56 +15,35 @@
</Design.DataContext>
<StackPanel x:Name="ServerList" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid ColumnDefinitions="Auto,*,Auto">
<Button Grid.Column="2" Content="+" Command="{Binding AddServerCommand}"/>
</Grid>
<ListBox x:Name="Servers" ItemsSource="{Binding ServerConfigurations}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="{Binding BackgroundBrush}" BorderThickness="2">
<Grid ColumnDefinitions="*,*">
<StackPanel
Orientation="Vertical"
HorizontalAlignment="Stretch"
Grid.Row="0"
Grid.Column="0">
<TextBlock Text="{Binding Name}" FontSize="18" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Host}" />
<TextBlock Text=":" />
<TextBlock Text="{Binding Port}" />
<TextBlock Text="/" />
<TextBlock Text="{Binding InitialDatabase}" />
</StackPanel>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Stretch"
VerticalAlignment="Top">
<Button Content="New"
Command="{Binding AddServerCommand}"/>
<Button Content="Edit"
Command="{Binding EditServerCommand}"/>
<Button Content="Open"
Command="{Binding ExploreServerCommand}"/>
</StackPanel>
<DataGrid ItemsSource="{Binding ServerConfigurations}"
SelectedItem="{Binding SelectedServerConfiguration, Mode=TwoWay}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AutoGenerateColumns="False"
IsReadOnly="True"
GridLinesVisibility="All"
BorderThickness="1">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTextColumn Header="Host" Binding="{Binding Host}" />
<DataGridTextColumn Header="Port" Binding="{Binding Port}" />
<DataGridTextColumn Header="Db" Binding="{Binding InitialDatabase}" />
<DataGridTextColumn Header="User" Binding="{Binding UserName}" />
<DataGridTextColumn Header="SSL" Binding="{Binding DefaultSslMode}" />
</DataGrid.Columns>
</StackPanel>
<StackPanel
Orientation="Horizontal"
HorizontalAlignment="Right"
Grid.Row="0"
Grid.Column="1">
<Button Command="{Binding ExploreCommand}">
DB
</Button>
<Button>Server</Button>
<Button Content="...">
<Button.Flyout>
<MenuFlyout>
<MenuItem Header="Edit" Command="{Binding EditCommand}" />
<Separator />
<MenuItem Header="Remove"
Command="{Binding #ServerList.((vm:ServerListViewModel)DataContext).RemoveServerCommand}"
CommandParameter="{Binding .}"
Foreground="Crimson" />
</MenuFlyout>
</Button.Flyout>
</Button>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataGrid>
</StackPanel>
</UserControl>