Skip to content

Commit 04ac6b0

Browse files
committed
begin work on the release page
1 parent 4543969 commit 04ac6b0

File tree

7 files changed

+230
-12
lines changed

7 files changed

+230
-12
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ AzureDevOpsTeamMemberVelocity.json
354354
NugetPageSettings.json
355355
GitPageSettings.json
356356
KubernetesPageSettings.json
357+
ListDefinitionFilter.json
357358

358359
key-*.xml
359360
Documentation.xml

AzureDevOpsTeamMembersVelocity/Pages/Releases.razor

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1-
@page "/Releases"
1+
@page "/Releases"
22
@inject ReleasesService ReleasesService
33
@inject IUserPreferenceRepository UserPreference
4+
@inject IDialogService DialogService
45

5-
<h3>Releases</h3>
6+
<div class="row">
7+
<h3>Releases</h3>
8+
</div>
69

710
<div class="row">
811
<div class="col-3">
912
<h4>Releases definition</h4>
13+
<div @onclick="OpenFilterModal">
14+
Advenced search
15+
</div>
1016
<ul class="list-group">
1117
@if (DefinitionList != null)
1218
{
@@ -48,15 +54,34 @@
4854

4955
List<Microsoft.VisualStudio.Services.ReleaseManagement.WebApi.ReleaseDefinition>? DefinitionList { get; set; }
5056

57+
ListDefinitionFilter ListDefinitionFilter { get; set; } = new ListDefinitionFilter();
58+
5159
protected override async Task OnInitializedAsync()
5260
{
5361
var settings = await UserPreference.GetAsync<TeamMembersVelocitySettings>();
5462

5563
if (settings.Organisation != null && settings.TeamProject != null)
5664
{
57-
DefinitionList = (await ReleasesService.ListDefinition(settings.Organisation, settings.TeamProject)).Item1?.Value;
65+
ListDefinitionFilter = await UserPreference.GetAsync<ListDefinitionFilter>();
66+
67+
DefinitionList = (await ReleasesService.ListDefinition(settings.Organisation, settings.TeamProject, ListDefinitionFilter)).Item1?.Value;
5868

5969
ReleasesList = (await ReleasesService.ListReleases(settings.Organisation, settings.TeamProject)).Item1?.Value;
6070
}
6171
}
72+
73+
public async Task OpenFilterModal()
74+
{
75+
var parameters = new DialogParameters();
76+
77+
parameters.Add("T", ListDefinitionFilter.GetType());
78+
parameters.Add("Value", ListDefinitionFilter);
79+
80+
DialogService.Show<AdvancedSearchDialog>("Advanved search", parameters, new DialogOptions
81+
{
82+
MaxWidth = MaxWidth.ExtraLarge
83+
});
84+
85+
await Task.CompletedTask;
86+
}
6287
}

AzureDevOpsTeamMembersVelocity/Services/ReleasesService.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using AzureDevOpsTeamMembersVelocity.Proxy;
2-
using Microsoft.CodeAnalysis;
1+
using AzureDevOpsTeamMembersVelocity.Settings;
2+
using AzureDevOpsTeamMembersVelocity.Proxy;
33
using System.Threading.Tasks;
44

55
namespace AzureDevOpsTeamMembersVelocity.Services
@@ -38,10 +38,19 @@ public ReleasesService(IDevOpsProxy proxy)
3838
/// <summary>
3939
/// Get a list of releases definition for a team project.
4040
/// </summary>
41-
public Task<(ListResponse<Microsoft.VisualStudio.Services.ReleaseManagement.WebApi.ReleaseDefinition>?, string?)> ListDefinition(string organization, string teamProject)
41+
/// <remarks>
42+
/// Microsoft documentation: https://docs.microsoft.com/en-us/rest/api/azure/devops/release/definitions/list?view=azure-devops-rest-6.0
43+
/// </remarks>
44+
public Task<(ListResponse<Microsoft.VisualStudio.Services.ReleaseManagement.WebApi.ReleaseDefinition>?, string?)> ListDefinition(string organization, string teamProject, ListDefinitionFilter? listDefinitionFilter = default)
4245
{
43-
return _proxy.GetAsync<ListResponse<Microsoft.VisualStudio.Services.ReleaseManagement.WebApi.ReleaseDefinition>>(
44-
$"https://vsrm.dev.azure.com/{organization}/{teamProject}/_apis/release/definitions?api-version=6.0");
46+
string releaseDefinitionUrl = $"https://vsrm.dev.azure.com/{organization}/{teamProject}/_apis/release/definitions?api-version=6.0";
47+
48+
if (listDefinitionFilter != null)
49+
{
50+
releaseDefinitionUrl = listDefinitionFilter.AppendParameterToQueryString(releaseDefinitionUrl);
51+
}
52+
53+
return _proxy.GetAsync<ListResponse<Microsoft.VisualStudio.Services.ReleaseManagement.WebApi.ReleaseDefinition>>(releaseDefinitionUrl);
4554
}
4655
}
4756
}

