# Building activities project settings

> Using the **UiPath.Activities.API** package from the **Official** feed (`https://pkgs.dev.azure.com/uipath/Public.Feeds/_packaging/UiPath-Official/nuget/v3/index.json`), you can create and add your own custom activity project settings in Studio. For information on how to use the API, see [Studio Activities SDK](https://docs.uipath.com/sdk/other/latest/developer-guide/studio-activities-sdk).
:::note
The **UiPath.Activities.API** package must be used as a development dependency in your custom project. Read more about [Development Dependencies](https://github.com/NuGet/Home/wiki/DevelopmentDependency-support-for-PackageReference).
:::

Using the **UiPath.Activities.API** package from the **Official** feed (`https://pkgs.dev.azure.com/uipath/Public.Feeds/_packaging/UiPath-Official/nuget/v3/index.json`), you can create and add your own custom activity project settings in Studio. For information on how to use the API, see [Studio Activities SDK](https://docs.uipath.com/sdk/other/latest/developer-guide/studio-activities-sdk).
:::note
The **UiPath.Activities.API** package must be used as a development dependency in your custom project. Read more about [Development Dependencies](https://github.com/NuGet/Home/wiki/DevelopmentDependency-support-for-PackageReference).
:::

Activity project settings encompass a set of options that can be adjusted on a project level directly from the [Project Settings](https://docs.uipath.com/studio/docs/configuring-activity-project-settings) window.

![docs image](https://dev-assets.cms.uipath.com/assets/images/sdk/sdk-docs-image-105444-81cfb0aa-ed489bd5.webp)

## Build activity settings

The following sample builds a set of settings for a music player sample activity.

### Add the tab and section

```
using UiPath.Studio.Activities.Api;
using UiPath.Studio.Activities.Api.Settings;
namespace MyCustomActivityPack
{
    public static class SettingsCreator
    {
        // This is the key used to reference a tab, even across packages.
        internal const string CategoryKey = "DemoTabUniqueKey";
        // This is the key used to reference the setting, even across packages.
        internal const string CommentTextKey = CategoryKey + ".Comment";
        internal const string PresetKey = CategoryKey + ".Preset";
        internal const string ShuffleKey = CategoryKey + ".Shuffle";
        public static void CreateSettings(IWorkflowDesignApi workflowDesignApi)
        {
            var settingsApi = workflowDesignApi.Settings;
            // Add the category (a tab in the settings page)
            var category = new SettingsCategory()
            {
                Description = "Settings Sample",
                Header = "Settings Sample",
                Key = CategoryKey
            };
            settingsApi.AddCategory(category);
            AddMusicPlayerSection(settingsApi, category);
            AddMiscSettings(settingsApi, category);
```

This adds a tab and section to the **Activity Project Settings** window. The tab description is visible when hovering over the tab's tooltip:

![docs image](https://dev-assets.cms.uipath.com/assets/images/sdk/sdk-docs-image-105220-14a97f13-1b740ff2.webp)

### Add settings

* Expandable settings section:
  ```
  private static SettingsSection AddMusicPlayerSection(IActivitiesSettingsService settingsApi, SettingsCategory category)
          {
              var section = new SettingsSection()
              {
                  Description = "Settings for a music player",
                  IsExpanded = true, //set this to control default expansion
                  Title = "Music Player Settings",
                  // the key of a section has to be unique only within the category
                  Key = "Player"
              };
              settingsApi.AddSection(category, section);
              AddSimpleBoolean(settingsApi, section);
              AddSingleChoice(settingsApi, section);
              return section;
          }
  ```

This results in:

![docs image](https://dev-assets.cms.uipath.com/assets/images/sdk/sdk-docs-image-105296-ef3d06a5-1f286055.webp)

* Radio button for Boolean values:
  ```
  private static void AddSimpleBoolean(IActivitiesSettingsService settingsApi, SettingsSection section)
          {
              var booleanSetting = new SingleValueEditorDescription<bool>
              {
                  DefaultValue = true,
                  Description = "If active, the playlist is shuffled",
                  // The value returned by GetDisplayValue should be localized
                  GetDisplayValue = b => b ? "On" : "Off",
                  Key = ShuffleKey,
                  Label = "Shuffle"
              };
              settingsApi.AddSetting(section, booleanSetting);
          }
  ```

This results in:

![docs image](https://dev-assets.cms.uipath.com/assets/images/sdk/sdk-docs-image-105683-d6e0fa5e-6835c449.webp)

* Multiple choice list of values:
  ```
  private static void AddSingleChoice(IActivitiesSettingsService settingsApi, SettingsSection category)
          {
              var booleanSetting = new SingleValueSelectorDescription
              {
                  DefaultValue = "pop",
                  Values = new[] { "classic", "pop", "rock" },
                  Description = "Sample single choice setting",
                  // The value returned by GetDisplayValue should be localized
                  GetDisplayValue = choice => choice + " music",
                  Key = PresetKey,
                  Label = "Mixer Preset"
              };
              settingsApi.AddSetting(category, booleanSetting);
          }
  ```

This results in:

![docs image](https://dev-assets.cms.uipath.com/assets/images/sdk/sdk-docs-image-105388-fc489073-837943e9.webp)

* Input text field with validation:
  ```
  private static void AddSimpleString(IActivitiesSettingsService settingsApi, SettingsSection section)
          {
              var simpleStringSetting = new SingleValueEditorDescription<string>()
              {
                  Description = "A free text comment that can't contain the word 'invalid'",
                  // The GetDisplayValue obtains a localized screen representation of the underlying setting value.
                  GetDisplayValue = LocalizeSimpleSettingValue,
                  IsReadOnly = false,
                  DefaultValue = "There is no comment",
                  Label = "Comment",
                  Validate = ValidateSimpleStringSetting,
                  Key = CommentTextKey
              };
              // Add the setting to the section.
              // A setting may also be directly added on a category. It will appear as a setting without a section (top level setting)
              settingsApi.AddSetting(section, simpleStringSetting);
          }
  private static string LocalizeSimpleSettingValue(string s) => $"A localized value of <code>{s}</code>";
  private static string ValidateSimpleStringSetting(string arg)
          {
              if (arg?.ToLowerInvariant().Contains("invalid") == true)
              {
                  return "The sample string setting is invalid if it contains the <code>invalid</code> keyword";
              }
              return string.Empty;
          }
  ```

This results in:

![docs image](https://dev-assets.cms.uipath.com/assets/images/sdk/sdk-docs-image-105392-aca0e533-562ee544.webp)

### Get process ID and logs

Using methods applied to the `IExecutorRuntime` reference, you can get information about the process ID which is being executed by the Robot, as well as execution logs. The following methods can be used:

* `IRunningJobInformation` - Collects information about the process which is being executed, and supports the following properties:
  + `JobID` - retrieves the process ID
  + `ProcessName` - retrieves the process name
  + `ProcessVersion` - retrieves the process version
  + `WorkflowFilePath` - retrieves the full path of the process
  + `InitiatedBy` - retrieves the source of a Job (Robot, Studio, Orchestrator, etc)
  + `FolderId` - retrieves the folder id of the process
  + `FolderName` - retrieves the folder name of the process
  + `TenantId` - retrieves the tenant id
  + `TenantKey` - retrieves the tenant key
  + `TenantName` - retrieves the tenant name
  + `RobotName` - retrieves the robot name
  + `LicenseType` - retrieves the robot license type
  + `RuntimeGovernanceEnabled` - provides info if runtime governance is enabled or not
  + `InternalArguments` - retrieves any internal arguments of the process
  + `OrganizationId` - retrieves the organization id
  + `PictureInPictureMode` - retrieves the type of Picture in Picture mode used. The following values are available:
    - `Main` - the process runs in the main Windows session
    - `PictureInPictureSession` - the process runs in the PiP session
    - `PictureInPictureDesktop` - the process runs in PiP virtual desktop mode
  + `LogMessage` - Generates [Robot Execution Logs](https://docs.uipath.com/robot/docs/robot-logs) according to a [Logging Level](https://docs.uipath.com/robot/docs/logging-levels) you specify. Read more about logs [on this page](https://docs.uipath.com/studio/docs/studio-logs). The following properties are supported:
  + `EventType` - the logging level to retrieve
  + `Message` - the message to display

The following code exemplifies the use of the `LogMessage` method:

```
public class MyLogMessageActivity : CodeActivity
{
    protected override void Execute(CodeActivityContext context)
    {
        var executorRuntime = context.GetExtension<IExecutorRuntime>();
        var jobInfo = executorRuntime.RunningJobInformation;
        executorRuntime.LogMessage(new LogMessage
        {
            EventType = TraceEventType.Warning,
            Message = $"Job {jobInfo.JobId}: My log message from workflow {jobInfo.WorkflowFilePath}"
        });
    }
}
```

## Add the project to Studio

To make the settings visible in Studio in the **Activity Project Settings** window, you need to publish your custom activities to a NuGet package and make it available to a feed defined in Studio, version 2019.10.1 or above.

### Create the NuGet package

![docs image](https://dev-assets.cms.uipath.com/assets/images/sdk/sdk-docs-image-105240-c0e8685d-11b926d3.gif)

1. Launch [NuGet Package Explorer](https://github.com/NuGetPackageExplorer/NuGetPackageExplorer/releases).
2. Click **Create a new package (Ctrl + N)**. A split-window is displayed which shows **Package metadata** and **Package contents**. We need to add all dependencies in the latter section.
3. Right-click the **Package contents** section. A context menu is displayed.
4. Click **Add lib folder**. Notice a new **lib** item is created in the **Package contents** section.
5. Right-click **lib** and select to **Add Existing File…**.
6. Load the external assembly (.dll) of your project.
7. Click **Edit > Edit Metadata**. The **Package metadata** section is displayed.
8. Fill in the fields as you see fit to better describe your project.
9. Fill in the **Id** field and make sure to include the keyword “Activities” so the package can be displayed in the Manage Packages window, in Studio.
10. Click **File > Save**. In our case, the `.nupkg` file is created.
    :::note
    Be sure to create an intuitive folder structure for your activities. All empty folders inside the custom activity get removed when used with Orchestrator.
    :::

### Install the NuGet package in UiPath Studio

Once the `.nupkg` file is created, add it to a custom feed in Studio, as explained [here](https://docs.uipath.com/studio/docs/managing-activities-packages#section-adding-custom-feeds).

Open the [Manage Packages](https://docs.uipath.com/studio/docs/managing-activities-packages#section-installing-packages) window and install the package. Make sure the custom feed is enabled in Studio.

## Sample settings

Put together, the above-created tab, section, and settings are visible in the **Activity Project Settings** window:

![docs image](https://dev-assets.cms.uipath.com/assets/images/sdk/sdk-docs-image-105543-69264069-d44b6961.webp)

Simply follow the link below to download the sample, which also contains an example of [Creating Custom Wizards](https://docs.uipath.com/sdk/other/latest/developer-guide/creating-custom-wizards).

[Download example](https://www.uipath.com/hubfs/Documentation/WorkflowExamples/Studio_v2019/MyCustomActivityPack.zip)
