Small fixes, mainly to make the TfsDestination work better.

This commit is contained in:
Robin 2018-04-26 16:00:40 +02:00
commit 62811016ce
9 changed files with 94 additions and 31 deletions

View file

@ -190,6 +190,7 @@
<Compile Include="ViewModels\JiraViewModel.cs" /> <Compile Include="ViewModels\JiraViewModel.cs" />
<Compile Include="ViewModels\JiraConfigViewModel.cs" /> <Compile Include="ViewModels\JiraConfigViewModel.cs" />
<None Include="app.config" /> <None Include="app.config" />
<EmbeddedResource Include="jira.svgz" />
<None Include="Languages\language_jiraplugin-de-DE.xml"> <None Include="Languages\language_jiraplugin-de-DE.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>

View file

@ -126,7 +126,7 @@ namespace Greenshot.Addon.Jira
} }
} }
IEnumerable<IDestination> DynamicDestinations() public override IEnumerable<IDestination> DynamicDestinations()
{ {
if (_jiraConnector == null || !_jiraConnector.IsLoggedIn) if (_jiraConnector == null || !_jiraConnector.IsLoggedIn)
{ {

Binary file not shown.

View file

@ -34,5 +34,8 @@ namespace Greenshot.Addon.Tfs.Entities
[JsonProperty("System.WorkItemType")] [JsonProperty("System.WorkItemType")]
public string WorkItemType { get; set; } public string WorkItemType { get; set; }
[JsonProperty("System.State")]
public string State { get; set; }
} }
} }

View file

