Skip to content

Commit c7d5faa

Browse files
committed
gitlab: add Avalonia-based UI helper on Mac/Linux
Implement an Avalonia-based UI helper for GitLab and include this in Mac and Linux packages/installers.
1 parent d322402 commit c7d5faa

File tree

12 files changed

+455
-0
lines changed

12 files changed

+455
-0
lines changed

Git-Credential-Manager.sln

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitLab.Tests", "src\shared\
6565
EndProject
6666
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitLab.UI", "src\shared\GitLab.UI\GitLab.UI.csproj", "{9AFD88E2-7E2C-46DA-9D38-4342086426D3}"
6767
EndProject
68+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitLab.UI.Avalonia", "src\shared\GitLab.UI.Avalonia\GitLab.UI.Avalonia.csproj", "{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}"
69+
EndProject
6870
Global
6971
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7072
Debug|Any CPU = Debug|Any CPU
@@ -451,6 +453,22 @@ Global
451453
{9AFD88E2-7E2C-46DA-9D38-4342086426D3}.MacRelease|Any CPU.Build.0 = Release|Any CPU
452454
{9AFD88E2-7E2C-46DA-9D38-4342086426D3}.WindowsRelease|Any CPU.ActiveCfg = Release|Any CPU
453455
{9AFD88E2-7E2C-46DA-9D38-4342086426D3}.WindowsRelease|Any CPU.Build.0 = Release|Any CPU
456+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
457+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
458+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.MacDebug|Any CPU.ActiveCfg = Debug|Any CPU
459+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.MacDebug|Any CPU.Build.0 = Debug|Any CPU
460+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
461+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.Release|Any CPU.Build.0 = Release|Any CPU
462+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.WindowsDebug|Any CPU.ActiveCfg = Debug|Any CPU
463+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.WindowsDebug|Any CPU.Build.0 = Debug|Any CPU
464+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.LinuxDebug|Any CPU.ActiveCfg = Debug|Any CPU
465+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.LinuxDebug|Any CPU.Build.0 = Debug|Any CPU
466+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.LinuxRelease|Any CPU.ActiveCfg = Release|Any CPU
467+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.LinuxRelease|Any CPU.Build.0 = Release|Any CPU
468+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.MacRelease|Any CPU.ActiveCfg = Release|Any CPU
469+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.MacRelease|Any CPU.Build.0 = Release|Any CPU
470+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.WindowsRelease|Any CPU.ActiveCfg = Release|Any CPU
471+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE}.WindowsRelease|Any CPU.Build.0 = Release|Any CPU
454472
EndGlobalSection
455473
GlobalSection(SolutionProperties) = preSolution
456474
HideSolutionNode = FALSE
@@ -486,6 +504,7 @@ Global
486504
{570897DC-A85C-4598-B793-9A00CF710119} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
487505
{1AF9F7C5-FA2E-48F1-B216-4D5E9A27F393} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
488506
{9AFD88E2-7E2C-46DA-9D38-4342086426D3} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
507+
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
489508
EndGlobalSection
490509
GlobalSection(ExtensibilityGlobals) = postSolution
491510
SolutionGuid = {0EF9FC65-E6BA-45D4-A455-262A9EA4366B}

src/linux/Packaging.Linux/build.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ OUT="$ROOT/out"
4646
GCM_SRC="$SRC/shared/Git-Credential-Manager"
4747
BITBUCKET_UI_SRC="$SRC/shared/Atlassian.Bitbucket.UI.Avalonia"
4848
GITHUB_UI_SRC="$SRC/shared/GitHub.UI.Avalonia"
49+
GITLAB_UI_SRC="$SRC/shared/GitLab.UI.Avalonia"
4950
PROJ_OUT="$OUT/linux/Packaging.Linux"
5051

5152
# Build parameters
@@ -118,6 +119,15 @@ dotnet publish "$GITHUB_UI_SRC" \
118119
-p:PublishSingleFile=true \
119120
--output="$(make_absolute "$PAYLOAD")" || exit 1
120121

