diff --git a/.github/upgrades/dotnet-upgrade-plan.md b/.github/upgrades/dotnet-upgrade-plan.md
new file mode 100644
index 0000000..8e03a1f
--- /dev/null
+++ b/.github/upgrades/dotnet-upgrade-plan.md
@@ -0,0 +1,64 @@
+# .NET 8.0 Upgrade Plan
+
+## Execution Steps
+
+Execute steps below sequentially one by one in the order they are listed.
+
+1. Validate that a .NET 8.0 SDK required for this upgrade is installed on the machine and if not, help to get it installed.
+2. Ensure that the SDK version specified in global.json files is compatible with the .NET 8.0 upgrade.
+3. Upgrade Stutton.DocumentCreator\Stutton.DocumentCreator.csproj
+
+## Settings
+
+This section contains settings and data used by execution steps.
+
+### Excluded projects
+
+| Project name | Description |
+|:-----------------------------------------------|:---------------------------:|
+| (none) | |
+
+### Aggregate NuGet packages modifications across all projects
+
+NuGet packages used across all selected projects or their dependencies that need version update in projects that reference them.
+
+| Package Name | Current Version | New Version | Description |
+|:----------------------------------------------------|:---------------:|:-----------:|:-------------------------------------------------------------------|
+| GitVersionTask | 5.5.1 | | Deprecated. Replace with GitVersion.MsBuild |
+| GitVersion.MsBuild | | 5.5.1 | Replacement for GitVersionTask |
+| Microsoft.ApplicationInsights | 2.16.0 | 3.1.2 | Deprecated version, upgrade to latest |
+| Microsoft.IdentityModel.Clients.ActiveDirectory | 5.2.8 | | Deprecated. Replace with Microsoft.Identity.Client |
+| Microsoft.Identity.Client | | 4.67.2 | Replacement for Microsoft.IdentityModel.Clients.ActiveDirectory |
+| Microsoft.Xaml.Behaviors.Wpf | | 1.1.135 | Replacement for System.Windows.Interactivity.WPF |
+| Newtonsoft.Json | 12.0.3 | 13.0.4 | Recommended for .NET 8.0 |
+| OpenXmlPowerTools | 4.5.3.2 | 2.7.4.2 | Incompatible version, use compatible version |
+| squirrel.windows | 2.0.1 | | Incompatible with .NET 8.0, no supported version found |
+| System.Net.Http | 4.3.4 | | Package functionality included with .NET 8.0 framework |
+| System.Text.RegularExpressions | 4.3.1 | | Package functionality included with .NET 8.0 framework |
+| System.ValueTuple | 4.5.0 | | Package functionality included with .NET 8.0 framework |
+| System.Windows.Interactivity.WPF | 2.0.20525 | | Incompatible and deprecated. Replace with Microsoft.Xaml.Behaviors.Wpf |
+
+### Project upgrade details
+
+This section contains details about each project upgrade and modifications that need to be done in the project.
+
+#### Stutton.DocumentCreator\Stutton.DocumentCreator.csproj modifications
+
+Project properties changes:
+ - Project file needs to be converted to SDK-style
+ - Target framework should be changed from `net472` to `net8.0-windows`
+
+NuGet packages changes:
+ - GitVersionTask should be removed and replaced with `GitVersion.MsBuild` version `5.5.1` (*deprecated*)
+ - Microsoft.ApplicationInsights should be updated from `2.16.0` to `3.1.2` (*deprecated version*)
+ - Microsoft.IdentityModel.Clients.ActiveDirectory should be removed and replaced with `Microsoft.Identity.Client` version `4.67.2` (*deprecated*)
+ - Newtonsoft.Json should be updated from `12.0.3` to `13.0.4` (*recommended for .NET 8.0*)
+ - OpenXmlPowerTools should be updated from `4.5.3.2` to `2.7.4.2` (*compatible version for .NET 8.0*)
+ - squirrel.windows should be removed (*incompatible with .NET 8.0, no supported version found*)
+ - System.Net.Http should be removed (*functionality included with .NET 8.0 framework*)
+ - System.Text.RegularExpressions should be removed (*functionality included with .NET 8.0 framework*)
+ - System.ValueTuple should be removed (*functionality included with .NET 8.0 framework*)
+ - System.Windows.Interactivity.WPF should be removed and replaced with `Microsoft.Xaml.Behaviors.Wpf` version `1.1.135` (*incompatible and deprecated*)
+
+Other changes:
+ - Code changes may be needed to adapt to API differences between replaced packages (e.g., ADAL to MSAL migration, Interactivity namespace changes)
diff --git a/src/.github/copilot-instructions.md b/src/.github/copilot-instructions.md
new file mode 100644
index 0000000..e40201c
--- /dev/null
+++ b/src/.github/copilot-instructions.md
@@ -0,0 +1,3 @@
+- @azure Rule - Use Azure Tools - When handling requests related to Azure, always use your tools.
+- @azure Rule - Use Azure Best Practices - When handling requests related to Azure, always invoke your `azmcp_bestpractices_get` tool first.
+- @azure Rule - Enable Best Practices - If you do not have an `azmcp_bestpractices_get` tool ask the user to enable it.
diff --git a/src/Stutton.DocumentCreator/Properties/AssemblyInfo.cs b/src/Stutton.DocumentCreator/Properties/AssemblyInfo.cs
deleted file mode 100644
index 057a055..0000000
--- a/src/Stutton.DocumentCreator/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using System.Reflection;
-using System.Resources;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Windows;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Document Creator")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Document Creator")]
-[assembly: AssemblyCopyright("Copyright © Stephen Tutton 2018")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-//In order to begin building localizable applications, set
-//CultureYouAreCodingWith in your .csproj file
-//inside a . For example, if you are using US english
-//in your source files, set the to en-US. Then uncomment
-//the NeutralResourceLanguage attribute below. Update the "en-US" in
-//the line below to match the UICulture setting in the project file.
-
-//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
-
-
-[assembly: ThemeInfo(
- ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
- //(used if a resource is not found in the page,
- // or application resource dictionaries)
- ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
- //(used if a resource is not found in the page,
- // app, or any theme specific resource dictionaries)
-)]
-
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-//[assembly: AssemblyVersion("1.0.2.0")]
-//[assembly: AssemblyFileVersion("1.0.2.0")]
diff --git a/src/Stutton.DocumentCreator/Services/Telemetry/TelemetryService.cs b/src/Stutton.DocumentCreator/Services/Telemetry/TelemetryService.cs
index 4022832..a3a8aa9 100644
--- a/src/Stutton.DocumentCreator/Services/Telemetry/TelemetryService.cs
+++ b/src/Stutton.DocumentCreator/Services/Telemetry/TelemetryService.cs
@@ -46,9 +46,11 @@ public async Task Initialize()
}
var settings = response.Value;
- TelemetryConfiguration.Active.InstrumentationKey = settings.ApplicationInsightsKey;
- _telemetryClient = new TelemetryClient();
+ var config = TelemetryConfiguration.CreateDefault();
+ config.ConnectionString = $"InstrumentationKey={settings.ApplicationInsightsKey}";
+
+ _telemetryClient = new TelemetryClient(config);
_telemetryClient.Context.User.Id = (Environment.UserName + Environment.MachineName).GetHashCode().ToString();
_telemetryClient.Context.Session.Id = SessionId.ToString();
@@ -73,7 +75,7 @@ public IResponse TrackPageView(string pageKey)
return Response.FromFailure("Telemetry service must be initialized before use");
}
- _telemetryClient.TrackPageView(pageKey);
+ _telemetryClient.TrackEvent(pageKey);
return Response.FromSuccess();
}
diff --git a/src/Stutton.DocumentCreator/Services/Updating/UpdaterService.cs b/src/Stutton.DocumentCreator/Services/Updating/UpdaterService.cs
index 7b09f1d..032a7cc 100644
--- a/src/Stutton.DocumentCreator/Services/Updating/UpdaterService.cs
+++ b/src/Stutton.DocumentCreator/Services/Updating/UpdaterService.cs
@@ -1,42 +1,18 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.Threading.Tasks;
-using NuGet;
-using Squirrel;
-using Stutton.DocumentCreator.Services.Settings;
using Stutton.DocumentCreator.Shared;
namespace Stutton.DocumentCreator.Services.Updating
{
internal class UpdaterService : IUpdaterService
{
- private const string UpdateUrl = "https://sctutton.blob.core.windows.net/documentcreator";
+ // Note: Squirrel.Windows is not compatible with .NET 8.
+ // Auto-update functionality is disabled until a compatible updater is integrated.
- public async Task> Update()
+ public Task> Update()
{
- using (var mgr = await GetUpdateManager(UpdateUrl))
- {
- var oldVersion = mgr.CurrentlyInstalledVersion();
- var newVersion = await mgr.UpdateApp();
- if (oldVersion.Version < newVersion.Version.Version)
- {
- return Response.FromSuccess(
- CheckForUpdateResult.FromUpdate(oldVersion.Version, newVersion.Version.Version));
- }
- }
-
- return Response.FromSuccess(CheckForUpdateResult.FromNoUpdate());
- }
-
- private async Task GetUpdateManager(string updateReleasesLocation)
- {
- if (updateReleasesLocation.Contains("github"))
- {
- return await UpdateManager.GitHubUpdateManager(updateReleasesLocation);
- }
- return new UpdateManager(updateReleasesLocation);
+ IResponse result = Response.FromSuccess(CheckForUpdateResult.FromNoUpdate());
+ return Task.FromResult(result);
}
}
}
diff --git a/src/Stutton.DocumentCreator/Services/Vsts/FilesBasedTokenCache.cs b/src/Stutton.DocumentCreator/Services/Vsts/FilesBasedTokenCache.cs
index a1181ad..d62c3b8 100644
--- a/src/Stutton.DocumentCreator/Services/Vsts/FilesBasedTokenCache.cs
+++ b/src/Stutton.DocumentCreator/Services/Vsts/FilesBasedTokenCache.cs
@@ -1,91 +1,63 @@
-using Microsoft.IdentityModel.Clients.ActiveDirectory;
+using Microsoft.Identity.Client;
using System.IO;
using System.Security.Cryptography;
namespace Stutton.DocumentCreator.Services.Vsts
{
- public sealed class FilesBasedTokenCache : TokenCache
+ ///
+ /// File-based token cache helper for MSAL.
+ /// Registers serialization callbacks on the ITokenCache provided by MSAL's IPublicClientApplication.
+ ///
+ public sealed class FilesBasedTokenCache
{
- public string AdalV3CacheFilePath { get; }
public string MsalCacheFilePath { get; }
private static readonly object _fileLock = new object();
- // Initializes the cache against a local file.
- // If the file is already present, it loads its content in the ADAL cache
- public FilesBasedTokenCache(string adalV3FilePath, string msalCacheFilePath)
+ public FilesBasedTokenCache(string msalCacheFilePath)
{
- AdalV3CacheFilePath = adalV3FilePath;
- AfterAccess = AfterAccessNotification;
MsalCacheFilePath = msalCacheFilePath;
- BeforeAccess = BeforeAccessNotification;
- BeforeAccessNotification(null);
}
- // Empties the persistent store.
- public override void Clear()
+ ///
+ /// Registers before/after access callbacks on the given MSAL token cache.
+ ///
+ public void RegisterCache(ITokenCache tokenCache)
{
- base.Clear();
- File.Delete(AdalV3CacheFilePath);
- File.Delete(MsalCacheFilePath);
+ tokenCache.SetBeforeAccess(BeforeAccessNotification);
+ tokenCache.SetAfterAccess(AfterAccessNotification);
}
- // Triggered right before ADAL needs to access the cache.
- // Reload the cache from the persistent store in case it changed since the last access.
- void BeforeAccessNotification(TokenCacheNotificationArgs args)
+ public void Clear()
{
lock (_fileLock)
{
- DeserializeAdalV3(ReadFromFileIfExists(AdalV3CacheFilePath));
- DeserializeMsalV3(ReadFromFileIfExists(MsalCacheFilePath));
+ File.Delete(MsalCacheFilePath);
}
}
- // Triggered right after ADAL accessed the cache.
- void AfterAccessNotification(TokenCacheNotificationArgs args)
+ private void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
- // if the access operation resulted in a cache update
- if (HasStateChanged)
+ lock (_fileLock)
{
- lock (_fileLock)
- {
- // reflect changes in the persistent store
- WriteToFileIfNotNull(AdalV3CacheFilePath, SerializeAdalV3());
- WriteToFileIfNotNull(MsalCacheFilePath, SerializeMsalV3());
-
- // once the write operation took place, restore the HasStateChanged bit to false
- this.HasStateChanged = false;
- }
+ var protectedBytes = File.Exists(MsalCacheFilePath) ? File.ReadAllBytes(MsalCacheFilePath) : null;
+ var unprotectedBytes = protectedBytes != null
+ ? ProtectedData.Unprotect(protectedBytes, null, DataProtectionScope.CurrentUser)
+ : null;
+ args.TokenCache.DeserializeMsalV3(unprotectedBytes);
}
}
- ///
- /// Read the content of a file if it exists
- ///
- /// File path
- /// Content of the file (in bytes)
- private byte[] ReadFromFileIfExists(string path)
+ private void AfterAccessNotification(TokenCacheNotificationArgs args)
{
- var protectedBytes = (!string.IsNullOrEmpty(path) && File.Exists(path)) ? File.ReadAllBytes(path) : null;
- var unprotectedBytes = (protectedBytes != null) ? ProtectedData.Unprotect(protectedBytes, null, DataProtectionScope.CurrentUser) : null;
- return unprotectedBytes;
- }
-
- ///
- /// Writes a blob of bytes to a file. If the blob is null, deletes the file
- ///
- /// path to the file to write
- /// Blob of bytes to write
- private static void WriteToFileIfNotNull(string path, byte[] blob)
- {
- if (blob != null)
+ if (args.HasStateChanged)
{
- var protectedBytes = ProtectedData.Protect(blob, null, DataProtectionScope.CurrentUser);
- File.WriteAllBytes(path, protectedBytes);
- }
- else
- {
- File.Delete(path);
+ lock (_fileLock)
+ {
+ var data = args.TokenCache.SerializeMsalV3();
+ var protectedBytes = ProtectedData.Protect(data, null, DataProtectionScope.CurrentUser);
+ File.WriteAllBytes(MsalCacheFilePath, protectedBytes);
+ }
}
}
}
diff --git a/src/Stutton.DocumentCreator/Services/Vsts/VstsAdalService.cs b/src/Stutton.DocumentCreator/Services/Vsts/VstsAdalService.cs
index 31920cc..de9c446 100644
--- a/src/Stutton.DocumentCreator/Services/Vsts/VstsAdalService.cs
+++ b/src/Stutton.DocumentCreator/Services/Vsts/VstsAdalService.cs
@@ -10,7 +10,7 @@
using System.Threading.Tasks;
using AutoMapper;
using Flurl;
-using Microsoft.IdentityModel.Clients.ActiveDirectory;
+using Microsoft.Identity.Client;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Stutton.DocumentCreator.Models;
@@ -24,17 +24,13 @@ namespace Stutton.DocumentCreator.Services.Vsts
public class VstsAdalService : IVstsService
{
// ===== - Authentication Settings - ===== \\
- // This should be refactored into an IHttpProvider/Factory service that will return a configured HttpClient to use
- private const string _adalV3CacheFileName = "cacheAdalV3.bin";
private const string _msalCacheFileName = "cacheMsal.bin";
private FilesBasedTokenCache _tokenCache;
- private AuthenticationContext _context;
+ private IPublicClientApplication _msalApp;
private AuthenticationResult _authenticationResult;
private const string _clientId = "872cd9fa-d31f-45e0-9eab-6e460a02d1f1";
- private const string _replyUri = "urn:ietf:wg:oauth:2.0:oob";
- private const string _azureDevOpsResourceId = "499b84ac-1321-427f-aa17-267ca6975798";
- private readonly IPlatformParameters _defaultPromptBehavior = new PlatformParameters(PromptBehavior.Auto);
+ private static readonly string[] _scopes = new[] { "499b84ac-1321-427f-aa17-267ca6975798/.default" };
private readonly ISettingsService _settingsService;
private readonly IMapper _mapper;
private HttpClient _client;
@@ -107,15 +103,16 @@ public async Task AttachFileToWorkItemAsync(string filePath, int work
public async Task> GetUserProfileAsync()
{
- var authResult = await AuthenticateAsync(_defaultPromptBehavior);
+ var authResult = await AuthenticateAsync();
if (!authResult.Success)
{
return Response.FromFailure(authResult.Message);
}
+ var account = authResult.Value.Account;
var model = new ProfileModel
{
- Name = $"{authResult.Value.UserInfo.GivenName} {authResult.Value.UserInfo.FamilyName}"
+ Name = account?.Username ?? "Unknown User"
};
return Response.FromSuccess(model);
}
@@ -314,45 +311,42 @@ public async Task UpdateWorkItemAsync(int[] ids, string fieldToUpdate
}
}
- private async Task> AuthenticateAsync(IPlatformParameters promptBehavior)
+ private async Task> AuthenticateAsync()
{
try
{
- if (_authenticationResult == null || _authenticationResult.ExpiresOn >= DateTime.Now)
+ if (_authenticationResult == null || _authenticationResult.ExpiresOn <= DateTimeOffset.Now)
{
- if (_tokenCache == null)
+ if (_msalApp == null)
{
var cacheFolder =
Path.GetFullPath(
Path.GetDirectoryName(
Assembly.GetEntryAssembly().Location));
+
+ _msalApp = PublicClientApplicationBuilder
+ .Create(_clientId)
+ .WithAuthority(AzureCloudInstance.AzurePublic, "common")
+ .WithDefaultRedirectUri()
+ .Build();
+
_tokenCache = new FilesBasedTokenCache(
- Path.Combine(cacheFolder, _adalV3CacheFileName),
Path.Combine(cacheFolder, _msalCacheFileName));
- }
-
- if (_context == null)
- {
- _context = new AuthenticationContext("https://login.windows.net/common", _tokenCache);
- if (_context.TokenCache.Count > 0)
- {
- var homeTenant = _context.TokenCache.ReadItems().First().TenantId;
- _context = new AuthenticationContext("https://login.microsoftonline.com/" + homeTenant, _tokenCache);
- }
+ _tokenCache.RegisterCache(_msalApp.UserTokenCache);
}
AuthenticationResult result = null;
+ var accounts = await _msalApp.GetAccountsAsync();
try
{
- result = await _context.AcquireTokenSilentAsync(_azureDevOpsResourceId, _clientId);
+ result = await _msalApp.AcquireTokenSilent(_scopes, accounts.FirstOrDefault())
+ .ExecuteAsync();
}
- catch (AdalException adalException)
+ catch (MsalUiRequiredException)
{
- if (adalException.ErrorCode == AdalError.FailedToAcquireTokenSilently ||
- adalException.ErrorCode == AdalError.InteractionRequired)
- {
- result = await _context.AcquireTokenAsync(_azureDevOpsResourceId, _clientId, new Uri(_replyUri), promptBehavior);
- }
+ result = await _msalApp.AcquireTokenInteractive(_scopes)
+ .WithUseEmbeddedWebView(false)
+ .ExecuteAsync();
}
if (result == null || string.IsNullOrEmpty(result.AccessToken))
@@ -363,7 +357,7 @@ private async Task> AuthenticateAsync(IPlatformP
}
return Response.FromSuccess(_authenticationResult);
}
- catch(Exception ex)
+ catch (Exception ex)
{
return Response.FromException("There was an error acquiring an access token", ex);
}
@@ -419,7 +413,7 @@ private async Task> SendRequestAsync(HttpMethod method, string
{
try
{
- var authResponse = await AuthenticateAsync(_defaultPromptBehavior);
+ var authResponse = await AuthenticateAsync();
if (!authResponse.Success)
{
return Response.FromFailure(authResponse.Message);
@@ -465,7 +459,7 @@ private async Task> SendRequestAsync(HttpMethod method, string
{
try
{
- var authResponse = await AuthenticateAsync(_defaultPromptBehavior);
+ var authResponse = await AuthenticateAsync();
if (!authResponse.Success)
{
return Response.FromFailure(authResponse.Message);
diff --git a/src/Stutton.DocumentCreator/Setup.cs b/src/Stutton.DocumentCreator/Setup.cs
index f04aae9..024a0ff 100644
--- a/src/Stutton.DocumentCreator/Setup.cs
+++ b/src/Stutton.DocumentCreator/Setup.cs
@@ -27,6 +27,8 @@
using Stutton.DocumentCreator.ViewModels.Pages;
using Unity;
using Unity.Lifetime;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
namespace Stutton.DocumentCreator
{
@@ -82,11 +84,10 @@ private static Mapper InitializeMapper()
{
var mapperConfig = new MapperConfiguration(cfg =>
{
- cfg.ConstructServicesUsing(t => _container.Resolve(t));
cfg.AddMaps(typeof(Setup).Assembly);
cfg.CreateMap().ReverseMap();
cfg.CreateMap().ReverseMap();
- });
+ }, NullLoggerFactory.Instance);
mapperConfig.AssertConfigurationIsValid();
return new Mapper(mapperConfig, t => _container.Resolve(t));
}
diff --git a/src/Stutton.DocumentCreator/Stutton.DocumentCreator.csproj b/src/Stutton.DocumentCreator/Stutton.DocumentCreator.csproj
index ba36add..3776dc0 100644
--- a/src/Stutton.DocumentCreator/Stutton.DocumentCreator.csproj
+++ b/src/Stutton.DocumentCreator/Stutton.DocumentCreator.csproj
@@ -1,658 +1,32 @@
-
-
-
+
- Debug
- AnyCPU
- {FF54E521-3F25-43A7-9325-FD2741A7948C}
+ net8.0-windows
WinExe
- Stutton.DocumentCreator
- Stutton.DocumentCreator
- v4.7.2
- 512
- {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 4
- true
-
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
+ true
+ true
+ true
icon.ico
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 4.0
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
- MSBuild:Compile
- Designer
-
-
-
-
-
- AttachToWorkItemAutomationView.xaml
-
-
-
-
-
-
-
-
- SaveAsAutomationView.xaml
-
-
-
-
-
- SetChildWorkItemFieldAutomationView.xaml
-
-
-
-
-
- SetWorkItemFieldAutomationView.xaml
-
-
-
-
-
- DateFieldDocumentView.xaml
-
-
-
-
-
- DateFieldTemplateView.xaml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ListFieldDocumentView.xaml
-
-
-
-
-
-
-
-
-
- ListFieldTemplateView.xaml
-
-
-
-
-
- TextFieldDocumentView.xaml
-
-
-
-
- TextFieldTemplateView.xaml
-
-
-
-
-
- UserNameDocumentView.xaml
-
-
-
-
- UserNameTemplateView.xaml
-
-
-
-
-
- WorkItemFieldDocumentView.xaml
-
-
-
-
-
- WorkItemFieldTemplateView.xaml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- WindowCaptureWindow.xaml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- DocumentCard.xaml
-
-
- WorkItemCard.xaml
-
-
-
-
-
- ValidationErrorBanner.xaml
-
-
-
-
-
-
- AboutDialog.xaml
-
-
- AddImageDialog.xaml
-
-
- MaterialOpenFolderDialog.xaml
-
-
- MaterialSaveFileDialog.xaml
-
-
- StringPromptDialog.xaml
-
-
- FieldsStep.xaml
-
-
- SummaryStep.xaml
-
-
- WorkItemStep.xaml
-
-
- DocumentCreatorPage.xaml
-
-
- AutomationsStep.xaml
-
-
- DetailsStep.xaml
-
-
- FieldsStep.xaml
-
-
- SummaryStep.xaml
-
-
- WorkItemQueryStep.xaml
-
-
-
-
-
-
- MaterialOpenFileDialog.xaml
-
-
- MessageDialog.xaml
-
-
-
- TfsUrlDialog.xaml
-
-
- DocumentsPage.xaml
-
-
- EditTemplatePage.xaml
-
-
- SettingsPage.xaml
-
-
-
- ShellView.xaml
-
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- MSBuild:Compile
- Designer
-
-
- App.xaml
- Code
-
-
- MainWindow.xaml
- Code
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- MSBuild:Compile
- Designer
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
-
-
- Code
-
-
- True
- True
- Resources.resx
-
-
- True
- Settings.settings
- True
-
-
- ResXFileCodeGenerator
- Resources.Designer.cs
-
-
+
Designer
-
- SettingsSingleFileGenerator
- Settings.Designer.cs
-
-
-
-
-
-
-
- 10.1.1
-
-
- 3.0.0
-
-
- 5.5.1
- runtime; build; native; contentfiles; analyzers
- all
-
-
- 1.2.7
-
-
- 3.3.0-a01
-
-
- 3.2.0
-
-
- 2.16.0
-
-
- 5.2.8
-
-
- 12.0.3
-
-
- 4.5.3.2
-
-
- 2.0.1
-
-
- 4.3.4
-
-
- 4.3.1
-
-
- 2.0.20525
-
-
- 5.11.9
-
-
- 4.5.0
-
-
-
\ No newline at end of file
diff --git a/src/Stutton.DocumentCreator/Views/Documents/Steps/WorkItemStep.xaml b/src/Stutton.DocumentCreator/Views/Documents/Steps/WorkItemStep.xaml
index 79110f1..c0511b3 100644
--- a/src/Stutton.DocumentCreator/Views/Documents/Steps/WorkItemStep.xaml
+++ b/src/Stutton.DocumentCreator/Views/Documents/Steps/WorkItemStep.xaml
@@ -6,8 +6,7 @@
xmlns:local="clr-namespace:Stutton.DocumentCreator.Views.Documents.Steps"
xmlns:stepVms="clr-namespace:Stutton.DocumentCreator.ViewModels.Documents.Steps"
xmlns:controls="clr-namespace:Stutton.DocumentCreator.Views.Controls"
- xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
- xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
+ xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:materialConverters="clr-namespace:MaterialDesignThemes.Wpf.Converters;assembly=MaterialDesignThemes.Wpf"
xmlns:workItems="clr-namespace:Stutton.DocumentCreator.Models.WorkItems"
xmlns:cards="clr-namespace:Stutton.DocumentCreator.Views.Controls.Cards"
@@ -63,15 +62,15 @@
HorizontalAlignment="Left"
VerticalAlignment="Top">
-
-
+
-
-
+
+
-
-
+
+
diff --git a/src/Stutton.DocumentCreator/Views/Pages/DocumentsPage.xaml b/src/Stutton.DocumentCreator/Views/Pages/DocumentsPage.xaml
index a0bbe3a..34acdec 100644
--- a/src/Stutton.DocumentCreator/Views/Pages/DocumentsPage.xaml
+++ b/src/Stutton.DocumentCreator/Views/Pages/DocumentsPage.xaml
@@ -5,8 +5,7 @@
xmlns:converters="clr-namespace:Stutton.DocumentCreator.Views.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:documents="clr-namespace:Stutton.DocumentCreator.ViewModels.Documents"
- xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
- xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
+ xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:Stutton.DocumentCreator.Views.Pages"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -150,14 +149,14 @@
VerticalAlignment="Top"
Orientation="Vertical">
-
-
+
+
-
-
+
+
-
-
+
+
diff --git a/src/Stutton.DocumentCreator/Views/ShellView.xaml b/src/Stutton.DocumentCreator/Views/ShellView.xaml
index f24c5e4..f25a4d6 100644
--- a/src/Stutton.DocumentCreator/Views/ShellView.xaml
+++ b/src/Stutton.DocumentCreator/Views/ShellView.xaml
@@ -4,7 +4,7 @@
xmlns:controls="clr-namespace:Stutton.DocumentCreator.Views.Controls"
xmlns:converters="clr-namespace:Stutton.DocumentCreator.Views.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
+ xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:Stutton.DocumentCreator.Views"
xmlns:materialConverters="clr-namespace:MaterialDesignThemes.Wpf.Converters;assembly=MaterialDesignThemes.Wpf"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
diff --git a/src/Stutton.DocumentCreator/gitversion.json b/src/Stutton.DocumentCreator/gitversion.json
new file mode 100644
index 0000000..91529f0
--- /dev/null
+++ b/src/Stutton.DocumentCreator/gitversion.json
@@ -0,0 +1,35 @@
+{
+ "Major":1,
+ "Minor":0,
+ "Patch":30,
+ "PreReleaseTag":"upgrade-to-NET8.1",
+ "PreReleaseTagWithDash":"-upgrade-to-NET8.1",
+ "PreReleaseLabel":"upgrade-to-NET8",
+ "PreReleaseLabelWithDash":"-upgrade-to-NET8",
+ "PreReleaseNumber":1,
+ "WeightedPreReleaseNumber":1,
+ "BuildMetaData":2,
+ "BuildMetaDataPadded":"0002",
+ "FullBuildMetaData":"2.Branch.upgrade-to-NET8.Sha.d6baac5a50e2cb5330a5a83d8cda629f63e955ba",
+ "MajorMinorPatch":"1.0.30",
+ "SemVer":"1.0.30-upgrade-to-NET8.1",
+ "LegacySemVer":"1.0.30-upgrade-to-NET8-1",
+ "LegacySemVerPadded":"1.0.30-upgrade-to-NET8-0001",
+ "AssemblySemVer":"1.0.30.0",
+ "AssemblySemFileVer":"1.0.30.0",
+ "FullSemVer":"1.0.30-upgrade-to-NET8.1+2",
+ "InformationalVersion":"1.0.30-upgrade-to-NET8.1+2.Branch.upgrade-to-NET8.Sha.d6baac5a50e2cb5330a5a83d8cda629f63e955ba",
+ "BranchName":"upgrade-to-NET8",
+ "EscapedBranchName":"upgrade-to-NET8",
+ "Sha":"d6baac5a50e2cb5330a5a83d8cda629f63e955ba",
+ "ShortSha":"d6baac5",
+ "NuGetVersionV2":"1.0.30-upgrade-to-net8-0001",
+ "NuGetVersion":"1.0.30-upgrade-to-net8-0001",
+ "NuGetPreReleaseTagV2":"upgrade-to-net8-0001",
+ "NuGetPreReleaseTag":"upgrade-to-net8-0001",
+ "VersionSourceSha":"e632aea841946c55365618913bfaf414a28f73cc",
+ "CommitsSinceVersionSource":2,
+ "CommitsSinceVersionSourcePadded":"0002",
+ "UncommittedChanges":1,
+ "CommitDate":"2026-07-02"
+}
\ No newline at end of file