@ -23,13 +23,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dapplo.HttpExtensions; using Dapplo.HttpExtensions;
using Dapplo.HttpExtensions.ContentConverter;
using Dapplo.HttpExtensions.Factory; using Dapplo.HttpExtensions.Factory;
using Dapplo.HttpExtensions.JsonNet; using Dapplo.HttpExtensions.JsonNet;
using Greenshot.Addon.Tfs.Entities; using Greenshot.Addon.Tfs.Entities;
@ -59,11 +59,16 @@ namespace Greenshot.Addon.Tfs
_coreConfiguration = coreConfiguration; _coreConfiguration = coreConfiguration;
_tfsConfiguration = tfsConfiguration; _tfsConfiguration = tfsConfiguration;
#if DEBUG
// Set json log threshold high
DefaultJsonHttpContentConverter.Instance.Value.LogThreshold = 0;
#endif
_tfsHttpBehaviour = new HttpBehaviour _tfsHttpBehaviour = new HttpBehaviour
{ {
HttpSettings = networkConfiguration, HttpSettings = networkConfiguration,
JsonSerializer = new JsonNetJsonSerializer() JsonSerializer = new JsonNetJsonSerializer()
}; };
} }
public bool CanUpdate => _tfsConfiguration.TfsUri != null && !string.IsNullOrEmpty(_tfsConfiguration.ApiKey); public bool CanUpdate => _tfsConfiguration.TfsUri != null && !string.IsNullOrEmpty(_tfsConfiguration.ApiKey);
@ -75,7 +80,7 @@ namespace Greenshot.Addon.Tfs
{ {
return; return;
} }
var workItems = await GetOwnWorkitems(); var workItems = await GetOwnWorkitems().ConfigureAwait(false);
foreach (var workItem in workItems.Items) foreach (var workItem in workItems.Items)
{ {
WorkItems[workItem.Id] = workItem; WorkItems[workItem.Id] = workItem;
@ -95,14 +100,14 @@ namespace Greenshot.Addon.Tfs
var wiql = new JObject { { "query", "Select [System.Id] FROM WorkItems WHERE [System.AssignedTo] = @me" } }; var wiql = new JObject { { "query", "Select [System.Id] FROM WorkItems WHERE [System.AssignedTo] = @me" } };
var queryResult = await client.PostAsync<HttpResponse<WorkItemQueryResult, string>>(workitemsQueryUri, wiql); var queryResult = await client.PostAsync<HttpResponse<WorkItemQueryResult, string>>(workitemsQueryUri, wiql).ConfigureAwait(false);
if (queryResult.HasError) if (queryResult.HasError)
{ {
throw new Exception(queryResult.ErrorResponse); throw new Exception(queryResult.ErrorResponse);
} }
var workItemsUri = apiUri.AppendSegments("wit", "workItems").ExtendQuery("ids", string.Join(",",queryResult.Response.Items.Select(item => item.Id))); var workItemsUri = apiUri.AppendSegments("wit", "workItems").ExtendQuery("ids", string.Join(",",queryResult.Response.Items.Select(item => item.Id)));
var result = await client.GetAsAsync<HttpResponse<WorkItemList, string>>(workItemsUri); var result = await client.GetAsAsync<HttpResponse<WorkItemList, string>>(workItemsUri).ConfigureAwait(false);
if (result.HasError) if (result.HasError)
{ {
throw new Exception(result.ErrorResponse); throw new Exception(result.ErrorResponse);
@ -132,7 +137,7 @@ namespace Greenshot.Addon.Tfs
using (var content = new StreamContent(imageStream)) using (var content = new StreamContent(imageStream))
{ {
content.SetContentType("application/octet-stream"); content.SetContentType("application/octet-stream");
var createAttachmentresult = await client.PostAsync<HttpResponse<CreateAttachmentResult, string>>(attachmentUri, content); var createAttachmentresult = await client.PostAsync<HttpResponse<CreateAttachmentResult, string>>(attachmentUri, content).ConfigureAwait(false);
if (createAttachmentresult.HasError) if (createAttachmentresult.HasError)
{ {
throw new Exception(createAttachmentresult.ErrorResponse); throw new Exception(createAttachmentresult.ErrorResponse);
@ -176,7 +181,7 @@ namespace Greenshot.Addon.Tfs
var content = HttpContentFactory.Create(linkAttachmentRequest); var content = HttpContentFactory.Create(linkAttachmentRequest);
content.SetContentType("application/json-patch+json"); content.SetContentType("application/json-patch+json");
var result = await client.PatchAsync<HttpResponse<string, string>>(linkAttachmentUri, content); var result = await client.PatchAsync<HttpResponse<string, string>>(linkAttachmentUri, content).ConfigureAwait(false);
if (result.HasError) if (result.HasError)
{ {
throw new Exception(result.ErrorResponse); throw new Exception(result.ErrorResponse);

View file

@ -65,20 +65,36 @@ namespace Greenshot.Addon.Tfs
_tfsConfiguration = tfsConfiguration; _tfsConfiguration = tfsConfiguration;
_tfsLanguage = tfsLanguage; _tfsLanguage = tfsLanguage;
_tfsClient = tfsClient; _tfsClient = tfsClient;
var ignoreTask = _tfsClient.UpdateWorkItems();
} }
public TfsDestination( public TfsDestination(
ITfsConfiguration tfsConfiguration, ITfsConfiguration tfsConfiguration,
ITfsLanguage tfsLanguage, ITfsLanguage tfsLanguage,
TfsClient tfsClient, WorkItem workItem) : this(tfsConfiguration, tfsLanguage, tfsClient) TfsClient tfsClient, WorkItem workItem)
{ {
_tfsConfiguration = tfsConfiguration;
_tfsLanguage = tfsLanguage;
_tfsClient = tfsClient;
_workItem = workItem; _workItem = workItem;
} }
public override bool IsActive => base.IsActive && _tfsClient.CanUpdate; public override bool IsActive => base.IsActive && _tfsClient.CanUpdate;
public override bool UseDynamicsOnly => true;
public override bool IsDynamic => true; public override bool IsDynamic => true;
protected override async Task PrepareDynamicDestinations(ToolStripMenuItem destinationToolStripMenuItem)
{
if (!destinationToolStripMenuItem.HasDropDownItems)
{
var oldColor = destinationToolStripMenuItem.BackColor;
destinationToolStripMenuItem.BackColor = Color.DarkGray;
await _tfsClient.UpdateWorkItems();
destinationToolStripMenuItem.BackColor = oldColor;
}
}
public override IEnumerable<IDestination> DynamicDestinations() public override IEnumerable<IDestination> DynamicDestinations()
{ {
var workitems = _tfsClient.WorkItems.Values; var workitems = _tfsClient.WorkItems.Values;
@ -96,7 +112,6 @@ namespace Greenshot.Addon.Tfs
} }
} }
public override string Description public override string Description
{ {
get get
@ -106,7 +121,8 @@ namespace Greenshot.Addon.Tfs
return _tfsLanguage.UploadMenuItem; return _tfsLanguage.UploadMenuItem;
} }
// Format the title of this destination // Format the title of this destination
return _workItem.Id + ": " + _workItem.Fields.Title.Substring(0, Math.Min(20, _workItem.Fields.Title.Length)); // TODO: substring?
return $"{_workItem.Fields.WorkItemType} {_workItem.Id}: {_workItem.Fields.Title}";
} }
} }
@ -123,8 +139,7 @@ namespace Greenshot.Addon.Tfs
} }
} }
public override async Task<ExportInformation> ExportCaptureAsync(bool manuallyInitiated, ISurface surface, public override async Task<ExportInformation> ExportCaptureAsync(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
ICaptureDetails captureDetails)
{ {
if (_workItem == null) if (_workItem == null)
{ {
@ -157,7 +172,7 @@ namespace Greenshot.Addon.Tfs
Uri response; Uri response;
var cancellationTokenSource = new CancellationTokenSource(); var cancellationTokenSource = new CancellationTokenSource();
using (var pleaseWaitForm = new PleaseWaitForm("OneDrive plug-in", _tfsLanguage.CommunicationWait, using (var pleaseWaitForm = new PleaseWaitForm("TFS plug-in", _tfsLanguage.CommunicationWait,
cancellationTokenSource)) cancellationTokenSource))
{ {
pleaseWaitForm.Show(); pleaseWaitForm.Show();

View file

@ -4,6 +4,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Greenshot.Addon.Tfs.ViewModels" xmlns:viewModels="clr-namespace:Greenshot.Addon.Tfs.ViewModels"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:behaviours="http://metro.mahapps.com/winfx/xaml/shared"
mc:Ignorable="d" mc:Ignorable="d"
d:DataContext="{d:DesignInstance viewModels:TfsConfigViewModel,IsDesignTimeCreatable=False}" d:DataContext="{d:DesignInstance viewModels:TfsConfigViewModel,IsDesignTimeCreatable=False}"
> >
@ -13,12 +15,12 @@
<ContentControl x:Name="FileConfigPartViewModel"/> <ContentControl x:Name="FileConfigPartViewModel"/>
<CheckBox IsChecked="{Binding TfsConfiguration.AfterUploadLinkToClipBoard}" Content="{Binding TfsLanguage.UsePageLink}"/> <CheckBox IsChecked="{Binding TfsConfiguration.AfterUploadLinkToClipBoard}" Content="{Binding TfsLanguage.UsePageLink}"/>
<DockPanel LastChildFill="True"> <DockPanel LastChildFill="True">
<Label Content="{Binding TfsLanguage.LabelUrl}" Width="100" /> <Label Content="{Binding TfsLanguage.LabelUrl}" Width="100"/>
<TextBox Text="{Binding TfsConfiguration.TfsUri}" /> <TextBox Text="{Binding TfsConfiguration.TfsUri}" mah:TextBoxHelper.ClearTextButton="True" mah:TextBoxHelper.Watermark="TFS Url"/>
</DockPanel> </DockPanel>
<DockPanel LastChildFill="True"> <DockPanel LastChildFill="True">
<Label Content="{Binding TfsLanguage.LabelApiKey}" Width="100" /> <Label Content="{Binding TfsLanguage.LabelApiKey}" Width="100" />
<TextBox Text="{Binding TfsConfiguration.ApiKey}" /> <PasswordBox behaviours:PasswordBoxBindingBehavior.Password="{Binding TfsConfiguration.ApiKey}" mah:PasswordBoxHelper.RevealButtonContent="{Binding TfsConfiguration.ApiKey}" />
</DockPanel> </DockPanel>
</StackPanel> </StackPanel>
</GroupBox> </GroupBox>

View file

@ -27,6 +27,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.Drawing; using System.Drawing;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
@ -64,12 +65,16 @@ namespace Greenshot.Addons.Core
Designation = GetType().GetDesignation(); Designation = GetType().GetDesignation();
} }
/// <inheritdoc />
public virtual string Designation { get; } public virtual string Designation { get; }
/// <inheritdoc />
public abstract string Description { get; } public abstract string Description { get; }
/// <inheritdoc />
public virtual Bitmap DisplayIcon { get; set; } public virtual Bitmap DisplayIcon { get; set; }
/// <inheritdoc />
public virtual BitmapSource DisplayIconWpf => DisplayIcon?.ToBitmapSource() ?? GetDisplayIcon(DpiHandler.DefaultScreenDpi).ToBitmapSource(); public virtual BitmapSource DisplayIconWpf => DisplayIcon?.ToBitmapSource() ?? GetDisplayIcon(DpiHandler.DefaultScreenDpi).ToBitmapSource();
public virtual Bitmap GetDisplayIcon(double dpi) public virtual Bitmap GetDisplayIcon(double dpi)
@ -81,9 +86,33 @@ namespace Greenshot.Addons.Core
public virtual Keys EditorShortcutKeys => Keys.None; public virtual Keys EditorShortcutKeys => Keys.None;
/// <summary>
/// Give a destination a preparation possibility before showing the toolstrip items
/// </summary>
/// <param name="destinationToolStripMenuItem">ToolStripMenuItem</param>
/// <returns>Task</returns>
protected virtual Task PrepareDynamicDestinations(ToolStripMenuItem destinationToolStripMenuItem)
{
return Task.FromResult(true);
}
/// <summary>
/// Get the Dynamic destinations
/// </summary>
/// <returns>IEnumerable of IDestination</returns>
public virtual IEnumerable<IDestination> DynamicDestinations() public virtual IEnumerable<IDestination> DynamicDestinations()
{ {
yield break; return Enumerable.Empty<IDestination>();
}
/// <summary>
/// Give a destination the possibility to clean up after showing the toolstrip item
/// </summary>
/// <param name="destinationToolStripMenuItem">ToolStripMenuItem</param>
/// <returns>Task</returns>
protected virtual Task AfterDynamicDestinations(ToolStripMenuItem destinationToolStripMenuItem)
{
return Task.FromResult(true);
} }
public void Dispose() public void Dispose()
@ -91,12 +120,16 @@ namespace Greenshot.Addons.Core
Dispose(true); Dispose(true);
} }
/// <inheritdoc />
public virtual bool IsDynamic => false; public virtual bool IsDynamic => false;
/// <inheritdoc />
public virtual bool UseDynamicsOnly => false; public virtual bool UseDynamicsOnly => false;
/// <inheritdoc />
public virtual bool IsLinkable => false; public virtual bool IsLinkable => false;
/// <inheritdoc />
public virtual bool IsActive => true; public virtual bool IsActive => true;
protected virtual ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) protected virtual ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
@ -140,13 +173,16 @@ namespace Greenshot.Addons.Core
if (IsDynamic && addDynamics) if (IsDynamic && addDynamics)
{ {
basisMenuItem.DropDownOpening += (sender, args) => basisMenuItem.DropDownOpening += async (sender, args) =>
{ {
if (basisMenuItem.DropDownItems.Count != 0) if (basisMenuItem.DropDownItems.Count != 0)
{ {
return; return;
} }
// Give the destination a chance to prepare for the destinations
await PrepareDynamicDestinations(basisMenuItem).ConfigureAwait(true);
var subDestinations = new List<IDestination>(); var subDestinations = new List<IDestination>();
// Fixing Bug #3536968 by catching the COMException (every exception) and not displaying the "subDestinations" // Fixing Bug #3536968 by catching the COMException (every exception) and not displaying the "subDestinations"
try try
@ -157,7 +193,7 @@ namespace Greenshot.Addons.Core
{ {
Log.Error().WriteLine("Skipping {0}, due to the following error: {1}", Description, ex.Message); Log.Error().WriteLine("Skipping {0}, due to the following error: {1}", Description, ex.Message);
} }
await AfterDynamicDestinations(basisMenuItem).ConfigureAwait(true);
if (subDestinations.Count <= 0) if (subDestinations.Count <= 0)
{ {
return; return;
@ -184,6 +220,7 @@ namespace Greenshot.Addons.Core
AddTagEvents(destinationMenuItem, menu, subDestination.Description); AddTagEvents(destinationMenuItem, menu, subDestination.Description);
basisMenuItem.DropDownItems.Add(destinationMenuItem); basisMenuItem.DropDownItems.Add(destinationMenuItem);
} }
basisMenuItem.ShowDropDown();
} }
}; };
} }

