Skip to content

Commit 6ceab40

Browse files
committed
bb-avnui: update Avalonia-based Bitbucket UI
Update the Avalonia-based UI for Bitbucket authentication to use a tabbed interface, showing each authentication mode in a separate tab. The new "credentials" prompt can offer and serve all authentication modes in a simpler way that pushes users who can to authenticate using a more secure method (where we don't capture the user/pass).
1 parent d4fcfb7 commit 6ceab40

File tree

9 files changed

+104
-133
lines changed

9 files changed

+104
-133
lines changed

src/shared/Atlassian.Bitbucket.UI.Avalonia/Commands/OAuthCommandImpl.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/shared/Atlassian.Bitbucket.UI.Avalonia/Controls/TesterWindow.axaml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,24 @@
66
x:Class="Atlassian.Bitbucket.UI.Controls.TesterWindow"
77
Title="Bitbucket Authentication Dialog Tester"
88
Height="240" Width="420" CanResize="False">
9-
<DockPanel>
10-
<Button Content="Show Credentials Dialog" Padding="10" Click="ShowCredentials" />
11-
<Button Content="Show OAuth Dialog" Padding="10" Click="ShowOAuth" />
12-
</DockPanel>
9+
<StackPanel Margin="10">
10+
<Grid RowDefinitions="Auto,Auto,Auto" ColumnDefinitions="Auto,*">
11+
<Label Grid.Row="0" Grid.Column="0"
12+
Content="Auth Modes" />
13+
<StackPanel Grid.Row="0" Grid.Column="1"
14+
Orientation="Horizontal" VerticalAlignment="Center">
15+
<CheckBox Content="OAuth" x:Name="showOAuth" MinWidth="90" IsChecked="True" />
16+
<CheckBox Content="Basic" x:Name="showBasic" MinWidth="80" IsChecked="True" />
17+
</StackPanel>
18+
<Label Grid.Row="1" Grid.Column="0"
19+
Content="URL" />
20+
<TextBox Grid.Row="1" Grid.Column="1"
21+
x:Name="url" />
22+
<Label Grid.Row="2" Grid.Column="0"
23+
Content="Username" />
24+
<TextBox Grid.Row="2" Grid.Column="1"
25+
x:Name="username" />
26+
</Grid>
27+
<Button Classes="accent" Content="Show" Click="ShowCredentials" />
28+
</StackPanel>
1329
</Window>

src/shared/Atlassian.Bitbucket.UI.Avalonia/Controls/TesterWindow.axaml.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using Atlassian.Bitbucket.UI.ViewModels;
23
using Atlassian.Bitbucket.UI.Views;
34
using Avalonia;
@@ -53,17 +54,17 @@ private void ShowCredentials(object sender, RoutedEventArgs e)
5354
{
5455
var vm = new CredentialsViewModel(_environment)
5556
{
56-
ShowOAuth = true
57+
ShowOAuth = this.FindControl<CheckBox>("showOAuth").IsChecked ?? false,
58+
ShowBasic = this.FindControl<CheckBox>("showBasic").IsChecked ?? false,
59+
UserName = this.FindControl<TextBox>("username").Text
5760
};
58-
var view = new CredentialsView();
59-
var window = new DialogWindow(view) {DataContext = vm};
60-
window.ShowDialog(this);
61-
}
6261

63-
private void ShowOAuth(object sender, RoutedEventArgs e)
64-
{
65-
var vm = new OAuthViewModel(_environment);
66-
var view = new OAuthView();
62+
if (Uri.TryCreate(this.FindControl<TextBox>("url").Text, UriKind.Absolute, out Uri uri))
63+
{
64+
vm.Url = uri;
65+
}
66+
67+
var view = new CredentialsView();
6768
var window = new DialogWindow(view) {DataContext = vm};
6869
window.ShowDialog(this);
6970
}

src/shared/Atlassian.Bitbucket.UI.Avalonia/Program.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ private static void AppMain(object o)
5050
using (var app = new HelperApplication(context))
5151
{
5252
app.RegisterCommand(new CredentialsCommandImpl(context));
53-
app.RegisterCommand(new OAuthCommandImpl(context));
5453

5554
int exitCode = app.RunAsync(args)
5655
.ConfigureAwait(false)

src/shared/Atlassian.Bitbucket.UI.Avalonia/Views/CredentialsView.axaml

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,79 @@
33
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
44
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
55
xmlns:vm="clr-namespace:Atlassian.Bitbucket.UI.ViewModels;assembly=Atlassian.Bitbucket.UI.Shared"
6+
xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcoreuiavn"
67
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
78
x:Class="Atlassian.Bitbucket.UI.Views.CredentialsView">
89
<Design.DataContext>
910
<vm:CredentialsViewModel/>
1011
</Design.DataContext>
1112
<DockPanel LastChildFill="True">
1213
<StackPanel DockPanel.Dock="Bottom">
13-
<Button HorizontalAlignment="Center" Margin="0,30,0,10"
14+
<Button HorizontalAlignment="Center" Margin="0,0,0,10"
1415
Classes="hyperlink"
1516
Command="{Binding ForgotPasswordCommand}"
1617
Content="Can't log in?"/>
17-
<Button HorizontalAlignment="Center" Margin="0,0,0,10"
18+
<Button HorizontalAlignment="Center" Margin="0,0,0,8"
1819
Classes="hyperlink"
1920
Command="{Binding SignUpCommand}"
2021
Content="Sign up for an account" />
2122
</StackPanel>
2223

23-
<StackPanel DockPanel.Dock="Top" Margin="0,0,0,30">
24-
<Image HorizontalAlignment="Center" Source="/Assets/atlassian-logo.png" />
25-
<TextBlock HorizontalAlignment="Center" Text="Log in to your account"/>
24+
<StackPanel DockPanel.Dock="Top">
25+
<Image HorizontalAlignment="Center" Source="/Assets/atlassian-logo.png" Height="90" />
26+
<TextBlock HorizontalAlignment="Center" Text="Log in to your account" Margin="0,-10,0,0" />
2627
<TextBlock HorizontalAlignment="Center" Text="{Binding Url}"
2728
IsVisible="{Binding Url, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
2829
Margin="0,10,0,0"/>
2930
</StackPanel>
3031

31-
<StackPanel Width="288">
32-
<TextBox x:Name="userNameTextBox" Margin="0,0,0,10"
33-
HorizontalAlignment="Stretch"
34-
Watermark="Email or username"
35-
Text="{Binding UserName}" />
36-
<TextBox x:Name="passwordTextBox" Margin="0,0,0,20"
37-
HorizontalAlignment="Stretch"
38-
Watermark="Password" PasswordChar=""
39-
Text="{Binding Password}" />
40-
<Button IsDefault="True" Margin="0,0,0,10"
41-
HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
42-
Command="{Binding LoginCommand}"
43-
Content="Continue" Width="140" Height="40"
44-
Classes="accent" />
45-
<Button HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
46-
IsVisible="{Binding ShowOAuth}"
47-
Command="{Binding OAuthCommand}"
48-
Classes="hyperlink"
49-
Content="Sign in with OAuth" />
50-
</StackPanel>
32+
<TabControl x:Name="authModesTabControl"
33+
VerticalContentAlignment="Center"
34+
AutoScrollToSelectedItem="True"
35+
Width="288"
36+
Margin="0,20">
37+
<TabControl.Styles>
38+
<Style Selector="TabItem">
39+
<Setter Property="MinHeight" Value="30" />
40+
</Style>
41+
<Style Selector="DockPanel > ItemsPresenter > WrapPanel">
42+
<Setter Property="HorizontalAlignment" Value="Center"/>
43+
</Style>
44+
</TabControl.Styles>
45+
46+
<TabItem IsVisible="{Binding ShowOAuth}">
47+
<TabItem.Header>
48+
<TextBlock Text="Browser" FontSize="12" />
49+
</TabItem.Header>
50+
<StackPanel Margin="0,15">
51+
<Button x:Name="oauthLoginButton" IsDefault="True"
52+
HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
53+
Command="{Binding OAuthCommand}"
54+
Classes="accent" Height="40" Padding="15,5"
55+
Content="Sign in with your browser" />
56+
</StackPanel>
57+
</TabItem>
58+
59+
<TabItem IsVisible="{Binding ShowBasic}">
60+
<TabItem.Header>
61+
<TextBlock Text="Password/Token" FontSize="12" />
62+
</TabItem.Header>
63+
<StackPanel Margin="0,15">
64+
<TextBox x:Name="userNameTextBox" Margin="0,0,0,10"
65+
HorizontalAlignment="Stretch"
66+
Watermark="Email or username"
67+
Text="{Binding UserName}" />
68+
<TextBox x:Name="passwordTextBox" Margin="0,0,0,10"
69+
HorizontalAlignment="Stretch"
70+
Watermark="Password or token" PasswordChar=""
71+
Text="{Binding Password}" />
72+
<Button IsDefault="True"
73+
HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
74+
Command="{Binding LoginCommand}"
75+
Content="Sign in" Width="140" Height="40"
76+
Classes="accent" />
77+
</StackPanel>
78+
</TabItem>
79+
</TabControl>
5180
</DockPanel>
5281
</UserControl>

src/shared/Atlassian.Bitbucket.UI.Avalonia/Views/CredentialsView.axaml.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ namespace Atlassian.Bitbucket.UI.Views
77
{
88
public class CredentialsView : UserControl, IFocusable
99
{
10+
private TabControl _tabControl;
11+
private Button _oauthLoginButton;
1012
private TextBox _userNameTextBox;
1113
private TextBox _passwordTextBox;
1214

@@ -19,6 +21,8 @@ private void InitializeComponent()
1921
{
2022
AvaloniaXamlLoader.Load(this);
2123

24+
_tabControl = this.FindControl<TabControl>("authModesTabControl");
25+
_oauthLoginButton = this.FindControl<Button>("oauthLoginButton");
2226
_userNameTextBox = this.FindControl<TextBox>("userNameTextBox");
2327
_passwordTextBox = this.FindControl<TextBox>("passwordTextBox");
2428
}
@@ -30,13 +34,22 @@ public void SetFocus()
3034
return;
3135
}
3236

33-
if (string.IsNullOrWhiteSpace(vm.UserName))
37+
if (vm.ShowOAuth)
3438
{
35-
_userNameTextBox.Focus();
39+
_tabControl.SelectedIndex = 0;
40+
_oauthLoginButton.Focus();
3641
}
37-
else
42+
else if (vm.ShowBasic)
3843
{
39-
_passwordTextBox.Focus();
44+
_tabControl.SelectedIndex = 1;
45+
if (string.IsNullOrWhiteSpace(vm.UserName))
46+
{
47+
_userNameTextBox.Focus();
48+
}
49+
else
50+
{
51+
_passwordTextBox.Focus();
52+
}
4053
}
4154
}
4255
}

src/shared/Atlassian.Bitbucket.UI.Avalonia/Views/OAuthView.axaml

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/shared/Atlassian.Bitbucket.UI.Avalonia/Views/OAuthView.axaml.cs

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/shared/Core.UI.Avalonia/Converters/BoolConvertersEx.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ public static class BoolConvertersEx
77
{
88
public static readonly IMultiValueConverter Or =
99
new FuncMultiValueConverter<bool,bool>(x => x.Aggregate(false, (a, b) => a || b));
10+
11+
public static readonly IMultiValueConverter And =
12+
new FuncMultiValueConverter<bool,bool>(x => x.Aggregate(true, (a, b) => a && b));
1013
}
1114
}

0 commit comments

Comments
 (0)