Skip to content

Commit

Permalink
Starting on #3 switching to data binding
Browse files Browse the repository at this point in the history
Move to codicon icons for status
Added query limit option
Added progress indicator for load
  • Loading branch information
timheuer committed Jul 14, 2023
1 parent 170b72a commit 0698029
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 37 deletions.
26 changes: 26 additions & 0 deletions src/Converters/ConclusionColorConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;

namespace GitHubActionsVS.Converters;

public class ConclusionColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string status = value as string;
return GetConclusionColor(status);
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}

private SolidColorBrush GetConclusionColor(string status) => status.ToLowerInvariant() switch
{
"success" => new SolidColorBrush(Colors.Green),
"failure" => new SolidColorBrush(Colors.Red),
_ => new SolidColorBrush(Colors.Black),
};
}
26 changes: 26 additions & 0 deletions src/Converters/ConclusionIconConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Globalization;
using System.Windows.Data;

namespace GitHubActionsVS.Converters;
public class ConclusionIconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string status = value as string;
return GetConclusionIndicator(status);
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}

private string GetConclusionIndicator(string status) => status.ToLowerInvariant() switch
{
"success" => "\uEBB3 ",
"failure" => "\uEBB4 ",
"cancelled" => "\uEABD ",
"skipped" => "\uEABD ",
_ => "🤷🏽",
};
}
6 changes: 6 additions & 0 deletions src/GitHubActionsVS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,14 @@
<ItemGroup>
<Compile Include="Commands\GotoRepoCommand.cs" />
<Compile Include="Commands\RefreshRepoCommand.cs" />
<Compile Include="Converters\ConclusionColorConverter.cs" />
<Compile Include="Converters\ConclusionIconConverter.cs" />
<Compile Include="Helpers\CredentialManager.cs" />
<Compile Include="Helpers\RepoInfo.cs" />
<Compile Include="Models\BaseWorkflowType.cs" />
<Compile Include="Models\SimpleJob.cs" />
<Compile Include="Models\SimpleRun.cs" />
<Compile Include="Options\ExtensionOptions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Commands\ActionsToolWindowCommand.cs" />
<Compile Include="GitHubActionsVSPackage.cs" />
Expand Down
1 change: 1 addition & 0 deletions src/GitHubActionsVSPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace GitHubActionsVS;
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
[ProvideToolWindow(typeof(ActionsToolWindow.Pane), Style = VsDockStyle.Tabbed, Window = WindowGuids.SolutionExplorer)]
[ProvideOptionPage(typeof(OptionsProvider.ExtensionOptionsOptions), "GitHub Actions for VS", "General", 0, 0, true, SupportsProfiles = true)]
[ProvideMenuResource("Menus.ctmenu", 1)]
[Guid(PackageGuids.GitHubActionsVSString)]
[ProvideBindingPath]
Expand Down
13 changes: 13 additions & 0 deletions src/Models/BaseWorkflowType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace GitHubActionsVS.Models;

public abstract class BaseWorkflowType
{
public string Name { get; set; }

public abstract string DisplayName { get; }
public string Conclusion { get; set; }
public DateTimeOffset? LogDate { get; set; }
public string DisplayDate => $"{LogDate:g}";
public string? Url { get; set; }
public string Id { get; set; }
}
6 changes: 6 additions & 0 deletions src/Models/SimpleJob.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace GitHubActionsVS.Models;

public class SimpleJob : SimpleRun
{
public override string DisplayName => Name;
}
10 changes: 10 additions & 0 deletions src/Models/SimpleRun.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace GitHubActionsVS.Models;
public class SimpleRun : BaseWorkflowType
{
public List<SimpleJob> Jobs { get; set; }
public string RunNumber { get; set; }

public override string DisplayName => $"{Name} #{RunNumber}";
}
20 changes: 20 additions & 0 deletions src/Options/ExtensionOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace GitHubActionsVS;
internal partial class OptionsProvider
{
// Register the options with this attribute on your package class:
// [ProvideOptionPage(typeof(OptionsProvider.ExtensionOptionsOptions), "GitHubActionsVS", "ExtensionOptions", 0, 0, true, SupportsProfiles = true)]
[ComVisible(true)]
public class ExtensionOptionsOptions : BaseOptionPage<ExtensionOptions> { }
}