View file

@ -29,28 +29,28 @@
<ColumnDefinition Width="200" /> <ColumnDefinition Width="200" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"> <Grid Grid.Column="0" Grid.Row="0">
<TextBox x:Name="Filter" /> <Grid.RowDefinitions>
<TreeView x:Name="TreeItems" <RowDefinition Height="30" />
cal:Message.Attach="[Event SelectedItemChanged] = [Action ActivateChildView($this.SelectedItem)]"> <RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox x:Name="Filter" Grid.Row="0" mah:TextBoxHelper.ClearTextButton="True" />
<TreeView x:Name="TreeItems" Grid.Row="1" cal:Message.Attach="[Event SelectedItemChanged] = [Action ActivateChildView($this.SelectedItem)]">
<TreeView.ItemContainerStyle> <TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}"> <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="IsEnabled" Value="{Binding IsEnabled}" /> <Setter Property="IsEnabled" Value="{Binding IsEnabled}" />
<Setter Property="Visibility" Value="{Binding IsVisible, Converter={StaticResource BooleanToVisibility}}" /> <Setter Property="Visibility" Value="{Binding IsVisible, Converter={StaticResource BooleanToVisibility}}" />
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource AuthenticationTargetPropertyConverter}}" <DataTrigger Binding="{Binding Converter={StaticResource AuthenticationTargetPropertyConverter}}" Value="{x:Static security:AuthenticationTargetProperties.Visibility}">
Value="{x:Static security:AuthenticationTargetProperties.Visibility}">
<Setter Property="security:AuthenticationVisibility.Permissions" Value="{Binding Permissions}" /> <Setter Property="security:AuthenticationVisibility.Permissions" Value="{Binding Permissions}" />
<Setter Property="security:AuthenticationVisibility.WhenPermissions" Value="{Binding WhenPermission}" /> <Setter Property="security:AuthenticationVisibility.WhenPermissions" Value="{Binding WhenPermission}" />
<Setter Property="security:AuthenticationVisibility.WhenPermissionsMissing" <Setter Property="security:AuthenticationVisibility.WhenPermissionsMissing" Value="{Binding WhenPermissionMissing}" />
Value="{Binding WhenPermissionMissing}" />
</DataTrigger> </DataTrigger>
<DataTrigger Binding="{Binding Converter={StaticResource AuthenticationTargetPropertyConverter}}" <DataTrigger Binding="{Binding Converter={StaticResource AuthenticationTargetPropertyConverter}}"
Value="{x:Static security:AuthenticationTargetProperties.IsEnabled}"> Value="{x:Static security:AuthenticationTargetProperties.IsEnabled}">
<Setter Property="security:AuthenticationEnabled.Permissions" Value="{Binding Permissions}" /> <Setter Property="security:AuthenticationEnabled.Permissions" Value="{Binding Permissions}" />
<Setter Property="security:AuthenticationEnabled.WhenPermissions" Value="{Binding WhenPermission}" /> <Setter Property="security:AuthenticationEnabled.WhenPermissions" Value="{Binding WhenPermission}" />
<Setter Property="security:AuthenticationEnabled.WhenPermissionsMissing" <Setter Property="security:AuthenticationEnabled.WhenPermissionsMissing" Value="{Binding WhenPermissionMissing}" />
Value="{Binding WhenPermissionMissing}" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
@ -61,7 +61,7 @@
</HierarchicalDataTemplate> </HierarchicalDataTemplate>
</TreeView.ItemTemplate> </TreeView.ItemTemplate>
</TreeView> </TreeView>
</StackPanel> </Grid>
<ContentControl x:Name="ActiveItem" Grid.Column="1" Grid.Row="0"/> <ContentControl x:Name="ActiveItem" Grid.Column="1" Grid.Row="0"/>
<UniformGrid Grid.Column="1" Grid.Row="1" Rows="1" Columns="2"> <UniformGrid Grid.Column="1" Grid.Row="1" Rows="1" Columns="2">
<Button x:Name="Cancel" Content="{Binding GreenshotLanguage.Cancel}" /> <Button x:Name="Cancel" Content="{Binding GreenshotLanguage.Cancel}" />