122+
echo "Publishing GitLab UI helper..."
123+
dotnet publish "$GITLAB_UI_SRC" \
124+
--configuration="$CONFIGURATION" \
125+
--framework="$FRAMEWORK" \
126+
--runtime="$RUNTIME" \
127+
--self-contained=true \
128+
-p:PublishSingleFile=true \
129+
--output="$(make_absolute "$PAYLOAD")" || exit 1
130+
121131
# Collect symbols
122132
echo "Collecting managed symbols..."
123133
mv "$PAYLOAD"/*.pdb "$SYMBOLOUT" || exit 1

src/osx/Installer.Mac/layout.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ INSTALLER_SRC="$SRC/osx/Installer.Mac"
2323
GCM_SRC="$SRC/shared/Git-Credential-Manager"
2424
BITBUCKET_UI_SRC="$SRC/shared/Atlassian.Bitbucket.UI.Avalonia"
2525
GITHUB_UI_SRC="$SRC/shared/GitHub.UI.Avalonia"
26+
GITLAB_UI_SRC="$SRC/shared/GitLab.UI.Avalonia"
2627

2728
# Build parameters
2829
FRAMEWORK=net5.0
@@ -99,6 +100,15 @@ dotnet publish "$GITHUB_UI_SRC" \
99100
--runtime="$RUNTIME" \
100101
--output="$(make_absolute "$PAYLOAD")" || exit 1
101102

103+
echo "Publishing GitLab UI helper..."
104+
dotnet publish "$GITLAB_UI_SRC" \
105+
--no-restore \
106+
-m:1 \
107+
--configuration="$CONFIGURATION" \
108+
--framework="$FRAMEWORK" \
109+
--runtime="$RUNTIME" \
110+
--output="$(make_absolute "$PAYLOAD")" || exit 1
111+
102112
# Collect symbols
103113
echo "Collecting managed symbols..."
104114
mv "$PAYLOAD"/*.pdb "$SYMBOLOUT" || exit 1

src/osx/SignFiles.Mac/SignFiles.Mac.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
$(OutDir)\GitHub.UI.dll;
2929
$(OutDir)\GitHub.UI.Shared.dll;
3030
$(OutDir)\GitLab.dll;
31+
$(OutDir)\GitLab.UI.dll;
3132
$(OutDir)\GitLab.UI.Shared.dll;
3233
$(OutDir)\Microsoft.AzureRepos.dll;
3334
$(OutDir)\gcmcore.dll;">
@@ -37,6 +38,7 @@
3738
<MacFilesToSign Include="
3839
$(OutDir)\git-credential-manager-core;
3940
$(OutDir)\GitHub.UI;
41+
$(OutDir)\GitLab.UI;
4042
$(OutDir)\Atlassian.Bitbucket.UI;">
4143
<InProject>false</InProject>
4244
</MacFilesToSign>
41.4 KB
Loading
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
using GitLab.UI.ViewModels;
4+
using GitLab.UI.Views;
5+
using GitCredentialManager;
6+
using GitCredentialManager.UI;
7+
8+
namespace GitLab.UI.Commands
9+
{
10+
public class CredentialsCommandImpl : CredentialsCommand
11+
{
12+
public CredentialsCommandImpl(ICommandContext context) : base(context) { }
13+
14+
protected override Task ShowAsync(CredentialsViewModel viewModel, CancellationToken ct)
15+
{
16+
return AvaloniaUi.ShowViewAsync<CredentialsView>(viewModel, GetParentHandle(), ct);
17+
}
18+
}
19+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<Window xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
x:Class="GitLab.UI.Controls.TesterWindow"
4+
CanResize="False" Width="550" SizeToContent="Height"
5+
Title="GitLab Authentication Dialog Tester">
6+
<TabControl Margin="5,10">
7+
<TabControl.Styles>
8+
<Style Selector="TabItem">
9+
<Setter Property="MinHeight" Value="30" />
10+
<Setter Property="FontSize" Value="12"/>
11+
</Style>
12+
<Style Selector="TabItem > StackPanel">
13+
<Setter Property="Margin" Value="0,10,0,0"/>
14+
</Style>
15+
<Style Selector="TabItem > StackPanel > Grid > Label">
16+
<Setter Property="VerticalAlignment" Value="Center" />
17+
<Setter Property="Margin" Value="0,0,10,0"/>
18+
</Style>
19+
<Style Selector="TabItem > StackPanel > Button">
20+
<Setter Property="Margin" Value="0,10,0,0" />
21+
<Setter Property="Padding" Value="14,10" />
22+
<Setter Property="HorizontalAlignment" Value="Right" />
23+
</Style>
24+
</TabControl.Styles>
25+
<TabItem Header="Credentials">
26+
<StackPanel>
27+
<Grid RowDefinitions="Auto,Auto,Auto" ColumnDefinitions="Auto,*">
28+
<Label Grid.Row="0" Grid.Column="0"
29+
Content="Auth Modes" />
30+
<StackPanel Grid.Row="0" Grid.Column="1"
31+
Orientation="Horizontal" VerticalAlignment="Center">
32+
<CheckBox Content="Browser" x:Name="useBrowser" MinWidth="90" IsChecked="True" />
33+
<CheckBox Content="PAT" x:Name="usePat" MinWidth="80" IsChecked="True" />
34+
<CheckBox Content="Basic" x:Name="useBasic" MinWidth="80" />
35+
</StackPanel>
36+
<Label Grid.Row="1" Grid.Column="0"
37+
Content="Instance URL" />
38+
<TextBox Grid.Row="1" Grid.Column="1"
39+
x:Name="instanceUrl" />
40+
<Label Grid.Row="2" Grid.Column="0"
41+
Content="Username" />
42+
<TextBox Grid.Row="2" Grid.Column="1"
43+
x:Name="username" />
44+
</Grid>
45+
<Button Classes="accent" Content="Show" Click="ShowCredentials" />
46+
</StackPanel>
47+
</TabItem>
48+
</TabControl>
49+
</Window>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System;
2+
using Avalonia;
3+
using Avalonia.Controls;
4+
using Avalonia.Interactivity;
5+
using Avalonia.Markup.Xaml;
6+
using GitLab.UI.ViewModels;
7+
using GitLab.UI.Views;
8+
using GitCredentialManager;
9+
using GitCredentialManager.Interop.Linux;
10+
using GitCredentialManager.Interop.MacOS;
11+
using GitCredentialManager.Interop.Posix;
12+
using GitCredentialManager.Interop.Windows;
13+
using GitCredentialManager.UI.Controls;
14+
15+
namespace GitLab.UI.Controls
16+
{
17+
public class TesterWindow : Window
18+
{
19+
private readonly IEnvironment _environment;
20+
21+
public TesterWindow()
22+
{
23+
InitializeComponent();
24+
#if DEBUG
25+
this.AttachDevTools();
26+
#endif
27+
28+
if (PlatformUtils.IsWindows())
29+
{
30+
_environment = new WindowsEnvironment(new WindowsFileSystem());
31+
}
32+
else
33+
{
34+
IFileSystem fs;
35+
if (PlatformUtils.IsMacOS())
36+
{
37+
fs = new MacOSFileSystem();
38+
}
39+
else
40+
{
41+
fs = new LinuxFileSystem();
42+
}
43+
44+
_environment = new PosixEnvironment(fs);
45+
}
46+
}
47+
48+
private void InitializeComponent()
49+
{
50+
AvaloniaXamlLoader.Load(this);
51+
}
52+
53+
private void ShowCredentials(object sender, RoutedEventArgs e)
54+
{
55+
var vm = new CredentialsViewModel(_environment)
56+
{
57+
ShowBrowserLogin = this.FindControl<CheckBox>("useBrowser").IsChecked ?? false,
58+
ShowTokenLogin = this.FindControl<CheckBox>("usePat").IsChecked ?? false,
59+
ShowBasicLogin = this.FindControl<CheckBox>("useBasic").IsChecked ?? false,
60+
Url = this.FindControl<TextBox>("instanceUrl").Text,
61+
UserName = this.FindControl<TextBox>("username").Text
62+
};
63+
var view = new CredentialsView();
64+
var window = new DialogWindow(view) {DataContext = vm};
65+
window.ShowDialog(this);
66+
}
67+
}
68+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>WinExe</OutputType>
5+
<TargetFramework>net5.0</TargetFramework>
6+
<RuntimeIdentifiers>osx-x64;linux-x64</RuntimeIdentifiers>
7+
<RootNamespace>GitLab.UI</RootNamespace>
8+
<AssemblyName>GitLab.UI</AssemblyName>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<ProjectReference Include="..\GitLab.UI\GitLab.UI.csproj" />
13+
<ProjectReference Include="..\Core.UI.Avalonia\Core.UI.Avalonia.csproj" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<Compile Update="Windows\CredentialsWindow.axaml.cs">
18+
<DependentUpon>CredentialsWindow.axaml</DependentUpon>
19+
<SubType>Code</SubType>
20+
</Compile>
21+
<Compile Update="Windows\TesterWindow.axaml.cs">
22+
<DependentUpon>Tester.axaml</DependentUpon>
23+
<SubType>Code</SubType>
24+
</Compile>
25+
<Compile Update="Controls\TesterWindow.axaml.cs">
26+
<DependentUpon>TesterWindow.axaml</DependentUpon>
27+
<SubType>Code</SubType>
28+
</Compile>
29+
</ItemGroup>
30+
31+
<ItemGroup>
32+
<AvaloniaResource Include="Assets\gitlab-logo-gray-rgb.png" />
33+
</ItemGroup>
34+
35+
</Project>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System;
2+
using System.Threading;
3+
using Avalonia;
4+
using GitLab.UI.Controls;
5+
using GitLab.UI.Commands;
6+
using GitCredentialManager;
7+
using GitCredentialManager.UI;
8+
9+
namespace GitLab.UI
10+
{
11+
public static class Program
12+
{
13+
public static void Main(string[] args)
14+
{
15+
// If we have no arguments then just start the app with the test window.
16+
if (args.Length == 0)
17+
{
18+
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
19+
return;
20+
}
21+
22+
// Create the dispatcher on the main thread. This is required
23+
// for some platform UI services such as macOS that mandates
24+
// all controls are created/accessed on the initial thread
25+
// created by the process (the process entry thread).
26+
Dispatcher.Initialize();
27+
28+
// Run AppMain in a new thread and keep the main thread free
29+
// to process the dispatcher's job queue.
30+
var appMain = new Thread(AppMain) {Name = nameof(AppMain)};
31+
appMain.Start(args);
32+
33+
// Process the dispatcher job queue (aka: message pump, run-loop, etc...)
34+
// We must ensure to run this on the same thread that it was created on
35+
// (the main thread) so we cannot use any async/await calls between
36+
// Dispatcher.Create and Run.
37+
Dispatcher.MainThread.Run();
38+
39+
// Execution should never reach here as AppMain terminates the process on completion.
40+
throw new InvalidOperationException("Main dispatcher job queue shutdown unexpectedly");
41+
}
42+
43+
private static void AppMain(object o)
44+
{
45+
string[] args = (string[]) o;
46+
47+
string appPath = ApplicationBase.GetEntryApplicationPath();
48+
using (var context = new CommandContext(appPath))
49+
using (var app = new HelperApplication(context))
50+
{
51+
app.RegisterCommand(new CredentialsCommandImpl(context));
52+
53+
int exitCode = app.RunAsync(args)
54+
.ConfigureAwait(false)
55+
.GetAwaiter()
56+
.GetResult();
57+
58+
Environment.Exit(exitCode);
59+
}
60+
}
61+
62+
public static AppBuilder BuildAvaloniaApp()
63+
=> AppBuilder.Configure(() => new AvaloniaApp(() => new TesterWindow()))
64+
.UsePlatformDetect()
65+
.LogToTrace();
66+
}
67+
}

0 commit comments

Comments
 (0)