AzureDevOpsTeamMembersVelocity/Settings/AbstractSettings.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ public abstract class AbstractSettings
1414
/// <summary>
1515
/// Tell if the settings instance as changed
1616
/// </summary>
17-
public bool AsChanged()
17+
public virtual bool AsChanged()
1818
{
1919
return _asChanged;
2020
}
2121

2222
/// <summary>
2323
/// Tell if the settings instance as not changed
2424
/// </summary>
25-
public bool AsNotChanged()
25+
public virtual bool AsNotChanged()
2626
{
2727
return !_asChanged;
2828
}
@@ -31,7 +31,7 @@ public bool AsNotChanged()
3131
/// Class that store settings should call this function ater saving the settings
3232
/// to help reduce number of I/O operation
3333
/// </summary>
34-
public void Saved()
34+
public virtual void Saved()
3535
{
3636
_asChanged = false;
3737
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
using System.ComponentModel;
2+
using System.Reflection;
3+
using System.Text;
4+
5+
namespace AzureDevOpsTeamMembersVelocity.Settings
6+
{
7+
/// <summary>
8+
/// Additional query string parameter for the ListDefinition action of the release section
9+
/// </summary>
10+
public class ListDefinitionFilter : AbstractSettings
11+
{
12+
private PropertyInfo[] Properties = typeof(ListDefinitionFilter).GetProperties();
13+
14+
/// <summary>
15+
/// Append all non null property of the current class in the query string of the url
16+
/// </summary>
17+
/// <param name="url">The url to append query string parameter</param>
18+
public string AppendParameterToQueryString(string url)
19+
{
20+
var sb = new StringBuilder(url);
21+
22+
for (int i = 0; i < Properties.Length; i++)
23+
{
24+
var value = Properties[i].GetValue(this);
25+
26+
if (!string.IsNullOrWhiteSpace(value?.ToString()))
27+
{
28+
sb.Append('&');
29+
30+
var displayName = Properties[i].GetCustomAttribute<DisplayNameAttribute>();
31+
32+
if (displayName != null)
33+
{
34+
sb.Append(displayName.DisplayName);
35+
}
36+
else
37+
{
38+
sb.Append(LowerCaseFirstLetter(Properties[i].Name));
39+
}
40+
41+
sb.Append('=');
42+
43+
sb.Append(value);
44+
}
45+
}
46+
47+
return sb.ToString();
48+
}
49+
50+
private string LowerCaseFirstLetter(string name)
51+
{
52+
var sb = new StringBuilder();
53+
54+
sb.Append(char.ToLower(name[0]));
55+
56+
for (int i = 1; i < name.Length; i++)
57+
{
58+
sb.Append(name[i]);
59+
}
60+
61+
return sb.ToString();
62+
}
63+
64+
/// <summary>
65+
/// Get release definitions with names containing searchText.
66+
/// </summary>
67+
public string? SearchText { get; set; }
68+
69+
/// <summary>
70+
/// The properties that should be expanded in the list of Release definitions.
71+
/// </summary>
72+
[DisplayName("$expand")]
73+
public string? Expand { get; set; }
74+
75+
/// <summary>
76+
/// Release definitions with given artifactType will be returned.
77+
/// Values can be Build, Jenkins, GitHub, Nuget, Team Build (external), ExternalTFSBuild, Git, TFVC, ExternalTfsXamlBuild.
78+
/// </summary>
79+
public string? ArtifactType { get; set; }
80+
81+
/// <summary>
82+
/// Release definitions with given artifactSourceId will be returned. e.g.
83+
/// For build it would be {projectGuid}:{BuildDefinitionId}, for Jenkins it would be {JenkinsConnectionId}:{JenkinsDefinitionId}, for TfsOnPrem it would be {TfsOnPremConnectionId}:{ProjectName}:{TfsOnPremDefinitionId}.
84+
/// For third-party artifacts e.g. TeamCity, BitBucket you may refer 'uniqueSourceIdentifier' inside vss-extension.json at https://github.com/Microsoft/vsts-rm-extensions/blob/master/Extensions.
85+
/// </summary>
86+
public string? ArtifactSourceId { get; set; }
87+
88+
/// <summary>
89+
/// Number of release definitions to get.
90+
/// </summary>
91+
[DisplayName("$top")]
92+
public int? Top { get; set; }
93+
94+
/// <summary>
95+
/// Gets the release definitions after the continuation token provided.
96+
/// </summary>
97+
public string? ContinuationToken { get; set; }
98+
99+
/// <summary>
100+
/// Gets the results in the defined order. Default is 'IdAscending'.
101+
/// </summary>
102+
public string? QueryOrder { get; set; }
103+
104+
/// <summary>
105+
/// Gets the release definitions under the specified path.
106+
/// </summary>
107+
public string? Path { get; set; }
108+
109+
/// <summary>
110+
/// 'true'to gets the release definitions with exact match as specified in searchText. Default is 'false'.
111+
/// </summary>
112+
public bool? IsExactNameMatch { get; set; }
113+
114+
/// <summary>
115+
/// A comma-delimited list of tags. Only release definitions with these tags will be returned.
116+
/// </summary>
117+
public string? TagFilter { get; set; }
118+
119+
/// <summary>
120+
/// A comma-delimited list of extended properties to be retrieved.
121+
/// If set, the returned Release Definitions will contain values for the specified property Ids (if they exist).
122+
/// If not set, properties will not be included.
123+
/// Note that this will not filter out any Release Definition from results irrespective of whether it has property set or not.
124+
/// </summary>
125+
public string? PropertyFilters { get; set; }
126+
127+
/// <summary>
128+
/// A comma-delimited list of release definitions to retrieve.
129+
/// </summary>
130+
public string? DefinitionIdFilter { get; set; }
131+
132+
/// <summary>
133+
/// 'true' to get release definitions that has been deleted. Default is 'false'
134+
/// </summary>
135+
public bool? IsDeleted { get; set; }
136+
137+
/// <summary>
138+
/// 'true' to get the release definitions under the folder with name as specified in searchText. Default is 'false'.
139+
/// </summary>
140+
public bool? SearchTextContainsFolderName { get; set; }
141+
142+
/// <inheritdoc />
143+
public override bool AsChanged()
144+
{
145+
return true;
146+
}
147+
148+
/// <inheritdoc />
149+
public override bool AsNotChanged()
150+
{
151+
return false;
152+
}
153+
154+
/// <inheritdoc />
155+
public override void Saved()
156+
{
157+
158+
}
159+
}
160+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
@foreach (var param in T.GetProperties())
3+
{
4+
<div class="form-group">
5+
<span>@param.Name</span>
6+
<input type="text" />
7+
</div>
8+
}
9+
10+
@code {
11+
[Parameter]
12+
public Type? T { get; set; }
13+
14+
[Parameter]
15+
public object? Value { get; set; }
16+
17+
protected async override Task OnInitializedAsync()
18+
{
19+
await Task.CompletedTask;
20+
}
21+
}

AzureDevOpsTeamMembersVelocity/_Imports.razor

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
@using System.IO;
2727
@using System.Net.Http
2828
@using System.Net.Http.Headers
29+
@using System.Reflection
2930
@using System.Security.Claims
3031
@using System.Text.Json
31-
@using System.Threading
32+
@using System.Threading
33+
@using System.Threading.Tasks

0 commit comments

Comments
 (0)