public class ExtensionOptions : BaseOptionModel<ExtensionOptions>
{
[Category("Query Settings")]
[DisplayName("Max Runs")]
[Description("The maximum number of runs to retrieve")]
[DefaultValue(10)]
public int MaxRuns { get; set; } = 10;
}
28 changes: 25 additions & 3 deletions src/ToolWindows/GHActionsToolWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
xmlns:catalog="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.ImageCatalog"
xmlns:toolkit="clr-namespace:Community.VisualStudio.Toolkit;assembly=Community.VisualStudio.Toolkit"
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
xmlns:ivc="clr-namespace:GitHubActionsVS.Converters"
toolkit:Themes.UseVsTheme="True"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300"
Name="GHActionToolWindow">
<UserControl.Resources>
<FontFamily x:Key="CodiconFont">pack://application:,,,/GitHubActionsVS;component/Resources/#codicon</FontFamily>
<ivc:ConclusionIconConverter x:Key="ConclusionIconConverter" />
<ivc:ConclusionColorConverter x:Key="ConclusionColorConverter" />
<Style TargetType="{x:Type Expander}">
<Setter Property="toolkit:Themes.UseVsTheme" Value="True" />
</Style>
Expand All @@ -40,12 +43,31 @@
<TextBlock Text="{Binding}" Margin="5,0" />
</StackPanel>
</DataTemplate>
<HierarchicalDataTemplate x:Key="TreeViewRunNodeDataTemplate" ItemsSource="{Binding Jobs}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Grid.Column="0">
<TextBlock VerticalAlignment="Center" FontFamily="{StaticResource CodiconFont}"
Foreground="{Binding Path=Conclusion, Converter={StaticResource ConclusionColorConverter}}"
Text="{Binding Path=Conclusion, Converter={StaticResource ConclusionIconConverter}}"/>
<emoji:TextBlock Text="{Binding DisplayName}" VerticalAlignment="Bottom" />
</StackPanel>
</HierarchicalDataTemplate>
</UserControl.Resources>
<Grid Margin="5,5,0,0">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ProgressBar x:Name="refreshProgress" Height="5" Grid.Row="0" Visibility="Collapsed" />
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Row="1" Margin="5,5,0,0">
<StackPanel Orientation="Vertical">
<Expander Header="Current Branch">
<TreeView x:Name="tvCurrentBranch" BorderThickness="0" />
<TreeView BorderThickness="0" PreviewMouseWheel="HandlePreviewMouseWheel" MouseDoubleClick="JobItem_MouseDoubleClick" x:Name="tvCurrentBranch" ItemTemplate="{DynamicResource TreeViewRunNodeDataTemplate}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<EventSetter Event="MouseDoubleClick" Handler="JobItem_MouseDoubleClick"/>
</Style>
</TreeView.Resources>
</TreeView>
</Expander>
<!--<Expander Header="Workflows">
<TreeView x:Name="tvWorkflows" BorderThickness="0"/>
Expand Down
102 changes: 68 additions & 34 deletions src/ToolWindows/GHActionsToolWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using GitHubActionsVS.Helpers;
using GitHubActionsVS.Models;
using GitHubActionsVS.ToolWindows;
using Octokit;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace GitHubActionsVS;

Expand Down Expand Up @@ -85,12 +88,20 @@ private void ClearTreeViews()
{
tvSecrets.Items.Clear();
//tvWorkflows.Items.Clear();
tvCurrentBranch.Items.Clear();
tvCurrentBranch.ItemsSource = null;
tvEnvironments.Items.Clear();
}

