Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
0ddcb61
Add support for service tasks, and add new service tasks for pdf gen…
bjorntore Jun 17, 2025
b1bcc4d
Remove default implementation of hook methods in standard service tasks.
bjorntore Jun 30, 2025
3ad4174
Skip validation if service task.
bjorntore Jun 30, 2025
2e79565
Always move to next for service tasks for now. Remoe service task res…
bjorntore Jul 2, 2025
21f71e8
Return element type on current task and process tasks to the client.
bjorntore Jul 4, 2025
fcc13bf
Some process engine method renaming.
bjorntore Jul 4, 2025
35097ee
Move current process state validation in process next into it's own m…
bjorntore Jul 4, 2025
4602c0a
Move "move next" check below result check.
bjorntore Jul 4, 2025
2cd3e82
Update PublicApi_ShouldNotChange_Unintentionally.verified.txt
bjorntore Aug 5, 2025
9fef45a
IServiceTask: Rename from params to context. Remove detailed error fi…
bjorntore Aug 6, 2025
1632b82
Remove ElementType again, as frontend didn't end up using it.
bjorntore Aug 6, 2025
6dba954
Revert adding Common namespace within ProcessTasks namespace.
bjorntore Aug 6, 2025
b8fa40e
Revert NextElement to ProcessNext rename in ProcessController.
bjorntore Aug 6, 2025
3b33b4a
IProcessEngine: Revert the rename from Next to ProcessNext back to re…
bjorntore Aug 6, 2025
c132415
Add remark about saving of data when execute returns successful result.
bjorntore Aug 6, 2025
75eab85
Log service task failures as error.
bjorntore Aug 6, 2025
d375ce4
Add test for error message when process is ended.
bjorntore Aug 7, 2025
8e058b5
Return bpmn element type to frontend.
bjorntore Aug 27, 2025
010385d
Remove useless variables.
bjorntore Sep 5, 2025
0124a54
Merge branch 'main' into feat/pdf-service-task
bjorntore Sep 5, 2025
dbdb128
Merge branch 'main' into feat/pdf-service-task
bjorntore Sep 10, 2025
3efdf3e
Merge branch 'main' into feat/pdf-service-task
bjorntore Sep 25, 2025
81aa1c3
Add default body for new method on IPdfService to avoid breaking change.
bjorntore Sep 25, 2025
064c17c
Sanitize a log.
bjorntore Sep 25, 2025
ae04d4c
Nitpick: Use PascalCase for named placeholders.
bjorntore Sep 25, 2025
8fa3a92
Prevent NRE in ProcessReader when no service tasks exists.
bjorntore Sep 25, 2025
dd37c8a
Add usings in PdfService to dispose streams when done.
bjorntore Sep 25, 2025
1da33f0
Hmm
bjorntore Sep 25, 2025
74bcaa7
Hmm 2
bjorntore Sep 25, 2025
8e21b26
Add support for custom pdf data type.
bjorntore Sep 25, 2025
f7f6191
Try catch in standard service tasks.
bjorntore Sep 25, 2025
e0139d3
Ensure no empty strings in AltinnPdfConfiguration.
bjorntore Sep 25, 2025
6559707
Make our service tasks internal sealed.
bjorntore Sep 25, 2025
45432b1
Revert "Try catch in standard service tasks."
bjorntore Sep 25, 2025
1962825
Use serviceTaskResult helper methods.
bjorntore Sep 25, 2025
defee86
Make pdf config sealed.
bjorntore Sep 25, 2025
debeef0
Add ability to stop EFormidlingServiceTask from sending eFormidling s…
bjorntore Sep 25, 2025
a80248f
Refactor configuration of eFormidling to enable setting up everything…
bjorntore Sep 26, 2025
80c6b82
Summary doc improvement.
bjorntore Sep 26, 2025
be2d6ab
Fix receiver config.
bjorntore Sep 29, 2025
168e184
Avoid breaking change in IEFormidlingReceivers.
bjorntore Sep 29, 2025
c37baab
nullcheck
bjorntore Sep 29, 2025
9376556
Don't have common eformidling config provider anyways. Just have a he…
bjorntore Sep 30, 2025
dab8d2d
Remove usage of FluentAssertions.
bjorntore Oct 1, 2025
2cd9848
assert receiver
bjorntore Oct 1, 2025
8d7ece0
Add test for exception when legacy eformidling config is null.
bjorntore Oct 1, 2025
76b634e
Fix legacy config provider name and try to make AltinnEFormidlingconf…
bjorntore Oct 1, 2025
5cad79d
add unit tests for AltinnEFormidlingConfigurationTests validate
bjorntore Oct 1, 2025
7b0a284
Change "Enabled" to "Disabled" for eFormidling. Active choice to disa…
bjorntore Oct 1, 2025
8102c43
nitpick
bjorntore Oct 1, 2025
3d73516
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 2, 2025
4769da7
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 6, 2025
60c709d
Tweak token names in DefaultEformidlingService.
bjorntore Oct 7, 2025
e3a2dc7
Add support for passing a list of task ids to the pdf component for a…
bjorntore Oct 7, 2025
e6cc72c
Add public api verified changes after adding auto pdf.
bjorntore Oct 8, 2025
0982b6a
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 13, 2025
7a13da8
Remove data type config for pdf.
bjorntore Oct 13, 2025
73b8d83
Sanitize more logs to satisfy sonar.
bjorntore Oct 13, 2025
1c7a32c
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 15, 2025
88032fb
Remove trailing semicolon.
bjorntore Oct 15, 2025
2315a72
Fix typo.
bjorntore Oct 15, 2025
f5e7499
Remove trailing semicolon.
bjorntore Oct 15, 2025
dd2d8ea
Fix typo.
bjorntore Oct 15, 2025
4b41c50
Null guard.
bjorntore Oct 15, 2025
1782006
Move process next do while inside process engine.
bjorntore Oct 16, 2025
98bae5e
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 17, 2025
9b652c2
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 21, 2025
cb9b661
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 22, 2025
318b9a9
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 22, 2025
5d30397
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 27, 2025
33ce78c
Merge branch 'main' into feat/pdf-service-task
bjorntore Oct 29, 2025
fa043be
Unit test custom pdf file name.
bjorntore Oct 29, 2025
431ac68
ProcessEngine and related tweaks from feature/fiks-io-client branch (…
danielskovli Oct 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
298 changes: 96 additions & 202 deletions src/Altinn.App.Api/Controllers/ProcessController.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static void AddEFormidlingServices<TM, TR>(this IServiceCollection servic
{
services.AddTransient(typeof(IEFormidlingReceivers), typeof(TR));
services.AddHttpClient<IEFormidlingClient, Common.EFormidlingClient.EFormidlingClient>();
services.AddTransient<IEFormidlingLegacyConfigurationProvider, EFormidlingLegacyConfigurationProvider>();
services.AddTransient<IEFormidlingService, DefaultEFormidlingService>();
services.Configure<Common.EFormidlingClient.Configuration.EFormidlingClientSettings>(
configuration.GetSection("EFormidlingClientSettings")
Expand All @@ -63,6 +64,7 @@ public static void AddEFormidlingServices2<TM, TR>(this IServiceCollection servi
{
services.AddTransient(typeof(IEFormidlingReceivers), typeof(TR));
services.AddHttpClient<IEFormidlingClient, Common.EFormidlingClient.EFormidlingClient>();
services.AddTransient<IEFormidlingLegacyConfigurationProvider, EFormidlingLegacyConfigurationProvider>();
services.AddTransient<IEFormidlingService, DefaultEFormidlingService>();
services.Configure<Common.EFormidlingClient.Configuration.EFormidlingClientSettings>(
configuration.GetSection("EFormidlingClientSettings")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Altinn.App.Core.EFormidling.Interface;
using Altinn.App.Core.Internal.App;
using Altinn.App.Core.Models;
using Altinn.Common.EFormidlingClient.Models.SBD;
using Altinn.Platform.Storage.Interface.Models;

Expand All @@ -24,17 +25,44 @@ public DefaultEFormidlingReceivers(IAppMetadata appMetadata)
/// <inheritdoc />
public async Task<List<Receiver>> GetEFormidlingReceivers(Instance instance)
{
await Task.CompletedTask;
ArgumentNullException.ThrowIfNull(instance);

Identifier identifier = new Identifier
ApplicationMetadata appMetadata = await _appMetadata.GetApplicationMetadata();

if (string.IsNullOrWhiteSpace(appMetadata.EFormidling?.Receiver))
{
return new List<Receiver>();
}

string receiver = appMetadata.EFormidling.Receiver.Trim();

return CreateReceiverList(receiver);
}

/// <inheritdoc />
public Task<List<Receiver>> GetEFormidlingReceivers(Instance instance, string? receiverFromConfig)
{
ArgumentNullException.ThrowIfNull(instance);

if (string.IsNullOrWhiteSpace(receiverFromConfig))
{
return Task.FromResult(new List<Receiver>());
}

string receiver = receiverFromConfig.Trim();

return Task.FromResult(CreateReceiverList(receiver));
}

private static List<Receiver> CreateReceiverList(string receiver)
{
var identifier = new Identifier
{
// 0192 prefix for all Norwegian organisations.
Value = $"0192:{(await _appMetadata.GetApplicationMetadata()).EFormidling.Receiver.Trim()}",
Value = $"0192:{receiver}",
Authority = "iso6523-actorid-upis",
};

Receiver receiver = new Receiver { Identifier = identifier };

return new List<Receiver> { receiver };
return [new Receiver { Identifier = identifier }];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Altinn.App.Core.Internal.Auth;
using Altinn.App.Core.Internal.Data;
using Altinn.App.Core.Internal.Events;
using Altinn.App.Core.Internal.Process.Elements.AltinnExtensionProperties;
using Altinn.App.Core.Models;
using Altinn.Common.AccessTokenClient.Services;
using Altinn.Common.EFormidlingClient;
Expand All @@ -34,6 +35,7 @@ public class DefaultEFormidlingService : IEFormidlingService
private readonly IDataClient _dataClient;
private readonly IEventsClient _eventClient;
private readonly AppImplementationFactory _appImplementationFactory;
private readonly IEFormidlingLegacyConfigurationProvider _configurationProvider;

/// <summary>
/// Initializes a new instance of the <see cref="DefaultEFormidlingService"/> class.
Expand All @@ -45,6 +47,7 @@ public DefaultEFormidlingService(
IDataClient dataClient,
IEventsClient eventClient,
IServiceProvider sp,
IEFormidlingLegacyConfigurationProvider configurationProvider,
IOptions<AppSettings>? appSettings = null,
IOptions<PlatformSettings>? platformSettings = null,
IEFormidlingClient? eFormidlingClient = null,
Expand All @@ -61,10 +64,22 @@ public DefaultEFormidlingService(
_dataClient = dataClient;
_eventClient = eventClient;
_appImplementationFactory = sp.GetRequiredService<AppImplementationFactory>();
_configurationProvider = configurationProvider;
}

/// <inheritdoc />
public async Task SendEFormidlingShipment(Instance instance)
{
await SendEFormidlingShipmentInternal(instance, await _configurationProvider.GetLegacyConfiguration());
}

/// <inheritdoc />
public async Task SendEFormidlingShipment(Instance instance, ValidAltinnEFormidlingConfiguration configuration)
{
await SendEFormidlingShipmentInternal(instance, configuration);
}

private async Task SendEFormidlingShipmentInternal(Instance instance, ValidAltinnEFormidlingConfiguration config)
{
var metadata = _appImplementationFactory.Get<IEFormidlingMetadata>();
if (
Expand All @@ -83,32 +98,32 @@ public async Task SendEFormidlingShipment(Instance instance)

ApplicationMetadata applicationMetadata = await _appMetadata.GetApplicationMetadata();

string accessToken = _tokenGenerator.GenerateAccessToken(
string userToken = _userTokenProvider.GetUserToken();
string platformAccessToken = _tokenGenerator.GenerateAccessToken(
applicationMetadata.Org,
applicationMetadata.AppIdentifier.App
);
string authzToken = _userTokenProvider.GetUserToken();

var requestHeaders = new Dictionary<string, string>
{
{ "Authorization", $"{AuthorizationSchemes.Bearer} {authzToken}" },
{ General.EFormidlingAccessTokenHeaderName, accessToken },
{ "Authorization", $"{AuthorizationSchemes.Bearer} {userToken}" },
{ General.EFormidlingAccessTokenHeaderName, platformAccessToken },
{ General.SubscriptionKeyHeaderName, _platformSettings.SubscriptionKey },
};

string instanceGuid = instance.Id.Split("/")[1];

StandardBusinessDocument sbd = await ConstructStandardBusinessDocument(instanceGuid, instance);
StandardBusinessDocument sbd = await ConstructStandardBusinessDocument(instanceGuid, instance, config);
await _eFormidlingClient.CreateMessage(sbd, requestHeaders);

(string metadataFilename, Stream stream) = await metadata.GenerateEFormidlingMetadata(instance);

using (stream)
await using (stream)
{
await _eFormidlingClient.UploadAttachment(stream, instanceGuid, metadataFilename, requestHeaders);
}

await SendInstanceData(instance, requestHeaders, metadataFilename);
await SendInstanceData(instance, requestHeaders, metadataFilename, config);

try
{
Expand All @@ -124,7 +139,8 @@ public async Task SendEFormidlingShipment(Instance instance)

private async Task<StandardBusinessDocument> ConstructStandardBusinessDocument(
string instanceGuid,
Instance instance
Instance instance,
ValidAltinnEFormidlingConfiguration config
)
{
if (_appSettings is null)
Expand All @@ -145,12 +161,11 @@ Instance instance
};

var eFormidlingReceivers = _appImplementationFactory.GetRequired<IEFormidlingReceivers>();
List<Receiver> receivers = await eFormidlingReceivers.GetEFormidlingReceivers(instance);
ApplicationMetadata appMetadata = await _appMetadata.GetApplicationMetadata();
List<Receiver> receivers = await eFormidlingReceivers.GetEFormidlingReceivers(instance, config.Receiver);

Scope scope = new Scope
{
Identifier = appMetadata.EFormidling.Process,
Identifier = config.Process,
InstanceIdentifier = Guid.NewGuid().ToString(),
Type = "ConversationId",
ScopeInformation = new List<ScopeInformation>
Expand All @@ -164,10 +179,10 @@ Instance instance
DocumentIdentification documentIdentification = new DocumentIdentification
{
InstanceIdentifier = instanceGuid,
Standard = appMetadata.EFormidling.Standard,
TypeVersion = appMetadata.EFormidling.TypeVersion,
Standard = config.Standard,
TypeVersion = config.TypeVersion,
CreationDateAndTime = completedTime,
Type = appMetadata.EFormidling.Type,
Type = config.Type,
};

StandardBusinessDocumentHeader sbdHeader = new StandardBusinessDocumentHeader
Expand All @@ -182,12 +197,12 @@ Instance instance
StandardBusinessDocument sbd = new StandardBusinessDocument
{
StandardBusinessDocumentHeader = sbdHeader,
Arkivmelding = new Arkivmelding { Sikkerhetsnivaa = appMetadata.EFormidling.SecurityLevel },
Arkivmelding = new Arkivmelding { Sikkerhetsnivaa = config.SecurityLevel },
};

if (!string.IsNullOrEmpty(appMetadata.EFormidling.DPFShipmentType))
if (!string.IsNullOrEmpty(config.DpfShipmentType))
{
sbd.Arkivmelding.DPF = new() { ForsendelsesType = appMetadata.EFormidling.DPFShipmentType };
sbd.Arkivmelding.DPF = new() { ForsendelsesType = config.DpfShipmentType };
}

return sbd;
Expand All @@ -196,7 +211,8 @@ Instance instance
private async Task SendInstanceData(
Instance instance,
Dictionary<string, string> requestHeaders,
string eformidlingMetadataFilename
string eformidlingMetadataFilename,
ValidAltinnEFormidlingConfiguration config
)
{
ApplicationMetadata applicationMetadata = await _appMetadata.GetApplicationMetadata();
Expand All @@ -211,7 +227,7 @@ string eformidlingMetadataFilename

foreach (DataElement dataElement in instance.Data.OrderBy(x => x.Created))
{
if (!applicationMetadata.EFormidling.DataTypes.Contains(dataElement.DataType))
if (!config.DataTypes.Contains(dataElement.DataType))
{
continue;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Altinn.App.Core.Internal.App;
using Altinn.App.Core.Internal.Process.Elements.AltinnExtensionProperties;
using Altinn.App.Core.Internal.Process.ProcessTasks.ServiceTasks.Legacy;
using Altinn.App.Core.Models;
using Altinn.Platform.Storage.Interface.Models;

namespace Altinn.App.Core.EFormidling.Implementation;

/// <summary>
/// A small wrapper around loading legacy eFormidling configuration from ApplicationMetadata, to be able to use the same configuration as the new eFormidling service task.
/// </summary>
/// <remarks>Should be deleted when <see cref="EformidlingServiceTaskLegacy" /> is removed.</remarks>
public interface IEFormidlingLegacyConfigurationProvider
{
/// <summary>
/// Gets validated eFormidling configuration from ApplicationMetadata (legacy).
/// </summary>
/// <returns>Validated eFormidling configuration.</returns>
Task<ValidAltinnEFormidlingConfiguration> GetLegacyConfiguration();
}

/// <inheritdoc />
internal sealed class EFormidlingLegacyConfigurationProvider : IEFormidlingLegacyConfigurationProvider
{
private readonly IAppMetadata _appMetadata;

public EFormidlingLegacyConfigurationProvider(IAppMetadata appMetadata)
{
_appMetadata = appMetadata;
}

public async Task<ValidAltinnEFormidlingConfiguration> GetLegacyConfiguration()
{
ApplicationMetadata applicationMetadata = await _appMetadata.GetApplicationMetadata();
EFormidlingContract? eFormidling = applicationMetadata.EFormidling;

if (eFormidling is null)
{
throw new ApplicationConfigException($"No legacy eFormidling configuration found in application metadata.");
}

return new ValidAltinnEFormidlingConfiguration(
true, // Enabled prop is not used in legacy mode, as whether eFormidling is enabled or not is determined in the legacy service task.
eFormidling.Receiver,
eFormidling.Process,
eFormidling.Standard,
eFormidling.TypeVersion,
eFormidling.Type,
eFormidling.SecurityLevel,
eFormidling.DPFShipmentType,
eFormidling.DataTypes?.ToList() ?? []
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,30 @@ namespace Altinn.App.Core.EFormidling.Interface;
public interface IEFormidlingReceivers
{
/// <summary>
/// Gets a list of eFormidling shipment receivers
/// Gets a list of eFormidling shipment receivers.
/// </summary>
/// <remarks>
/// <para>
/// Note that the identifier value property on the receiver objects should be prefixed with `0192:` for Norwegian organisations.
/// </para>
/// </remarks>
/// <param name="instance">Instance data</param>
/// <returns>List of eFormidling receivers</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="instance"/> is null</exception>
public Task<List<Receiver>> GetEFormidlingReceivers(Instance instance);

/// <summary>
/// Gets a list of eFormidling shipment receivers.
/// </summary>
/// <remarks>
/// <para>
/// Note that the identifier value property on the receiver objects should be prefixed with `0192:` for Norwegian organisations.
/// </para>
/// </remarks>
/// <param name="instance">Instance data</param>
/// <param name="receiverFromConfig">Receiver organization number from static configuration (BPMN or ApplicationMetadata, depending on if service task is used or not).</param>
/// <returns>List of eFormidling receivers</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="instance"/> is null</exception>
public Task<List<Receiver>> GetEFormidlingReceivers(Instance instance, string? receiverFromConfig) =>
GetEFormidlingReceivers(instance);
}
13 changes: 13 additions & 0 deletions src/Altinn.App.Core/EFormidling/Interface/IEFormidlingService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Altinn.App.Core.Internal.Process.Elements.AltinnExtensionProperties;
using Altinn.Platform.Storage.Interface.Models;

namespace Altinn.App.Core.EFormidling.Interface;
Expand All @@ -13,4 +14,16 @@ public interface IEFormidlingService
/// <param name="instance">Instance data</param>
/// <returns></returns>
public Task SendEFormidlingShipment(Instance instance);

/// <summary>
/// Send the eFormidling shipment with explicit configuration context.
/// </summary>
/// <param name="instance">Instance data</param>
/// <param name="configuration">A valid config for eFormidling.</param>
/// <returns></returns>
public Task SendEFormidlingShipment(Instance instance, ValidAltinnEFormidlingConfiguration configuration)
{
// Default implementation for backward compatibility - calls legacy method. Only meant to avoid forcing implementers to implement the new method.
return SendEFormidlingShipment(instance);
}
}
8 changes: 6 additions & 2 deletions src/Altinn.App.Core/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
using Altinn.App.Core.Internal.Process.EventHandlers;
using Altinn.App.Core.Internal.Process.EventHandlers.ProcessTask;
using Altinn.App.Core.Internal.Process.ProcessTasks;
using Altinn.App.Core.Internal.Process.ServiceTasks;
using Altinn.App.Core.Internal.Process.ProcessTasks.ServiceTasks;
using Altinn.App.Core.Internal.Process.ProcessTasks.ServiceTasks.Legacy;
using Altinn.App.Core.Internal.Registers;
using Altinn.App.Core.Internal.Secrets;
using Altinn.App.Core.Internal.Sign;
Expand Down Expand Up @@ -371,8 +372,11 @@ private static void AddProcessServices(IServiceCollection services)
services.AddTransient<IProcessTask, NullTypeProcessTask>();

// Service tasks
services.AddTransient<IPdfServiceTaskLegacy, PdfServiceTaskLegacy>();
services.AddTransient<IEFormidlingServiceTaskLegacy, EformidlingServiceTaskLegacy>();

services.AddTransient<IServiceTask, PdfServiceTask>();
services.AddTransient<IServiceTask, EformidlingServiceTask>();
services.AddTransient<IServiceTask, EFormidlingServiceTask>();
}

private static void AddActionServices(IServiceCollection services)
Expand Down
8 changes: 8 additions & 0 deletions src/Altinn.App.Core/Features/Telemetry/Telemetry.Processes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ internal void ProcessEnded(ProcessStateChange processChange)
return activity;
}

internal Activity? StartProcessExecuteServiceTaskActivity(Instance instance, string serviceTaskType)
{
var activity = ActivitySource.StartActivity($"{Prefix}.ExecuteServiceTask");
activity?.SetInstanceId(instance);
activity?.SetTag(InternalLabels.ProcessServiceTaskType, serviceTaskType);
return activity;
}

internal Activity? StartProcessEndActivity(Instance instance)
{
var activity = ActivitySource.StartActivity($"{Prefix}.End");
Expand Down
1 change: 1 addition & 0 deletions src/Altinn.App.Core/Features/Telemetry/Telemetry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ internal static class InternalLabels

internal const string ProcessErrorType = "process.error.type";
internal const string ProcessAction = "process.action";
internal const string ProcessServiceTaskType = "process.service.task.type";

internal const string ProblemType = "problem.type";
internal const string ProblemTitle = "problem.title";
Expand Down
Loading
Loading