private async Task LoadDataAsync()
{

// get the settings
var generalSettings = await ExtensionOptions.GetLiveInstanceAsync();
var maxRuns = generalSettings.MaxRuns;

refreshProgress.IsIndeterminate = true;
refreshProgress.Visibility = Visibility.Visible;

GitHubClient client = GetGitHubClient();

try
Expand Down Expand Up @@ -122,46 +133,65 @@ private async Task LoadDataAsync()
//}

// get current branch
var runs = await client.Actions?.Workflows?.Runs?.List(_repoInfo.RepoOwner, _repoInfo.RepoName, new WorkflowRunsRequest() { Branch = _repoInfo.CurrentBranch }, new ApiOptions() { PageCount = 2, PageSize = 10 });
var runs = await client.Actions?.Workflows?.Runs?.List(_repoInfo.RepoOwner, _repoInfo.RepoName, new WorkflowRunsRequest() { Branch = _repoInfo.CurrentBranch }, new ApiOptions() { PageCount = 1, PageSize = maxRuns });

// creating simplified model of the GH info for the treeview
List<SimpleRun> runsList = new List<SimpleRun>();

// iterate throught the runs
foreach (var run in runs.WorkflowRuns)
{
var item = new TreeViewItem
SimpleRun simpleRun = new()
{
Header = CreateEmojiContent($"{GetConclusionIndicator(run.Conclusion.Value.StringValue)} {run.Name} #{run.RunNumber}"),
Tag = run
Conclusion = run.Conclusion.Value.StringValue,
Name = run.Name,
LogDate = run.UpdatedAt,
Id = run.Id.ToString(),
RunNumber = run.RunNumber.ToString()
};

// iterate through the run
var jobs = await client.Actions?.Workflows?.Jobs?.List(_repoInfo.RepoOwner, _repoInfo.RepoName, run.Id);
// get the jobs for the run
var jobs = await client.Actions.Workflows.Jobs?.List(_repoInfo.RepoOwner, _repoInfo.RepoName, run.Id);

List<SimpleJob> simpleJobs = new();

// iterate through the jobs' steps
foreach (var job in jobs.Jobs)
{
var jobItem = new TreeViewItem
{
Header = CreateEmojiContent($"{GetConclusionIndicator(job.Conclusion.Value.StringValue)} {job.Name}"),
Tag = job
};

// iterate through the job
List<SimpleJob> steps = new();
foreach (var step in job.Steps)
{
var stepItem = new TreeViewItem
steps.Add(new SimpleJob()
{
Header = CreateEmojiContent($"{GetConclusionIndicator(step.Conclusion.Value.StringValue)}: {step.Name}"),
Tag = $"{job.HtmlUrl}#step:{step.Number.ToString()}:1" //https://github.com/timheuer/workflow-playground/actions/runs/5548963145/jobs/10132505381#step:2:7
};
stepItem.MouseDoubleClick += JobItem_MouseDoubleClick;
jobItem.Items.Add(stepItem);
Conclusion = step.Conclusion.Value.StringValue,
Name = step.Name,
Url = $"{job.HtmlUrl}#step:{step.Number.ToString()}:1"
});
}

item.Items.Add(jobItem);
simpleJobs.Add(new SimpleJob()
{
Conclusion = job.Conclusion.Value.StringValue,
Name = job.Name,
Id = job.Id.ToString(),
Jobs = steps // add the steps to the job
});
}
tvCurrentBranch.Items.Add(item);

// add the jobs to the run
simpleRun.Jobs = simpleJobs;

runsList.Add(simpleRun);
}

tvCurrentBranch.ItemsSource = runsList;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}

refreshProgress.Visibility = Visibility.Collapsed;
refreshProgress.IsIndeterminate = false;
}

private UIElement CreateEmojiContent(string emojiString)
Expand All @@ -183,21 +213,25 @@ private static GitHubClient GetGitHubClient()
return client;
}

private string GetConclusionIndicator(string status) => status.ToLowerInvariant() switch
{
"success" => "",
"failure" => "",
"cancelled" => "🚫",
"skipped" => "",
_ => "🤷🏽",
};

private void JobItem_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// get the items Tag
if (sender is TreeViewItem item && item.Tag is string url)
if (sender is TreeViewItem item && item.Header is SimpleJob job && job.Url is not null)
{
Process.Start(job.Url);
}
}

private void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!e.Handled)
{
Process.Start(url);
e.Handled = true;
var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
eventArg.RoutedEvent = UIElement.MouseWheelEvent;
eventArg.Source = sender;
var parent = ((Control)sender).Parent as UIElement;
parent.RaiseEvent(eventArg);
}
}
}
Expand Down

0 comments on commit 0698029

Please sign in to comment.