diff --git a/Activities/Activities.FTP.sln b/Activities/Activities.FTP.sln
index 3cfd676ac..7d629c145 100644
--- a/Activities/Activities.FTP.sln
+++ b/Activities/Activities.FTP.sln
@@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.FTP", "FTP\UiPath.FT
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.FTP.Activities", "FTP\UiPath.FTP.Activities\UiPath.FTP.Activities.csproj", "{FDFC92EE-090C-4E23-9422-F90EB94C43DD}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.FTP.Activities.Design", "FTP\UiPath.FTP.Activities.Design\UiPath.FTP.Activities.Design.csproj", "{7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.FTP.Activities.Packaging", "FTP\UiPath.FTP.Activities.Packaging\UiPath.FTP.Activities.Packaging.csproj", "{6AC9D371-2E80-4933-87ED-E15EE8FE35C6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.FTP.Tests", "FTP\UiPath.FTP.Tests\UiPath.FTP.Tests.csproj", "{D35ADF63-DD01-476A-8D15-CD3FB412AE5D}"
@@ -47,10 +45,6 @@ Global
{FDFC92EE-090C-4E23-9422-F90EB94C43DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FDFC92EE-090C-4E23-9422-F90EB94C43DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FDFC92EE-090C-4E23-9422-F90EB94C43DD}.Release|Any CPU.Build.0 = Release|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Release|Any CPU.Build.0 = Release|Any CPU
{6AC9D371-2E80-4933-87ED-E15EE8FE35C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AC9D371-2E80-4933-87ED-E15EE8FE35C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AC9D371-2E80-4933-87ED-E15EE8FE35C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/Activities/Community.Activities.sln b/Activities/Community.Activities.sln
index 3422061b4..bac1a66cf 100644
--- a/Activities/Community.Activities.sln
+++ b/Activities/Community.Activities.sln
@@ -28,8 +28,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.FTP", "FTP\UiPath.FT
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.FTP.Activities", "FTP\UiPath.FTP.Activities\UiPath.FTP.Activities.csproj", "{FDFC92EE-090C-4E23-9422-F90EB94C43DD}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UiPath.FTP.Activities.Design", "FTP\UiPath.FTP.Activities.Design\UiPath.FTP.Activities.Design.csproj", "{7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{4B6FEFA2-F51E-4577-858E-320B8A094289}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "UiPath.Shared.Activities", "Shared\UiPath.Shared.Activities\UiPath.Shared.Activities.shproj", "{4E20C041-2F59-408E-ADB3-0BCFAB48DE61}"
@@ -205,18 +203,6 @@ Global
{FDFC92EE-090C-4E23-9422-F90EB94C43DD}.Release|x64.Build.0 = Release|Any CPU
{FDFC92EE-090C-4E23-9422-F90EB94C43DD}.Release|x86.ActiveCfg = Release|Any CPU
{FDFC92EE-090C-4E23-9422-F90EB94C43DD}.Release|x86.Build.0 = Release|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Debug|x64.Build.0 = Debug|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Debug|x86.Build.0 = Debug|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Release|Any CPU.Build.0 = Release|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Release|x64.ActiveCfg = Release|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Release|x64.Build.0 = Release|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Release|x86.ActiveCfg = Release|Any CPU
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E}.Release|x86.Build.0 = Release|Any CPU
{7421A593-343B-4D49-AFBE-A1B8BE179CE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7421A593-343B-4D49-AFBE-A1B8BE179CE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7421A593-343B-4D49-AFBE-A1B8BE179CE2}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -729,7 +715,6 @@ Global
{ACB02213-A7C2-4BCA-ACE2-2BFAD6E0E54C} = {D5226852-11EA-497E-9C0E-DFFCB97E9BB6}
{E9137637-B657-4C22-85A5-2E30ADF82566} = {099CA148-FA0A-44E4-8C8A-CAF7B106897E}
{FDFC92EE-090C-4E23-9422-F90EB94C43DD} = {099CA148-FA0A-44E4-8C8A-CAF7B106897E}
- {7D1DC1A6-AA81-4E6A-9081-97BF21662F4E} = {099CA148-FA0A-44E4-8C8A-CAF7B106897E}
{4E20C041-2F59-408E-ADB3-0BCFAB48DE61} = {4B6FEFA2-F51E-4577-858E-320B8A094289}
{7421A593-343B-4D49-AFBE-A1B8BE179CE2} = {4B6FEFA2-F51E-4577-858E-320B8A094289}
{C50DBC2A-7E3F-4D8A-BC91-E5F87A9B3211} = {4B6FEFA2-F51E-4577-858E-320B8A094289}
diff --git a/Activities/Credentials/UiPath.Credentials.Activities/UiPath.Credentials.Activities.csproj b/Activities/Credentials/UiPath.Credentials.Activities/UiPath.Credentials.Activities.csproj
index 0dd8695b7..f0252f89a 100644
--- a/Activities/Credentials/UiPath.Credentials.Activities/UiPath.Credentials.Activities.csproj
+++ b/Activities/Credentials/UiPath.Credentials.Activities/UiPath.Credentials.Activities.csproj
@@ -48,9 +48,6 @@
-
-
-
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/ActivitySynonymApiRegistration.cs b/Activities/FTP/UiPath.FTP.Activities.Design/ActivitySynonymApiRegistration.cs
deleted file mode 100644
index 7455d6329..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/ActivitySynonymApiRegistration.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using System.Runtime.CompilerServices;
-using UiPath.FTP.Activities.Design.Properties;
-using UiPath.Studio.Activities.Api;
-
-namespace UiPath.FTP.Activities.Design
-{
- ///
- /// Class for synonyms registration, taken from Activities Repo
- ///
- internal class ActivitySynonymApiRegistration : ApiRegistrationBase
- {
- ///
- /// Checks whether the registration of synonyms can be performed
- ///
- /// The api
- /// True or false, meaning whether the registration can be performed or not
- public override bool CanPerformRegistration(IWorkflowDesignApi api)
- {
- return api != null && api.HasFeature(DesignFeatureKeys.ActivitySynonyms);
- }
-
- ///
- /// Register synonyms for the required activities
- ///
- /// The api
- [MethodImpl(MethodImplOptions.NoInlining)]
- protected override void PerformRegistration(IWorkflowDesignApi api)
- {
- api.ActivitySynonymService.SetActivitySynonyms(typeof(WithFtpSession), new[] { Resources.ActivitySynonymUseFtpConnection });
- api.ActivitySynonymService.SetActivitySynonyms(typeof(MoveItem), new[] { Resources.ActivitySynonymMoveFileOrFolder });
- api.ActivitySynonymService.SetActivitySynonyms(typeof(Delete), new[] { Resources.ActivitySynonymDeleteFileOrFolder });
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/ApiRegistrationBase.cs b/Activities/FTP/UiPath.FTP.Activities.Design/ApiRegistrationBase.cs
deleted file mode 100644
index be0fd801c..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/ApiRegistrationBase.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-using System.Diagnostics;
-using UiPath.Studio.Activities.Api;
-
-namespace UiPath.FTP.Activities.Design
-{
- ///
- /// Base class for API registration, taken from Activities Repo
- ///
- internal abstract class ApiRegistrationBase
- {
- public void Initialize(IWorkflowDesignApi api)
- {
- try
- {
- if (!CanPerformRegistration(api))
- return;
- }
- catch (Exception ex)
- {
- Trace.TraceError(ex.ToString());
- }
-
- // Separate method to prevent JIT compilation exception
- // in case the api is not supported (for older Studio)
- PerformRegistration(api);
- }
-
- ///
- /// Checks whether the registration can be performed
- ///
- /// The api
- /// True or false, meaning whether the registration can be performed or not
- public abstract bool CanPerformRegistration(IWorkflowDesignApi api);
-
- ///
- /// Performs the registration
- ///
- /// The api
- protected abstract void PerformRegistration(IWorkflowDesignApi api);
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/DeleteDesigner.xaml b/Activities/FTP/UiPath.FTP.Activities.Design/DeleteDesigner.xaml
deleted file mode 100644
index d07d59535..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/DeleteDesigner.xaml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/DeleteDesigner.xaml.cs b/Activities/FTP/UiPath.FTP.Activities.Design/DeleteDesigner.xaml.cs
deleted file mode 100644
index 74b6f35ea..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/DeleteDesigner.xaml.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
-namespace UiPath.FTP.Activities.Design
-{
- ///
- /// Interaction logic for DeleteDesigner.xaml
- ///
- public partial class DeleteDesigner
- {
- public DeleteDesigner()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/DesignerMetadata.cs b/Activities/FTP/UiPath.FTP.Activities.Design/DesignerMetadata.cs
deleted file mode 100644
index ed183ff61..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/DesignerMetadata.cs
+++ /dev/null
@@ -1,163 +0,0 @@
-using System.Activities.Presentation.Metadata;
-using System.Activities.Presentation.View.OutlineView;
-using System.ComponentModel;
-using System.ComponentModel.Design;
-using System.Globalization;
-using UiPath.FTP.Activities.Design.Properties;
-using UiPath.Studio.Activities.Api;
-
-namespace UiPath.FTP.Activities.Design
-{
- public class DesignerMetadata : IRegisterMetadata
- {
- ///
- /// Help link template
- ///
- private const string UrlWorkflowActivitiesDocsTemplate = "https://docs.uipath.com/activities/lang-{0}/docs/{1}";
-
- ///
- /// Calls the Initialize method which will handle the registration of synonyms
- ///
- ///
- private void InitializeInternal(object api)
- {
- if (api is IWorkflowDesignApi wfDesignApi)
- {
- new ActivitySynonymApiRegistration().Initialize(wfDesignApi);
- }
- }
-
- ///
- /// Calls the private method which will handle the registration of synonyms
- ///
- ///
- public void Initialize(object api)
- {
- if (api == null)
- {
- return;
- }
- InitializeInternal(api);
- }
-
- public void Register()
- {
- AttributeTableBuilder builder = new AttributeTableBuilder();
- ShowPropertyInOutlineViewAttribute hideFromOutlineAttribute = new ShowPropertyInOutlineViewAttribute() { CurrentPropertyVisible = false, DuplicatedChildNodesVisible = false };
-
-
-
- builder.AddCustomAttributes(typeof(WithFtpSession), new DesignerAttribute(typeof(WithFtpSessionDesigner)));
- builder.AddCustomAttributes(typeof(MoveItem), new DesignerAttribute(typeof(MoveItemsDesigner)));
- builder.AddCustomAttributes(typeof(DownloadFiles), new DesignerAttribute(typeof(DownloadFilesDesigner)));
- builder.AddCustomAttributes(typeof(UploadFiles), new DesignerAttribute(typeof(UploadFilesDesigner)));
- builder.AddCustomAttributes(typeof(Delete), new DesignerAttribute(typeof(DeleteDesigner)));
- builder.AddCustomAttributes(typeof(DirectoryExists), new DesignerAttribute(typeof(DirectoryExistsDesigner)));
- builder.AddCustomAttributes(typeof(EnumerateObjects), new DesignerAttribute(typeof(EnumerateObjectsDesigner)));
- builder.AddCustomAttributes(typeof(FileExists), new DesignerAttribute(typeof(FileExistsDesigner)));
-
- builder.AddCustomAttributes(typeof(WithFtpSession), nameof(WithFtpSession.Body), hideFromOutlineAttribute);
-
- // Category
- CategoryAttribute FTPCategoryAttribute =
- new CategoryAttribute($"{Resources.CategoryAppIntegration}.{Resources.CategoryFTP}");
- builder.AddCustomAttributes(typeof(Delete), FTPCategoryAttribute);
- builder.AddCustomAttributes(typeof(DirectoryExists), FTPCategoryAttribute);
- builder.AddCustomAttributes(typeof(DownloadFiles), FTPCategoryAttribute);
- builder.AddCustomAttributes(typeof(EnumerateObjects), FTPCategoryAttribute);
- builder.AddCustomAttributes(typeof(FileExists), FTPCategoryAttribute);
- builder.AddCustomAttributes(typeof(MoveItem), FTPCategoryAttribute);
- builder.AddCustomAttributes(typeof(UploadFiles), FTPCategoryAttribute);
- builder.AddCustomAttributes(typeof(WithFtpSession), FTPCategoryAttribute);
-
- // Activities DisplayName
- builder.AddCustomAttributes(typeof(Delete), new DisplayNameAttribute(SharedResources.Activity_Delete_Name));
- builder.AddCustomAttributes(typeof(DirectoryExists), new DisplayNameAttribute(SharedResources.Activity_DirectoryExists_Name));
- builder.AddCustomAttributes(typeof(DownloadFiles), new DisplayNameAttribute(SharedResources.Activity_DownloadFiles_Name));
- builder.AddCustomAttributes(typeof(EnumerateObjects), new DisplayNameAttribute(SharedResources.Activity_EnumerateObjects_Name));
- builder.AddCustomAttributes(typeof(FileExists), new DisplayNameAttribute(SharedResources.Activity_FileExists_Name));
- builder.AddCustomAttributes(typeof(MoveItem), new DisplayNameAttribute(SharedResources.Activity_MoveItem_Name));
- builder.AddCustomAttributes(typeof(UploadFiles), new DisplayNameAttribute(SharedResources.Activity_UploadFiles_Name));
- builder.AddCustomAttributes(typeof(WithFtpSession), new DisplayNameAttribute(SharedResources.Activity_WithFtpSession_Name));
-
- // Properties and Descriptions
- var ContinueOnError = new DisplayNameAttribute(SharedResources.ContinueOnError);
- var UsernameDescription = new DescriptionAttribute(SharedResources.UsernameDescription);
- var PasswordDescription = new DescriptionAttribute(SharedResources.PasswordDescription);
- var ClientCertificatePasswordDescription = new DescriptionAttribute(SharedResources.ClientCertificatePasswordDescription);
- var HostDescription = new DescriptionAttribute(SharedResources.HostDescription);
- var PortDescription = new DescriptionAttribute(SharedResources.PortDescription);
- var RemotePathDescription = new DescriptionAttribute(SharedResources.RemotePathDescription);
- var DirectoryExistsDescription = new DescriptionAttribute(SharedResources.DirectoryExistsDescription);
- var FileExistsDescription = new DescriptionAttribute(SharedResources.FileExistsDescription);
- var FilesDescription = new DescriptionAttribute(SharedResources.FilesDescription);
- var MoveItemNewPathDescription = new DescriptionAttribute(SharedResources.NewPathDescription);
- var LocalPathDescription = new DescriptionAttribute(SharedResources.LocalPathDescription);
-
- //Delete properties
- builder.AddCustomAttributes(typeof(Delete), nameof(Delete.ContinueOnError), ContinueOnError);
- builder.AddCustomAttributes(typeof(Delete), nameof(Delete.RemotePath), RemotePathDescription);
- builder.AddCustomAttributes(typeof(Delete), new HelpKeywordAttribute(GenerateHelpLinkForActivity("ftp-delete")));
-
- //DirectoryExists properties
- builder.AddCustomAttributes(typeof(DirectoryExists), nameof(DirectoryExists.ContinueOnError), ContinueOnError);
- builder.AddCustomAttributes(typeof(DirectoryExists), nameof(DirectoryExists.RemotePath), RemotePathDescription);
- builder.AddCustomAttributes(typeof(DirectoryExists), nameof(DirectoryExists.Exists), DirectoryExistsDescription);
- builder.AddCustomAttributes(typeof(DirectoryExists), new HelpKeywordAttribute(GenerateHelpLinkForActivity("directory-exists")));
-
- //File properties
- builder.AddCustomAttributes(typeof(FileExists), nameof(FileExists.ContinueOnError), ContinueOnError);
- builder.AddCustomAttributes(typeof(FileExists), nameof(FileExists.RemotePath), RemotePathDescription);
- builder.AddCustomAttributes(typeof(FileExists), nameof(FileExists.Exists), FileExistsDescription);
- builder.AddCustomAttributes(typeof(FileExists), new HelpKeywordAttribute(GenerateHelpLinkForActivity("file-exists")));
-
- //MoveItem properties
- builder.AddCustomAttributes(typeof(MoveItem), nameof(MoveItem.ContinueOnError), ContinueOnError);
- builder.AddCustomAttributes(typeof(MoveItem), nameof(MoveItem.RemotePath), RemotePathDescription);
- builder.AddCustomAttributes(typeof(MoveItem), nameof(MoveItem.NewPath), MoveItemNewPathDescription);
- builder.AddCustomAttributes(typeof(MoveItem), new HelpKeywordAttribute(GenerateHelpLinkForActivity("move-item")));
-
- //DownloadFiles properties
- builder.AddCustomAttributes(typeof(DownloadFiles), nameof(DownloadFiles.ContinueOnError), ContinueOnError);
- builder.AddCustomAttributes(typeof(DownloadFiles), nameof(DownloadFiles.RemotePath), RemotePathDescription);
- builder.AddCustomAttributes(typeof(DownloadFiles), nameof(DownloadFiles.LocalPath), LocalPathDescription);
- builder.AddCustomAttributes(typeof(DownloadFiles), new HelpKeywordAttribute(GenerateHelpLinkForActivity("download-files")));
-
- //EnumerateObjects properties
- builder.AddCustomAttributes(typeof(EnumerateObjects), nameof(EnumerateObjects.ContinueOnError), ContinueOnError);
- builder.AddCustomAttributes(typeof(EnumerateObjects), nameof(EnumerateObjects.RemotePath), RemotePathDescription);
- builder.AddCustomAttributes(typeof(EnumerateObjects), nameof(EnumerateObjects.Files), FilesDescription);
- //builder.AddCustomAttributes(typeof(EnumerateObjects), new HelpKeywordAttribute(GenerateHelpLinkForActivity("enumerate-objects")));
-
- //UploadFiles properties
- builder.AddCustomAttributes(typeof(UploadFiles), nameof(UploadFiles.ContinueOnError), ContinueOnError);
- builder.AddCustomAttributes(typeof(UploadFiles), nameof(UploadFiles.LocalPath), LocalPathDescription);
- builder.AddCustomAttributes(typeof(UploadFiles), nameof(UploadFiles.RemotePath), RemotePathDescription);
- builder.AddCustomAttributes(typeof(UploadFiles), new HelpKeywordAttribute(GenerateHelpLinkForActivity("upload-files")));
-
- // WithFTPSession properties
- builder.AddCustomAttributes(typeof(WithFtpSession), nameof(WithFtpSession.ContinueOnError), ContinueOnError);
- builder.AddCustomAttributes(typeof(WithFtpSession), nameof(WithFtpSession.Username), UsernameDescription);
- builder.AddCustomAttributes(typeof(WithFtpSession), nameof(WithFtpSession.Password), PasswordDescription);
- builder.AddCustomAttributes(typeof(WithFtpSession), nameof(WithFtpSession.ClientCertificatePassword), ClientCertificatePasswordDescription);
- builder.AddCustomAttributes(typeof(WithFtpSession), nameof(WithFtpSession.Host), HostDescription);
- builder.AddCustomAttributes(typeof(WithFtpSession), nameof(WithFtpSession.Port), PortDescription);
- builder.AddCustomAttributes(typeof(WithFtpSession), new HelpKeywordAttribute(GenerateHelpLinkForActivity("with-ftp-session")));
-
- builder.AddCustomAttributes(typeof(WithFtpSession), nameof(WithFtpSession.UseAnonymousLogin), new DescriptionAttribute(SharedResources.UseAnonymousLoginDescription));
-
- MetadataStore.AddAttributeTable(builder.CreateTable());
- }
-
- private static string GenerateHelpLinkForActivity(string activity)
- {
- // Normally, Studio should handle the help link generation. However, this package started with some
- // hardcoded links early on, and kept doing things this way, so we can't really remove them. What we can do
- // instead is generate them in the same way Studio would, based on the language.
- var cultureCode = CultureInfo.CurrentUICulture.Name.Replace("-", "_");
- var activityLink = string.Format(UrlWorkflowActivitiesDocsTemplate, cultureCode, activity);
- return activityLink;
- }
-
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/DirectoryExistsDesigner.xaml b/Activities/FTP/UiPath.FTP.Activities.Design/DirectoryExistsDesigner.xaml
deleted file mode 100644
index 0099cfb02..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/DirectoryExistsDesigner.xaml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/DirectoryExistsDesigner.xaml.cs b/Activities/FTP/UiPath.FTP.Activities.Design/DirectoryExistsDesigner.xaml.cs
deleted file mode 100644
index 213802e20..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/DirectoryExistsDesigner.xaml.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
-namespace UiPath.FTP.Activities.Design
-{
- ///
- /// Interaction logic for DirectoryExistsDesigner.xaml
- ///
- public partial class DirectoryExistsDesigner
- {
- public DirectoryExistsDesigner()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/DownloadFilesDesigner.xaml b/Activities/FTP/UiPath.FTP.Activities.Design/DownloadFilesDesigner.xaml
deleted file mode 100644
index e4752ee91..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/DownloadFilesDesigner.xaml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/DownloadFilesDesigner.xaml.cs b/Activities/FTP/UiPath.FTP.Activities.Design/DownloadFilesDesigner.xaml.cs
deleted file mode 100644
index 8e96f6bbb..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/DownloadFilesDesigner.xaml.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
-namespace UiPath.FTP.Activities.Design
-{
- ///
- /// Interaction logic for DownloadFilesDesigner.xaml
- ///
- public partial class DownloadFilesDesigner
- {
- public DownloadFilesDesigner()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/EnumerateObjectsDesigner.xaml b/Activities/FTP/UiPath.FTP.Activities.Design/EnumerateObjectsDesigner.xaml
deleted file mode 100644
index fac49e0e3..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/EnumerateObjectsDesigner.xaml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/EnumerateObjectsDesigner.xaml.cs b/Activities/FTP/UiPath.FTP.Activities.Design/EnumerateObjectsDesigner.xaml.cs
deleted file mode 100644
index bdc1d0c5d..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/EnumerateObjectsDesigner.xaml.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
-namespace UiPath.FTP.Activities.Design
-{
- ///
- /// Interaction logic for EnumerateObjectsDesigner.xaml
- ///
- public partial class EnumerateObjectsDesigner
- {
- public EnumerateObjectsDesigner()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/FileExistsDesigner.xaml b/Activities/FTP/UiPath.FTP.Activities.Design/FileExistsDesigner.xaml
deleted file mode 100644
index 310a26b5d..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/FileExistsDesigner.xaml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/FileExistsDesigner.xaml.cs b/Activities/FTP/UiPath.FTP.Activities.Design/FileExistsDesigner.xaml.cs
deleted file mode 100644
index 0eef9e049..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/FileExistsDesigner.xaml.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
-namespace UiPath.FTP.Activities.Design
-{
- ///
- /// Interaction logic for FileExistsDesigner.xaml
- ///
- public partial class FileExistsDesigner
- {
- public FileExistsDesigner()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/MoveItemsDesigner.xaml b/Activities/FTP/UiPath.FTP.Activities.Design/MoveItemsDesigner.xaml
deleted file mode 100644
index e344d0a8a..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/MoveItemsDesigner.xaml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/MoveItemsDesigner.xaml.cs b/Activities/FTP/UiPath.FTP.Activities.Design/MoveItemsDesigner.xaml.cs
deleted file mode 100644
index 330ad6db1..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/MoveItemsDesigner.xaml.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
-namespace UiPath.FTP.Activities.Design
-{
- ///
- /// Interaction logic for MoveItemsDesigner.xaml
- ///
- public partial class MoveItemsDesigner
- {
- public MoveItemsDesigner()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/AssemblyInfo.cs b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/AssemblyInfo.cs
deleted file mode 100644
index da43d0271..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Runtime.InteropServices;
-using System.Windows.Markup;
-
-[assembly: XmlnsDefinition("http://schemas.uipath.com/workflow/activities/ftp", "UiPath.FTP.Activities.Design")]
-
-
-// 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)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM.
-
-[assembly: Guid("7d1dc1a6-aa81-4e6a-9081-97bf21662f4e")]
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/Resources.cs b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/Resources.cs
deleted file mode 100644
index be1a7d33d..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/Resources.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace UiPath.FTP.Activities.Design.Properties
-{
- internal class Resources : UiPath_FTP_Activities_Design
- {
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/SharedResources.cs b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/SharedResources.cs
deleted file mode 100644
index b8e224e5e..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/SharedResources.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using UiPath.FTP.Activities.Properties;
-
-namespace UiPath.FTP.Activities.Design.Properties
-{
- ///
- /// Class SharedResources
- /// Implements the
- ///
- public class SharedResources : UiPath_FTP_Activities
- {
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.Designer.cs b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.Designer.cs
deleted file mode 100644
index 5994db221..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.Designer.cs
+++ /dev/null
@@ -1,306 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-namespace UiPath.FTP.Activities.Design.Properties {
- using System;
-
-
- ///
- /// A strongly-typed resource class, for looking up localized strings, etc.
- ///
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- public class UiPath_FTP_Activities_Design {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal UiPath_FTP_Activities_Design() {
- }
-
- ///
- /// Returns the cached ResourceManager instance used by this class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- public static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UiPath.FTP.Activities.Design.Properties.UiPath.FTP.Activities.Design", typeof(UiPath_FTP_Activities_Design).Assembly);
- resourceMan = temp;
- }
- return resourceMan;
- }
- }
-
- ///
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- public static global::System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
- }
-
- ///
- /// Looks up a localized string similar to FTP Session Scope.
- ///
- public static string Activity_WithFtpSession_Property_DisplayName_Name {
- get {
- return ResourceManager.GetString("Activity_WithFtpSession_Property_DisplayName_Name", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Delete.
- ///
- public static string ActivitySynonymDeleteFileOrFolder {
- get {
- return ResourceManager.GetString("ActivitySynonymDeleteFileOrFolder", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Move Item.
- ///
- public static string ActivitySynonymMoveFileOrFolder {
- get {
- return ResourceManager.GetString("ActivitySynonymMoveFileOrFolder", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to With FTP connection.
- ///
- public static string ActivitySynonymUseFtpConnection {
- get {
- return ResourceManager.GetString("ActivitySynonymUseFtpConnection", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to App Integration.
- ///
- public static string CategoryAppIntegration {
- get {
- return ResourceManager.GetString("CategoryAppIntegration", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to FTP.
- ///
- public static string CategoryFTP {
- get {
- return ResourceManager.GetString("CategoryFTP", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ClientCertificatePassword.
- ///
- public static string ClientCertificatePasswordDescription {
- get {
- return ResourceManager.GetString("ClientCertificatePasswordDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ContinueOnError.
- ///
- public static string ContinueOnError {
- get {
- return ResourceManager.GetString("ContinueOnError", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Delete.
- ///
- public static string DeleteDisplayName {
- get {
- return ResourceManager.GetString("DeleteDisplayName", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Directory Exists.
- ///
- public static string DirectoryExistsDescription {
- get {
- return ResourceManager.GetString("DirectoryExistsDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Directory Exists.
- ///
- public static string DirectoryExistsDisplayName {
- get {
- return ResourceManager.GetString("DirectoryExistsDisplayName", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Download Files.
- ///
- public static string DownloadFilesDisplayName {
- get {
- return ResourceManager.GetString("DownloadFilesDisplayName", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Enumerate Objects.
- ///
- public static string EnumerateObjectsDisplayName {
- get {
- return ResourceManager.GetString("EnumerateObjectsDisplayName", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to File Exists.
- ///
- public static string FileExistsDescription {
- get {
- return ResourceManager.GetString("FileExistsDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to File Exists.
- ///
- public static string FileExistsDisplayName {
- get {
- return ResourceManager.GetString("FileExistsDisplayName", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Files.
- ///
- public static string FilesDescription {
- get {
- return ResourceManager.GetString("FilesDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Host.
- ///
- public static string HostDescription {
- get {
- return ResourceManager.GetString("HostDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to LocalPath.
- ///
- public static string LocalPathDescription {
- get {
- return ResourceManager.GetString("LocalPathDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Move Item.
- ///
- public static string MoveItemDisplayName {
- get {
- return ResourceManager.GetString("MoveItemDisplayName", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to NewPath.
- ///
- public static string MoveItemNewPathDescription {
- get {
- return ResourceManager.GetString("MoveItemNewPathDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Password.
- ///
- public static string PasswordDescription {
- get {
- return ResourceManager.GetString("PasswordDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Port.
- ///
- public static string PortDescription {
- get {
- return ResourceManager.GetString("PortDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to File or Folder to delete.
- ///
- public static string RemotePathDescription {
- get {
- return ResourceManager.GetString("RemotePathDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Upload Files.
- ///
- public static string UploadFilesDisplayName {
- get {
- return ResourceManager.GetString("UploadFilesDisplayName", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to When this box is checked, the username and password fields are ignored, and a standard anonymous user is used instead..
- ///
- public static string UseAnonymousLoginDescription {
- get {
- return ResourceManager.GetString("UseAnonymousLoginDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Username.
- ///
- public static string UsernameDescription {
- get {
- return ResourceManager.GetString("UsernameDescription", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to FTP Scope.
- ///
- public static string WithFtpSessionDisplayName {
- get {
- return ResourceManager.GetString("WithFtpSessionDisplayName", resourceCulture);
- }
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.de.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.de.resx
deleted file mode 100644
index 660624df0..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.de.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Löschen
-
-
- Element verschieben
-
-
- Mit FTP-Verbindung
-
-
- Scope der FTP-Sitzung
-
-
- App Integration
- Activity name
-
-
- FTP
-
-
- Clientzertifikatpasswort
-
-
- BeiFehlerFortsetzen
-
-
- Delete
- Activity name
-
-
- Verzeichnis vorhanden
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- Datei vorhanden
-
-
- File Exists
- Activity name
-
-
- Dateien
-
-
- Host
-
-
- LokalerPfad
-
-
- Move Item
- Activity name
-
-
- NewPath
-
-
- Kennwort
-
-
- Port
-
-
- Zu löschende Datei oder zu löschender Ordner
-
-
- Upload Files
- Activity name
-
-
- Wenn dieses Kontrollkästchen aktiviert ist, werden die Felder „Benutzername“ und „Kennwort“ ignoriert, und stattdessen wird ein anonymer Standardbenutzer verwendet.
-
-
- Benutzername
-
-
- FTP-Scope
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.es-MX.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.es-MX.resx
deleted file mode 100644
index 0305ce4b0..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.es-MX.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Eliminar
-
-
- Mover elemento
-
-
- Con conexión FTP
-
-
- Ámbito de sesión FTP
-
-
- App Integration
- Activity name
-
-
- FTP
-
-
- ClientCertificatePassword
-
-
- ContinuarConElError
-
-
- Delete
- Activity name
-
-
- El directorio existe
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- File Exists
-
-
- File Exists
- Activity name
-
-
- Archivos
-
-
- Anfitrión
-
-
- LocalPath
-
-
- Move Item
- Activity name
-
-
- Nueva ruta
-
-
- Contraseña
-
-
- Puerto
-
-
- Archivo o carpeta a eliminar
-
-
- Upload Files
- Activity name
-
-
- Cuando se marca esta casilla, se omiten los campos Nombre de usuario y Contraseña, y se utiliza un usuario anónimo estándar en su lugar.
-
-
- Nombre de usuario
-
-
- Ámbito de FTP
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.es.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.es.resx
deleted file mode 100644
index 30b2f5e60..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.es.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Eliminar
-
-
- Mover elemento
-
-
- Con conexión FTP
-
-
- Alcance de la sesión FTP
-
-
- Integración de aplicaciones
- Activity name
-
-
- FTP
-
-
- ContraseñaDelCertificadoDelCliente
-
-
- ContinuarEnCasoDeError
-
-
- Eliminar
- Activity name
-
-
- El directorio existe
-
-
- El directorio existe
- Activity name
-
-
- Descargar archivos
- Activity name
-
-
- Enumerar objetos
- Activity name
-
-
- El archivo existe
-
-
- El archivo existe
- Activity name
-
-
- Archivos
-
-
- Host
-
-
- RutaLocal
-
-
- Mover elemento
- Activity name
-
-
- NuevaRuta
-
-
- Contraseña
-
-
- Puerto
-
-
- Archivo o carpeta a eliminar
-
-
- Cargar archivos
- Activity name
-
-
- Cuando se marca esta casilla, se omiten los campos de nombre de usuario y contraseña y se utiliza un usuario anónimo estándar en su lugar.
-
-
- Nombre de usuario
-
-
- Ámbito del FTP
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.fr.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.fr.resx
deleted file mode 100644
index c8ef72663..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.fr.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Supprimer
-
-
- Move Item
-
-
- Avec connexion FTP
-
-
- Portée de la session FTP
-
-
- App Integration
- Activity name
-
-
- FTP
-
-
- MotDePasseCertificatClient
-
-
- ContinuerSurErreur
-
-
- Delete
- Activity name
-
-
- Directory Exists
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- Fichier existant
-
-
- File Exists
- Activity name
-
-
- Fichiers
-
-
- Hôte
-
-
- CheminLocal
-
-
- Move Item
- Activity name
-
-
- Nouveau chemin
-
-
- Mot de passe
-
-
- Port
-
-
- Fichier ou dossier à supprimer
-
-
- Upload Files
- Activity name
-
-
- Lorsque cette case est cochée, les champs nom d’utilisateur et mot de passe sont ignorés, et un utilisateur anonyme standard est utilisé à la place.
-
-
- Nom d'utilisateur
-
-
- Étendue FTP
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ja.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ja.resx
deleted file mode 100644
index 672e8ee7b..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ja.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- 削除
-
-
- 項目を移動
-
-
- FTP 接続を使用
-
-
- FTP セッション スコープ
-
-
- アプリの連携
- Activity name
-
-
- FTP
-
-
- クライアント証明書パスワードです。
-
-
- エラー発生時に実行を継続
-
-
- 削除
- Activity name
-
-
- ディレクトリの存在を確認します。(Directory Exists)
-
-
- ディレクトリの存在を確認
- Activity name
-
-
- ファイルをダウンロード
- Activity name
-
-
- オブジェクトを列挙
- Activity name
-
-
- ファイルの存在の有無を確認します。(File Exists)
-
-
- ファイルの存在を確認
- Activity name
-
-
- ファイルです。
-
-
- ホストです。
-
-
- ローカル パスです。
-
-
- アイテムを移動
- Activity name
-
-
- 新しいパスです。
-
-
- パスワード
-
-
- ポート
-
-
- 削除するファイルまたはフォルダーです。
-
-
- ファイルをアップロード
- Activity name
-
-
- このチェックボックスをオンにすると、ユーザー名とパスワード フィールドが無視され、代わりに標準の匿名ユーザーが使用されます。
-
-
- ユーザー名です
-
-
- FTP スコープ
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ko.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ko.resx
deleted file mode 100644
index 5ddfef278..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ko.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- 삭제
-
-
- 항목 이동
-
-
- FTP 연결 사용
-
-
- FTP 세션 범위
-
-
- App Integration
- Activity name
-
-
- FTP
-
-
- ClientCertificatePassword
-
-
- 오류 발생 시 계속 진행
-
-
- Delete
- Activity name
-
-
- 디렉터리 있음
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- 파일 있음
-
-
- File Exists
- Activity name
-
-
- 파일
-
-
- 호스트
-
-
- LocalPath
-
-
- Move Item
- Activity name
-
-
- NewPath
-
-
- 암호
-
-
- 포트
-
-
- 삭제할 파일 또는 폴더
-
-
- Upload Files
- Activity name
-
-
- 이 상자를 선택하면, 사용자 이름 및 암호 필드가 무시되고 표준 익명 사용자가 대신 사용됩니다.
-
-
- 사용자 이름
-
-
- FTP 범위
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.pt-BR.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.pt-BR.resx
deleted file mode 100644
index 3dec38e6a..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.pt-BR.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Excluir
-
-
- Mover item
-
-
- Com conexão FTP
-
-
- Escopo da sessão do FTP
-
-
- App Integration
- Activity name
-
-
- FTP
-
-
- SenhadoCertificadodoCliente
-
-
- ContinuarComErro
-
-
- Delete
- Activity name
-
-
- O diretório existe
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- O arquivo existe
-
-
- File Exists
- Activity name
-
-
- Arquivos
-
-
- Host
-
-
- CaminhoLocal
-
-
- Move Item
- Activity name
-
-
- NovoCaminho
-
-
- Senha
-
-
- Porta
-
-
- Arquivo ou pasta a ser excluído
-
-
- Upload Files
- Activity name
-
-
- Quando esta caixa está marcada, os campos de nome de usuário e senha são ignorados, e um usuário anônimo padrão é usado.
-
-
- Nome de Usuário
-
-
- Escopo do FTP
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.pt.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.pt.resx
deleted file mode 100644
index 0338025fb..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.pt.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Eliminar
-
-
- Move Item
-
-
- Com ligação FTP
-
-
- Âmbito da Sessão de FTP
-
-
- App Integration
- Activity name
-
-
- FTP
-
-
- Palavra-passeCertificadoCliente
-
-
- ContinueNoErro
-
-
- Delete
- Activity name
-
-
- O Diretório Existe
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- O Ficheiro Existe
-
-
- File Exists
- Activity name
-
-
- Ficheiros
-
-
- Anfitrião
-
-
- LocalPath
-
-
- Move Item
- Activity name
-
-
- NewPath
-
-
- Palavra-passe
-
-
- Porta
-
-
- Ficheiro ou Pasta a Eliminar
-
-
- Upload Files
- Activity name
-
-
- Quando esta caixa está selecionada, os campos de nome de utilizador e palavra-passe são ignorados e, em alternativa, é utilizado um utilizador anónimo padrão.
-
-
- Nome de utilizador
-
-
- Âmbito FTP
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.resx
deleted file mode 100644
index 711d53aa3..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Delete
-
-
- Move Item
-
-
- With FTP connection
-
-
- FTP Session Scope
-
-
- App Integration
- Activity name
-
-
- FTP
-
-
- ClientCertificatePassword
-
-
- ContinueOnError
-
-
- Delete
- Activity name
-
-
- Directory Exists
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- File Exists
-
-
- File Exists
- Activity name
-
-
- Files
-
-
- Host
-
-
- LocalPath
-
-
- Move Item
- Activity name
-
-
- NewPath
-
-
- Password
-
-
- Port
-
-
- File or Folder to delete
-
-
- Upload Files
- Activity name
-
-
- When this box is checked, the username and password fields are ignored, and a standard anonymous user is used instead.
-
-
- Username
-
-
- FTP Scope
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ro.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ro.resx
deleted file mode 100644
index 2dbf04bc1..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ro.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Ștergeți
-
-
- Mută obiectul
-
-
- Cu conexiune FTP
-
-
- Domeniul sesiunii FTP
-
-
- App Integration
- Activity name
-
-
- FTP
-
-
- ClientCertificatePassword
-
-
- ContinueOnError
-
-
- Delete
- Activity name
-
-
- Există directorul
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- Fișierul există
-
-
- File Exists
- Activity name
-
-
- Fișiere
-
-
- Gazdă
-
-
- LocalPath
-
-
- Move Item
- Activity name
-
-
- NewPath
-
-
- Parolă
-
-
- Port
-
-
- Fișier sau folder de șters
-
-
- Upload Files
- Activity name
-
-
- Când această căsuță este bifată, câmpurile pentru numele de utilizator și parolă sunt ignorate, iar în schimb se folosește un utilizator anonim standard.
-
-
- Nume de utilizator
-
-
- FTP Scope
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ru.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ru.resx
deleted file mode 100644
index 06e78e84f..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.ru.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Удалить
-
-
- Переместить элемент
-
-
- С FTP-соединением
-
-
- Область действия сеанса FTP
-
-
- Интеграция приложений
- Activity name
-
-
- FTP
-
-
- ClientCertificatePassword
-
-
- ПродолжитьПриОшибке
-
-
- Delete
- Activity name
-
-
- Каталог существует
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- Файл существует
-
-
- File Exists
- Activity name
-
-
- Файлы
-
-
- Хост
-
-
- LocalPath
-
-
- Move Item
- Activity name
-
-
- NewPath
-
-
- Пароль
-
-
- Порт
-
-
- Файл или папка для удаления
-
-
- Upload Files
- Activity name
-
-
- Если установлен этот флажок, поля с именем пользователя и паролем игнорируются, а вместо этого используется стандартный анонимный пользователь.
-
-
- Пользователь
-
-
- Область FTP
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.tr.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.tr.resx
deleted file mode 100644
index 1649401a4..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.tr.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- Sil
-
-
- Öğeyi Taşı
-
-
- FTP bağlantısı ile
-
-
- FTP Oturum Kapsamı
-
-
- App Integration
- Activity name
-
-
- FTP
-
-
- İstemciSertifikasıParolası
-
-
- HataOlduğundaDevamEt
-
-
- Delete
- Activity name
-
-
- Dizin Var
-
-
- Directory Exists
- Activity name
-
-
- Download Files
- Activity name
-
-
- Enumerate Objects
- Activity name
-
-
- Dosya Var
-
-
- File Exists
- Activity name
-
-
- Dosyalar
-
-
- Ana Bilgisayar
-
-
- LocalPath
-
-
- Move Item
- Activity name
-
-
- NewPath
-
-
- Parola
-
-
- Bağlantı Noktası
-
-
- Silinecek dosya veya klasör
-
-
- Upload Files
- Activity name
-
-
- Bu kutu işaretlendiğinde kullanıcı adı ve parola alanları yok sayılır ve bunun yerine standart bir anonim kullanıcı kullanılır.
-
-
- Kullanıcı adı
-
-
- FTP Kapsamı
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.zh-CN.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.zh-CN.resx
deleted file mode 100644
index a6da83f2e..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.zh-CN.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- 删除
-
-
- 移动项目
-
-
- 使用 FTP 连接
-
-
- FTP 会话作用域
-
-
- 应用程序集成
- Activity name
-
-
- FTP
-
-
- 客户端证书密码
-
-
- 出错时继续
-
-
- 删除
- Activity name
-
-
- 目录存在
-
-
- 目录存在
- Activity name
-
-
- 下载文件
- Activity name
-
-
- 枚举对象
- Activity name
-
-
- 文件存在
-
-
- 文件存在
- Activity name
-
-
- 文件
-
-
- 主机
-
-
- 本地路径
-
-
- 移动项目
- Activity name
-
-
- 新路径
-
-
- 密码
-
-
- 端口
-
-
- 要删除的文件/文件夹
-
-
- 上传文件
- Activity name
-
-
- 选中此复选框时,将忽略用户名和密码字段,并改用标准匿名用户。
-
-
- 用户名
-
-
- FTP 作用域
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.zh-TW.resx b/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.zh-TW.resx
deleted file mode 100644
index f7de3b0a4..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/Properties/UiPath.FTP.Activities.Design.zh-TW.resx
+++ /dev/null
@@ -1,209 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- 刪除
-
-
- 移動項目
-
-
- 使用 FTP 連線
-
-
- FTP 工作階段範圍
-
-
- 應用程式整合
- Activity name
-
-
- FTP
-
-
- 用戶端憑證密碼
-
-
- 錯誤時繼續
-
-
- 刪除
- Activity name
-
-
- 目錄存在
-
-
- 目錄存在
- Activity name
-
-
- 下載檔案
- Activity name
-
-
- 列舉對象
- Activity name
-
-
- 檔案存在
-
-
- 檔案存在
- Activity name
-
-
- 檔案
-
-
- 主機
-
-
- 本機路徑
-
-
- 移動項目
- Activity name
-
-
- 新路徑
-
-
- 密碼
-
-
- 連接埠
-
-
- 要刪除的檔案或資料夾
-
-
- 上傳檔案
- Activity name
-
-
- 勾選此方塊時,將忽略使用者名稱和密碼欄位,並改用標準匿名使用者。
-
-
- 使用者名稱
-
-
- FTP 範圍
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/ReleaseNotes.txt b/Activities/FTP/UiPath.FTP.Activities.Design/ReleaseNotes.txt
deleted file mode 100644
index e69de29bb..000000000
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/UiPath.FTP.Activities.Design.csproj b/Activities/FTP/UiPath.FTP.Activities.Design/UiPath.FTP.Activities.Design.csproj
deleted file mode 100644
index eb400d1c4..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/UiPath.FTP.Activities.Design.csproj
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
- $(WindowsFramework)
- $(ProjectDir)..\..\Output\Activities\FTP\
- true
-
-
-
-
-
-
-
- Controls\ActivityDecoratorControl.cs
-
-
-
-
- Themes\Generic.xaml
- MSBuild:Compile
- Designer
-
-
-
-
- {fdfc92ee-090c-4e23-9422-f90eb94c43dd}
- UiPath.FTP.Activities
-
-
- {e9137637-b657-4c22-85a5-2e30adf82566}
- UiPath.FTP
-
-
-
-
-
-
-
- True
- True
- UiPath.FTP.Activities.Design.resx
-
-
-
-
- UiPath.FTP.Activities.Design.resx
-
-
- PublicResXFileCodeGenerator
- UiPath.FTP.Activities.Design.Designer.cs
-
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/UploadFilesDesigner.xaml b/Activities/FTP/UiPath.FTP.Activities.Design/UploadFilesDesigner.xaml
deleted file mode 100644
index 692c2cbd9..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/UploadFilesDesigner.xaml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/UploadFilesDesigner.xaml.cs b/Activities/FTP/UiPath.FTP.Activities.Design/UploadFilesDesigner.xaml.cs
deleted file mode 100644
index b92ae5539..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/UploadFilesDesigner.xaml.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
-namespace UiPath.FTP.Activities.Design
-{
- ///
- /// Interaction logic for UploadFilesDesigner.xaml
- ///
- public partial class UploadFilesDesigner
- {
- public UploadFilesDesigner()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/WithFtpSessionDesigner.xaml b/Activities/FTP/UiPath.FTP.Activities.Design/WithFtpSessionDesigner.xaml
deleted file mode 100644
index 169b29c7b..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/WithFtpSessionDesigner.xaml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities.Design/WithFtpSessionDesigner.xaml.cs b/Activities/FTP/UiPath.FTP.Activities.Design/WithFtpSessionDesigner.xaml.cs
deleted file mode 100644
index 426b2d63e..000000000
--- a/Activities/FTP/UiPath.FTP.Activities.Design/WithFtpSessionDesigner.xaml.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace UiPath.FTP.Activities.Design
-{
- public partial class WithFtpSessionDesigner
- {
- public WithFtpSessionDesigner()
- {
- InitializeComponent();
- }
- }
-}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/UiPath.FTP.Activities.Packaging.csproj b/Activities/FTP/UiPath.FTP.Activities.Packaging/UiPath.FTP.Activities.Packaging.csproj
index d4a1c7bc4..49aa8106a 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/UiPath.FTP.Activities.Packaging.csproj
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/UiPath.FTP.Activities.Packaging.csproj
@@ -1,6 +1,6 @@
- $(PortableFramework);$(WindowsFramework)
+ $(PortableFramework)..\..\Output\Activities\FTP\
@@ -52,10 +52,6 @@
%(RecursiveDir)%(Filename)%(Extension)
-
-
-
-
@@ -78,11 +74,6 @@
-
-
- All
-
- All
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/Delete.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/Delete.md
index 6247be3a6..92ee8c882 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/Delete.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/Delete.md
@@ -2,7 +2,7 @@
`UiPath.FTP.Activities.Delete`
-Removes a specified file from an FTP server. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
+Removes a file or folder from an FTP server. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
**Package:** `UiPath.FTP.Activities`
**Category:** FTP
@@ -13,13 +13,13 @@ Removes a specified file from an FTP server. This activity only works if it is p
| Name | Display Name | Kind | Type | Required | Default | Placeholder | Description |
|------|-------------|------|------|----------|---------|-------------|-------------|
-| `RemotePath` | File or folder to delete | InArgument | `string` | Yes | | | Remote path to the file or folder. |
+| `RemotePath` | File or folder to delete | InArgument | `string` | Yes | | `/remote/folder/file.txt` | Remote path to the file or folder. |
### Configuration
| Name | Display Name | Type | Default | Description |
|------|-------------|------|---------|-------------|
-| `ContinueOnError` | Continue On Error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
+| `ContinueOnError` | Continue on error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
## XAML Example
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/DirectoryExists.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/DirectoryExists.md
index e0c953328..ce0d511fb 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/DirectoryExists.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/DirectoryExists.md
@@ -1,8 +1,8 @@
-# Directory Exists
+# Check If Folder Exists
`UiPath.FTP.Activities.DirectoryExists`
-Checks whether a certain directory exists on an FTP server. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
+Checks whether a folder exists on an FTP server. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
**Package:** `UiPath.FTP.Activities`
**Category:** FTP
@@ -13,24 +13,28 @@ Checks whether a certain directory exists on an FTP server. This activity only w
| Name | Display Name | Kind | Type | Required | Default | Placeholder | Description |
|------|-------------|------|------|----------|---------|-------------|-------------|
-| `RemotePath` | Folder Path | InArgument | `string` | Yes | | | Remote folder path to check. |
+| `RemotePath` | Folder path | InArgument | `string` | Yes | | `/remote/folder` | Remote folder path to check. |
### Configuration
| Name | Display Name | Type | Default | Description |
|------|-------------|------|---------|-------------|
-| `ContinueOnError` | Continue On Error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
+| `ContinueOnError` | Continue on error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
### Output
| Name | Display Name | Kind | Type | Description |
|------|-------------|------|------|-------------|
-| `Exists` | Exists | OutArgument | `bool` | A boolean variable that states whether the indicated directory was found or not. |
+| `Exists` | Exists | OutArgument | `bool` | A boolean variable that states whether the indicated folder was found or not. |
+
+> **A symbolic link pointing at a folder returns `False` on SFTP.** The SSH library classifies links as
+> regular files, so this activity does not see them as folders. See
+> [List Files and Folders](EnumerateObjects.md) for the full explanation. FTP and FTPS are unaffected.
## XAML Example
Requires the FTP namespace (`xmlns:ftp="http://schemas.uipath.com/workflow/activities/ftp"`, see [overview](../overview.md#xaml-namespace)) and must run inside a [`WithFtpSession`](WithFtpSession.md) scope.
```xml
-
+
```
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/DownloadFiles.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/DownloadFiles.md
index 6fd2fddf0..d3940eab9 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/DownloadFiles.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/DownloadFiles.md
@@ -13,17 +13,33 @@ Downloads the specified files from an FTP server to the specified local folder.
| Name | Display Name | Kind | Type | Required | Default | Placeholder | Description |
|------|-------------|------|------|----------|---------|-------------|-------------|
-| `RemotePath` | Path to files to download | InArgument | `string` | Yes | | | The path of the files on the FTP server that are to be downloaded. |
-| `LocalPath` | Where to download | InArgument | `string` | Yes | | | The local path for the files that are to be downloaded. |
-| `Recursive` | Include subfolders | Property | `bool` | | | | If this box is checked, the folders will be downloaded with their respective subfolders. |
-| `Create` | Create | Property | `bool` | | | | If this box is checked, the folder path will be created locally in case it does not already exist. |
-| `Overwrite` | Overwrite | Property | `bool` | | | | If this box is checked, the files will be overwritten locally if they're already stored there. |
+| `RemotePath` | Path to files to download | InArgument | `string` | Yes | | `/remote/folder` | The path of the files on the FTP server that are to be downloaded. |
+| `LocalPath` | Where to download | InArgument | `string` | Yes | | `C:\Local\folder` | The local path for the files that are to be downloaded. |
+| `Recursive` | Include subfolders | Property | `bool` | | | | If turned on, the folders are downloaded with their respective subfolders. |
+| `Create` | Create folder if missing | Property | `bool` | | | | If turned on, the folder path is created locally in case it does not already exist. |
+| `Overwrite` | Overwrite existing files | Property | `bool` | | | | If turned on, the files are overwritten locally if they are already stored there. |
### Configuration
| Name | Display Name | Type | Default | Description |
|------|-------------|------|---------|-------------|
-| `ContinueOnError` | Continue On Error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
+| `ContinueOnError` | Continue on error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
+
+## Behaviour notes
+
+These apply to `Recursive="True"`:
+
+- **Symbolic links are not descended into.** On SFTP a link is still transferred as a file (the server
+ follows it on open), but the walk does not treat it as a folder, so files underneath a linked folder
+ are not downloaded. This prevents a link cycle from recursing forever.
+- **A sub-folder the server lists but refuses to open is skipped, not fatal.** Its contents are simply
+ not downloaded, the path is written to the trace log as a warning, and the rest of the transfer
+ completes. Note the activity reports success in this case — check the trace if you need certainty
+ that every file was retrieved.
+- **Connection and timeout failures still fail the activity**, so a dropped connection is never
+ reported as a completed download.
+- **A bad `RemotePath` still fails.** The tolerance above applies only to sub-folders discovered during
+ the walk.
## XAML Example
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/EnumerateObjects.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/EnumerateObjects.md
index 093c2b503..c97da256c 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/EnumerateObjects.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/EnumerateObjects.md
@@ -1,8 +1,8 @@
-# Enumerate Objects
+# List Files and Folders
`UiPath.FTP.Activities.EnumerateObjects`
-Generates a collection of files that have been found on the FTP server. Subfolders can also be included in the search by checking the Includes subfolders box. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
+Generates a collection of the files and folders found on the FTP server. Subfolders can also be included by turning on Include subfolders. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
**Package:** `UiPath.FTP.Activities`
**Category:** FTP
@@ -13,21 +13,21 @@ Generates a collection of files that have been found on the FTP server. Subfolde
| Name | Display Name | Kind | Type | Required | Default | Placeholder | Description |
|------|-------------|------|------|----------|---------|-------------|-------------|
-| `RemotePath` | Remote Path | InArgument | `string` | Yes | | | The path of the directory on the FTP server whose files are to be enumerated. |
-| `Recursive` | Include subfolders | Property | `bool` | | | | If this check box is selected, the subfolders are also included in the enumeration of the files on the FTP server. |
-| `Filter` | Object types | Property | `FtpFilterObjectType` | | `Directory \| File \| Link \| Other` (all) | | Filters returned items by type (selected types are included). See enum + semantics below. |
+| `RemotePath` | Folder path | InArgument | `string` | Yes | | `/remote/folder` | The path of the folder on the FTP server whose contents are listed. |
+| `Recursive` | Include subfolders | Property | `bool` | | | | If turned on, the subfolders are also included in the listing. |
+| `Filter` | Item types to include | Property | `FtpFilterObjectType` | | `Directory \| File \| Link \| Other` (all) | `Select the item types to include` | Filters returned items by type (selected types are included). See enum + semantics below. |
### Configuration
| Name | Display Name | Type | Default | Description |
|------|-------------|------|---------|-------------|
-| `ContinueOnError` | Continue On Error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
+| `ContinueOnError` | Continue on error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
### Output
| Name | Display Name | Kind | Type | Description |
|------|-------------|------|------|-------------|
-| `Files` | Files | OutArgument | `IEnumerable` | A collection of files that have been found on the FTP server. |
+| `Files` | Files and folders | OutArgument | `IEnumerable` | The collection of files and folders found on the FTP server. |
## `FtpFilterObjectType` (the `Filter` property)
@@ -37,8 +37,8 @@ Generates a collection of files that have been found on the FTP server. Subfolde
|-------|---------|---------|
| `None` | 0 | Returns an **empty** collection. |
| `Directory` | 1 | Include directories. |
-| `File` | 2 | Include regular files. |
-| `Link` | 4 | Include symbolic links. |
+| `File` | 2 | Include regular files. On SFTP this also includes symbolic links — see the note below. |
+| `Link` | 4 | Include symbolic links. **On SFTP this matches nothing** — see the note below. |
| `Other` | 8 | Include other entries (named pipe, device, etc.). |
**Semantics (as implemented):**
@@ -49,6 +49,27 @@ Generates a collection of files that have been found on the FTP server. Subfolde
Each returned `FtpObjectInfo` also carries its `Type` (`ftp:FtpObjectType`: `Directory`/`File`/`Link`/`Other`), so you can alternatively filter the output collection yourself.
+> **Symbolic links on SFTP are reported as `File`, not `Link`.** The SSH library treats a link as a
+> regular file, so on an SFTP connection `Filter="Link"` returns nothing and `Filter="File"` includes
+> links alongside real files. FTP and FTPS are unaffected and report `Link` correctly. If you need to
+> tell links apart on SFTP, this activity cannot currently do it.
+
+## Behaviour notes
+
+These apply to `Recursive="True"`:
+
+- **Symbolic links are not followed.** A link is listed in the results, but the walk does not descend
+ into it, so files underneath it are not returned. This prevents a link cycle from recursing forever.
+- **A sub-folder the server lists but refuses to open is skipped, not fatal.** Servers can return an
+ entry from a directory listing and then reject an attempt to open it — a dangling link, a stale
+ mount point, an entry deleted mid-walk. The sub-folder still appears in the results, its contents
+ are omitted, the offending path is written to the trace log as a warning, and the rest of the
+ listing completes.
+- **Connection and timeout failures still fail the activity.** A dropped connection is never reported
+ as a successful partial listing.
+- **A bad `RemotePath` still fails.** The tolerance above applies only to sub-folders discovered
+ during the walk, never to the path you asked for.
+
## XAML Example
Requires the FTP namespace (`xmlns:ftp="http://schemas.uipath.com/workflow/activities/ftp"`) and must run inside a [`WithFtpSession`](WithFtpSession.md) scope. `Files` is an `OutArgument>`.
@@ -56,7 +77,7 @@ Requires the FTP namespace (`xmlns:ftp="http://schemas.uipath.com/workflow/activ
List **files only** in the current remote folder:
```xml
-
```
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/FileExists.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/FileExists.md
index d09ac1d13..7d1630a9e 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/FileExists.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/FileExists.md
@@ -1,8 +1,8 @@
-# File Exists
+# Check If File Exists
`UiPath.FTP.Activities.FileExists`
-Checks whether a certain file exists in the specified FTP directory. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
+Checks whether a file exists in the specified FTP folder. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
**Package:** `UiPath.FTP.Activities`
**Category:** FTP
@@ -13,13 +13,13 @@ Checks whether a certain file exists in the specified FTP directory. This activi
| Name | Display Name | Kind | Type | Required | Default | Placeholder | Description |
|------|-------------|------|------|----------|---------|-------------|-------------|
-| `RemotePath` | File Path | InArgument | `string` | Yes | | | Remote file path to check. |
+| `RemotePath` | File path | InArgument | `string` | Yes | | `/remote/folder/file.txt` | Remote file path to check. |
### Configuration
| Name | Display Name | Type | Default | Description |
|------|-------------|------|---------|-------------|
-| `ContinueOnError` | Continue On Error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
+| `ContinueOnError` | Continue on error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
### Output
@@ -27,10 +27,14 @@ Checks whether a certain file exists in the specified FTP directory. This activi
|------|-------------|------|------|-------------|
| `Exists` | Exists | OutArgument | `bool` | A boolean variable that states whether the indicated file was found or not. |
+> **On SFTP this also returns `True` for a symbolic link**, whatever the link points at, because the
+> SSH library classifies links as regular files. See [List Files and Folders](EnumerateObjects.md).
+> FTP and FTPS are unaffected.
+
## XAML Example
Requires the FTP namespace (`xmlns:ftp="http://schemas.uipath.com/workflow/activities/ftp"`, see [overview](../overview.md#xaml-namespace)) and must run inside a [`WithFtpSession`](WithFtpSession.md) scope.
```xml
-
+
```
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/MoveItem.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/MoveItem.md
index 3560b18cd..2b1d2ad0f 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/MoveItem.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/MoveItem.md
@@ -13,15 +13,15 @@ Moves an item on an FTP server to a different remote path. This activity only wo
| Name | Display Name | Kind | Type | Required | Default | Placeholder | Description |
|------|-------------|------|------|----------|---------|-------------|-------------|
-| `RemotePath` | File or folder to move | InArgument | `string` | Yes | | | Remote path of the item to move. |
-| `NewPath` | Where to move | InArgument | `string` | Yes | | | The new remote path to move the item to. |
-| `Overwrite` | Overwrite | Property | `bool` | | | | If this box is checked, the files will be overwritten in the new remote directory if they're already stored there. |
+| `RemotePath` | File or folder to move | InArgument | `string` | Yes | | `/remote/folder/file.txt` | Remote path of the item to move. |
+| `NewPath` | Where to move | InArgument | `string` | Yes | | `/remote/new-folder/file.txt` | The new remote path to move the item to. |
+| `Overwrite` | Overwrite existing files | Property | `bool` | | | | If turned on, the files are overwritten in the new remote folder if they are already stored there. |
### Configuration
| Name | Display Name | Type | Default | Description |
|------|-------------|------|---------|-------------|
-| `ContinueOnError` | Continue On Error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
+| `ContinueOnError` | Continue on error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
## XAML Example
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/UploadFiles.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/UploadFiles.md
index 85c4d07f0..0e776c657 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/UploadFiles.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/UploadFiles.md
@@ -2,7 +2,7 @@
`UiPath.FTP.Activities.UploadFiles`
-Uploads a file to an FTP server. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
+Uploads files to an FTP server. This activity only works if it is placed inside a [Use FTP Connection](WithFtpSession.md) scope activity.
**Package:** `UiPath.FTP.Activities`
**Category:** FTP
@@ -13,17 +13,17 @@ Uploads a file to an FTP server. This activity only works if it is placed inside
| Name | Display Name | Kind | Type | Required | Default | Placeholder | Description |
|------|-------------|------|------|----------|---------|-------------|-------------|
-| `LocalPath` | Files to upload | InArgument | `string` | Yes | | | Local path of the files to upload. |
-| `RemotePath` | Where to upload | InArgument | `string` | Yes | | | Remote destination path on the FTP server. |
-| `Recursive` | Include subfolders | Property | `bool` | | | | If this box is checked, the folders will be uploaded with their respective subfolders. |
-| `Create` | Create | Property | `bool` | | | | If this box is checked, the folder path will be created on the FTP server in case it does not already exist. |
-| `Overwrite` | Overwrite | Property | `bool` | | | | If this box is checked, the files will be overwritten on the FTP server if they're already stored there. |
+| `LocalPath` | Files to upload | InArgument | `string` | Yes | | `C:\Local\folder` | Local path of the files to upload. |
+| `RemotePath` | Where to upload | InArgument | `string` | Yes | | `/remote/folder` | Remote destination path on the FTP server. |
+| `Recursive` | Include subfolders | Property | `bool` | | | | If turned on, the folders are uploaded with their respective subfolders. |
+| `Create` | Create folder if missing | Property | `bool` | | | | If turned on, the folder path is created on the FTP server in case it does not already exist. |
+| `Overwrite` | Overwrite existing files | Property | `bool` | | | | If turned on, the files are overwritten on the FTP server if they are already stored there. |
### Configuration
| Name | Display Name | Type | Default | Description |
|------|-------------|------|---------|-------------|
-| `ContinueOnError` | Continue On Error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
+| `ContinueOnError` | Continue on error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
## XAML Example
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/WithFtpSession.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/WithFtpSession.md
index 073309dad..171648758 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/WithFtpSession.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/activities/WithFtpSession.md
@@ -13,32 +13,32 @@ Connects to FTP server and provides a scope for other FTP activities.
| Name | Display Name | Kind | Type | Required | Default | Placeholder | Description |
|------|-------------|------|------|----------|---------|-------------|-------------|
-| `Host` | Host | InArgument | `string` | Yes | | | The URL of the FTP server that you want to connect to. |
-| `Port` | Port | InArgument | `int` | | | | The port of the FTP server that you want to connect to. |
-| `Timeout` | Timeout (milliseconds) | InArgument | `int` | | | | The timeout value (in milliseconds) for the FTP/SFTP connection. If not set, the default timeout of the underlying library is used. |
+| `Host` | Host | InArgument | `string` | Yes | | `ftp.example.com` | The URL of the FTP server that you want to connect to. |
+| `Port` | Port | InArgument | `int` | | | `21 for FTP, 22 for SFTP` | The port of the FTP server that you want to connect to. |
+| `Timeout` | Timeout | InArgument | `int` | | | `Milliseconds` | The timeout value (in milliseconds) for the FTP/SFTP connection. If not set, the default timeout of the underlying library is used. |
| `Username` | Username | InArgument | `string` | | | | The username that will be used to connect to the FTP server. |
| `Password` | Password | InArgument | `string` | | | | The password that will be used to connect to the FTP server. |
-| `SecurePassword` | Secure Password | InArgument | `SecureString` | | | | The password in secure string format. Provide either `Password` or `SecurePassword`. |
-| `UseAnonymousLogin` | Use Anonymous Login | Property | `bool` | | | | When this box is checked, the username and password fields are ignored, and a standard anonymous user is used instead. |
-| `FtpsMode` | FTPS Mode | Property | `FtpsMode` | | | | Switches to the FTPS protocol. Choose one of the two available options: Explicit or Implicit. |
-| `SslProtocols` | SSL Protocols | Property | `FtpSslProtocols` | | | | Select the SSL protocol to be used for the FTPS connection. |
-| `UseSftp` | Use SFTP | Property | `bool` | | | | Check this box if you want to use the SFTP transfer protocol. |
-| `ClientCertificatePath` | Client Certificate File | InArgument | `string` | | | | The path to the certificate used to verify the identity of the client. |
-| `ClientCertificatePassword` | Client Certificate Password | InArgument | `string` | | | | The password for the client certificate. |
-| `ClientCertificateSecurePassword` | Client Certificate Secure Password | InArgument | `SecureString` | | | | The password for client certificate in secure string format. |
-| `AcceptAllCertificates` | Accept All Certificates | Property | `bool` | | | | If this box is checked, all certificates will be accepted, including the ones that are expired or not verified. |
-| `ProxyType` | Proxy Type | Property | `FtpProxyType` | | | | The type of proxy. |
-| `ProxyServer` | Proxy Host | InArgument | `string` | | | | Proxy host name. |
-| `ProxyPort` | Proxy Host Port | InArgument | `int` | | | | Proxy port number. |
-| `ProxyUser` | Proxy Username | InArgument | `string` | | | | The user used for proxy if authentication is required. |
-| `ProxyPassword` | Proxy Password | InArgument | `string` | | | | The password used for proxy if authentication is required. |
-| `ProxySecurePassword` | Proxy Secure Password | InArgument | `SecureString` | | | | The proxy password in secure string format. |
+| `SecurePassword` | Secure password | InArgument | `SecureString` | | | | The password in secure string format. Provide either `Password` or `SecurePassword`. |
+| `UseAnonymousLogin` | Use anonymous login | Property | `bool` | | | | If turned on, the username and password fields are ignored, and a standard anonymous user is used instead. |
+| `FtpsMode` | FTPS mode | Property | `FtpsMode` | | | | Switches to the FTPS protocol. Choose one of the two available options: Explicit or Implicit. |
+| `SslProtocols` | SSL protocols | Property | `FtpSslProtocols` | | | `Auto: negotiate the best available protocol` | Select the SSL protocol to be used for the FTPS connection. |
+| `UseSftp` | Use SFTP | Property | `bool` | | | | Turn on to use the SFTP transfer protocol. |
+| `ClientCertificatePath` | Client certificate file | InArgument | `string` | | | `C:\Certificates\client.pfx` | The path to the certificate used to verify the identity of the client. |
+| `ClientCertificatePassword` | Client certificate password | InArgument | `string` | | | | The password for the client certificate. |
+| `ClientCertificateSecurePassword` | Client certificate secure password | InArgument | `SecureString` | | | | The password for client certificate in secure string format. |
+| `AcceptAllCertificates` | Accept all certificates | Property | `bool` | | | | If turned on, all certificates are accepted, including the ones that are expired or not verified. |
+| `ProxyType` | Proxy type | Property | `FtpProxyType` | | | | The type of proxy. |
+| `ProxyServer` | Proxy host | InArgument | `string` | | | `proxy.example.com` | Proxy host name. |
+| `ProxyPort` | Proxy port | InArgument | `int` | | | | Proxy port number. |
+| `ProxyUser` | Proxy username | InArgument | `string` | | | | The user used for proxy if authentication is required. |
+| `ProxyPassword` | Proxy password | InArgument | `string` | | | | The password used for proxy if authentication is required. |
+| `ProxySecurePassword` | Proxy secure password | InArgument | `SecureString` | | | | The proxy password in secure string format. |
### Configuration
| Name | Display Name | Type | Default | Description |
|------|-------------|------|---------|-------------|
-| `ContinueOnError` | Continue On Error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
+| `ContinueOnError` | Continue on error | `bool` | | Specifies if the automation should continue even when the activity throws an error. |
## XAML Example
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/coded-api.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/coded-api.md
index 738f41490..9df1b5e59 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/coded-api.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/coded-api.md
@@ -94,6 +94,12 @@ Downloads a file or directory from the FTP server to a local path. When `remoteP
**Returns:** `Task`
+**Recursive walk behaviour:**
+- Symbolic links are not descended into. On SFTP a link is still transferred as a file (the server follows it on open), but files underneath a linked directory are not downloaded. This prevents a link cycle from recursing forever.
+- A sub-directory the server lists but refuses to open is skipped rather than failing the whole call: its contents are omitted, the path is traced as a warning, and the transfer completes. **The call still succeeds** — inspect the trace if you need certainty that every file was retrieved.
+- Connection and timeout failures still throw, so a dropped connection is never reported as a completed download.
+- A bad `remotePath` still throws. The tolerance above applies only to sub-directories found during the walk.
+
---
### `Task UploadFiles(string localPath, string remotePath, bool overwrite = false, bool recursive = false, CancellationToken ct = default)`
@@ -146,6 +152,9 @@ Checks whether a file exists at the specified remote path.
**Returns:** `Task` — `true` if the remote file exists; `false` otherwise.
+> **On SFTP this also returns `true` for a symbolic link**, whatever it points at -- links are
+> classified as regular files. See the `FtpObjectType` note under Return Types.
+
---
### `Task DirectoryExists(string remotePath, CancellationToken ct = default)`
@@ -158,6 +167,8 @@ Checks whether a directory exists at the specified remote path.
**Returns:** `Task` — `true` if the remote directory exists; `false` otherwise.
+> **A symbolic link pointing at a directory returns `false` on SFTP**, for the same reason.
+
---
### `Task> EnumerateObjects(string remotePath, bool recursive = false, CancellationToken ct = default)`
@@ -171,6 +182,14 @@ Lists files and directories at the specified remote path.
**Returns:** `Task>` — Collection of `FtpObjectInfo` items describing each file and directory found.
+**Recursive walk behaviour:**
+- Symbolic links are listed but not descended into, so entries underneath a linked directory are not returned. This prevents a link cycle from recursing forever.
+- A sub-directory the server lists but refuses to open is skipped rather than failing the whole call: the sub-directory still appears in the results, its contents are omitted, and the path is traced as a warning.
+- Connection and timeout failures still throw, so a dropped connection is never returned as a successful partial listing.
+- A bad `remotePath` still throws. The tolerance above applies only to sub-directories found during the walk.
+
+> **On SFTP, `FtpObjectInfo.Type` is never `Link`.** See the `FtpObjectType` note under Return Types.
+
---
## Return Types
@@ -186,7 +205,7 @@ Describes a single file or directory entry returned by `EnumerateObjects`.
| `Size` | `long` | Size in bytes. `0` for directories. |
| `Created` | `DateTime` | Creation timestamp (server-reported; may be `DateTime.MinValue` if not supported). |
| `Modified` | `DateTime` | Last-modified timestamp (server-reported). |
-| `Type` | `FtpObjectType` | Whether the item is a file, directory, symbolic link, or other. |
+| `Type` | `FtpObjectType` | Whether the item is a file, directory, symbolic link, or other. **On SFTP, symbolic links are reported as `File`, never `Link`** -- see the `FtpObjectType` note below. |
| `OwnerPermissions` | `FtpPermissions` | Unix-style owner permissions (flags: `Read`, `Write`, `Execute`). |
| `GroupPermissions` | `FtpPermissions` | Unix-style group permissions. |
| `OthersPermissions` | `FtpPermissions` | Unix-style other permissions. |
@@ -255,6 +274,11 @@ Options for configuring an FTP/FTPS/SFTP session. Properties are grouped by conc
**`FtpObjectType`**: `Directory`, `File`, `Link`, `Other`
+> **`Link` is never produced on SFTP.** The SSH library classifies a symbolic link as a regular
+> file, so over SFTP links arrive as `FtpObjectType.File` and a `Type == FtpObjectType.Link`
+> test matches nothing. FTP and FTPS are unaffected and report `Link` correctly. There is
+> currently no way to distinguish a link from a file over SFTP through this API.
+
**`FtpPermissions`** (`[Flags]`): `None`, `Read`, `Write`, `Execute`
---
@@ -342,6 +366,7 @@ public async void Execute()
var items = await session.EnumerateObjects("/data", recursive: false);
foreach (var item in items)
{
+ // Over SFTP this also matches symbolic links; see the FtpObjectType note above.
if (item.Type == FtpObjectType.File)
Log($"{item.Name} — {item.Size} bytes, modified {item.Modified:yyyy-MM-dd}");
}
diff --git a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/overview.md b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/overview.md
index 86e7fd6d1..e9a1189df 100644
--- a/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/overview.md
+++ b/Activities/FTP/UiPath.FTP.Activities.Packaging/docs/overview.md
@@ -6,13 +6,13 @@
| Activity | Description |
|----------|-------------|
-| [Delete File or Folder](activities/Delete.md) | Removes a specified file from an FTP server. This activity only works if it is placed inside a With FTP Session scope activity. |
-| [Directory Exists](activities/DirectoryExists.md) | Checks whether a certain directory exists on an FTP server. This activity only works if it is placed inside a With FTP Session scope activity. |
-| [Download Files](activities/DownloadFiles.md) | Downloads the specified files from an FTP server to the specified local folder. This activity only works if it is placed inside a With FTP Session scope activity. |
-| [Enumerate Objects](activities/EnumerateObjects.md) | Generates a collection of files that have been found on the FTP server. Subfolders can also be included in the search by checking the Includes subfolders box. This activity only works if it is placed inside a With FTP Session scope activity. |
-| [File Exists](activities/FileExists.md) | Checks whether a certain file exists in the specified FTP directory. This activity only works if it is placed inside a With FTP Session scope activity. |
-| [Move File or Folder](activities/MoveItem.md) | Moves an item on an FTP server to a different remote path. This activity only works if it is placed inside a With FTP Session scope activity. |
-| [Upload Files](activities/UploadFiles.md) | Uploads a file to an FTP server. This activity only works if it is placed inside a With FTP Session scope activity. |
+| [Delete File or Folder](activities/Delete.md) | Removes a file or folder from an FTP server. This activity only works if it is placed inside a Use FTP Connection activity. |
+| [Check If Folder Exists](activities/DirectoryExists.md) | Checks whether a folder exists on an FTP server. This activity only works if it is placed inside a Use FTP Connection activity. |
+| [Download Files](activities/DownloadFiles.md) | Downloads the specified files from an FTP server to the specified local folder. This activity only works if it is placed inside a Use FTP Connection activity. |
+| [List Files and Folders](activities/EnumerateObjects.md) | Generates a collection of the files and folders found on the FTP server. Subfolders can also be included by turning on Include subfolders. This activity only works if it is placed inside a Use FTP Connection activity. |
+| [Check If File Exists](activities/FileExists.md) | Checks whether a file exists in the specified FTP folder. This activity only works if it is placed inside a Use FTP Connection activity. |
+| [Move File or Folder](activities/MoveItem.md) | Moves an item on an FTP server to a different remote path. This activity only works if it is placed inside a Use FTP Connection activity. |
+| [Upload Files](activities/UploadFiles.md) | Uploads files to an FTP server. This activity only works if it is placed inside a Use FTP Connection activity. |
| [Use FTP Connection](activities/WithFtpSession.md) | Connects to FTP server and provides a scope for other FTP activities. |
## XAML Namespace
@@ -34,6 +34,6 @@ This one URI maps the whole package — the activities (`UiPath.FTP.Activities`)
| Type | XAML | Notes |
|------|------|-------|
| `IFtpSession` | `ftp:IFtpSession` | Delegate argument exposed by the `WithFtpSession` scope body (`ActivityAction`, arg name `FtpSession`). |
-| `FtpObjectInfo` | `ftp:FtpObjectInfo` | Returned by Enumerate Objects. Members: `FullName`, `Name`, `Size`, `Created`, `Modified`, `Type` (`FtpObjectType`), `OwnerPermissions`, `GroupPermissions`, `OthersPermissions` (`FtpPermissions`). |
-| `FtpObjectType` | `ftp:FtpObjectType` | Enum: `Directory`, `File`, `Link`, `Other`. |
-| `FtpFilterObjectType` | `ftp:FtpFilterObjectType` | `[Flags]` enum used by Enumerate Objects `Filter` — see that activity's doc for values and semantics. |
+| `FtpObjectInfo` | `ftp:FtpObjectInfo` | Returned by List Files and Folders. Members: `FullName`, `Name`, `Size`, `Created`, `Modified`, `Type` (`FtpObjectType`), `OwnerPermissions`, `GroupPermissions`, `OthersPermissions` (`FtpPermissions`). |
+| `FtpObjectType` | `ftp:FtpObjectType` | Enum: `Directory`, `File`, `Link`, `Other`. **On SFTP, `Link` is never produced** — symbolic links are reported as `File`. FTP/FTPS report `Link` correctly. See [List Files and Folders](activities/EnumerateObjects.md). |
+| `FtpFilterObjectType` | `ftp:FtpFilterObjectType` | `[Flags]` enum used by List Files and Folders `Filter` — see that activity's doc for values and semantics. |
diff --git a/Activities/FTP/UiPath.FTP.Activities/DownloadFiles.cs b/Activities/FTP/UiPath.FTP.Activities/DownloadFiles.cs
index 1cfbab942..e39dc30f8 100644
--- a/Activities/FTP/UiPath.FTP.Activities/DownloadFiles.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/DownloadFiles.cs
@@ -23,7 +23,7 @@ public partial class DownloadFiles : FtpAsyncActivity
public InArgument RemotePath { get; set; }
[RequiredArgument]
- [LocalizedCategory(nameof(Resources.Output))]
+ [LocalizedCategory(nameof(Resources.Input))]
[LocalizedDisplayName(nameof(Resources.Activity_DownloadFiles_Property_LocalPath_Name))]
[LocalizedDescription(nameof(Resources.Activity_DownloadFiles_Property_LocalPath_Description))]
public InArgument LocalPath { get; set; }
diff --git a/Activities/FTP/UiPath.FTP.Activities/MoveItem.cs b/Activities/FTP/UiPath.FTP.Activities/MoveItem.cs
index c25dcb5a1..d4cc7ca65 100644
--- a/Activities/FTP/UiPath.FTP.Activities/MoveItem.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/MoveItem.cs
@@ -31,9 +31,9 @@ public partial class MoveItem : FtpCodeActivity
[LocalizedDescription(nameof(Resources.Activity_MoveItem_Property_Overwrite_Description))]
public bool Overwrite { get; set; }
- [LocalizedCategory(nameof(Resources.Common))]
- [LocalizedDisplayName(nameof(Resources.Activity_MoveItem_Property_ContinueOnError_Name))]
- [LocalizedDescription(nameof(Resources.Activity_MoveItem_Property_ContinueOnError_Description))]
+ [LocalizedCategory(nameof(Resources.Options))]
+ [LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_ContinueOnError_Name))]
+ [LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_ContinueOnError_Description))]
public InArgument ContinueOnError { get; set; } = false;
protected override void Execute(CodeActivityContext context)
diff --git a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/BaseFtpViewModel.cs b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/BaseFtpViewModel.cs
index 1f3dbd81b..77fd899a6 100644
--- a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/BaseFtpViewModel.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/BaseFtpViewModel.cs
@@ -1,5 +1,6 @@
using System.Activities.DesignViewModels;
using System.Activities.ViewModels;
+using UiPath.FTP.Activities.Properties;
namespace UiPath.FTP.Activities.NetCore.ViewModels
{
@@ -16,13 +17,26 @@ public BaseFtpViewModel(IDesignServices services) : base(services)
///
/// Specifies if the automation should continue even when the activity throws an error.
///
- public DesignInArgument ContinueOnError { get; set; }
+ public DesignInArgument ContinueOnError { get; set; } = new DesignInArgument();
protected override void InitializeModel()
{
base.InitializeModel();
PersistValuesChangedDuringInit();
+ }
+ ///
+ /// Configures ContinueOnError as the closing property of the Options section. Every activity
+ /// in the pack shares the same label, tooltip and widget for it, so it is configured once here.
+ ///
+ protected void ConfigureContinueOnError(ref int orderIndex)
+ {
+ ContinueOnError.DisplayName = Resources.Activity_WithFtpSession_Property_ContinueOnError_Name;
+ ContinueOnError.Tooltip = Resources.Activity_WithFtpSession_Property_ContinueOnError_Description;
+ ContinueOnError.IsPrincipal = false;
+ ContinueOnError.IsRequired = false;
+ ContinueOnError.OrderIndex = orderIndex++;
+ ContinueOnError.Category = Resources.Options;
ContinueOnError.Widget = new DefaultWidget { Type = ViewModelWidgetType.NullableBoolean };
}
}
diff --git a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DeleteViewModel.cs b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DeleteViewModel.cs
index 244747b20..537befa2a 100644
--- a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DeleteViewModel.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DeleteViewModel.cs
@@ -1,4 +1,5 @@
-using System.Activities.DesignViewModels;
+using System.Activities.DesignViewModels;
+using UiPath.FTP.Activities.Properties;
namespace UiPath.FTP.Activities.NetCore.ViewModels
{
@@ -15,12 +16,23 @@ public DeleteViewModel(IDesignServices services) : base(services)
///
/// The path of the file that is to be removed from the FTP server.
///
- public DesignInArgument RemotePath { get; set; }
+ public DesignInArgument RemotePath { get; set; } = new DesignInArgument();
protected override void InitializeModel()
{
base.InitializeModel();
- PersistValuesChangedDuringInit();
+
+ int orderIndex = 1;
+
+ RemotePath.DisplayName = Resources.Activity_Delete_Property_RemotePath_Name;
+ RemotePath.Tooltip = Resources.Activity_Delete_Property_RemotePath_Description;
+ RemotePath.EditPlaceholder = Resources.Activity_Delete_Property_RemotePath_Placeholder;
+ RemotePath.IsRequired = true;
+ RemotePath.IsPrincipal = true;
+ RemotePath.OrderIndex = orderIndex++;
+ RemotePath.Category = Resources.Input;
+
+ ConfigureContinueOnError(ref orderIndex);
}
}
}
diff --git a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DirectoryExistsViewModel.cs b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DirectoryExistsViewModel.cs
index c986c1185..398332f85 100644
--- a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DirectoryExistsViewModel.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DirectoryExistsViewModel.cs
@@ -1,4 +1,5 @@
-using System.Activities.DesignViewModels;
+using System.Activities.DesignViewModels;
+using UiPath.FTP.Activities.Properties;
namespace UiPath.FTP.Activities.NetCore.ViewModels
{
@@ -15,22 +16,35 @@ public DirectoryExistsViewModel(IDesignServices services) : base(services)
///
/// The path of the FTP directory in which to check whether the indicated directory exists.
///
- public DesignInArgument RemotePath { get; set; }
+ public DesignInArgument RemotePath { get; set; } = new DesignInArgument();
///
/// A boolean variable that states whether the indicated directory was found or not.
///
- public DesignOutArgument Exists { get; set; }
+ public DesignOutArgument Exists { get; set; } = new DesignOutArgument();
protected override void InitializeModel()
{
base.InitializeModel();
- PersistValuesChangedDuringInit();
- int propertyOrderIndex = 1;
+ int orderIndex = 1;
- RemotePath.OrderIndex = propertyOrderIndex++;
- Exists.OrderIndex = propertyOrderIndex;
+ RemotePath.DisplayName = Resources.Activity_DirectoryExists_Property_RemotePath_Name;
+ RemotePath.Tooltip = Resources.Activity_DirectoryExists_Property_RemotePath_Description;
+ RemotePath.EditPlaceholder = Resources.Activity_DirectoryExists_Property_RemotePath_Placeholder;
+ RemotePath.IsRequired = true;
+ RemotePath.IsPrincipal = true;
+ RemotePath.OrderIndex = orderIndex++;
+ RemotePath.Category = Resources.Input;
+
+ ConfigureContinueOnError(ref orderIndex);
+
+ // the output closes the property list, after the Options section
+ Exists.DisplayName = Resources.Activity_DirectoryExists_Property_Exists_Name;
+ Exists.Tooltip = Resources.Activity_DirectoryExists_Property_Exists_Description;
+ Exists.IsPrincipal = false;
+ Exists.OrderIndex = orderIndex;
+ Exists.Category = Resources.Output;
}
}
}
diff --git a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DownloadFilesViewModel.cs b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DownloadFilesViewModel.cs
index a5aabbcd2..7d5462b33 100644
--- a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DownloadFilesViewModel.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/DownloadFilesViewModel.cs
@@ -1,4 +1,6 @@
-using System.Activities.DesignViewModels;
+using System.Activities.DesignViewModels;
+using System.Activities.ViewModels;
+using UiPath.FTP.Activities.Properties;
namespace UiPath.FTP.Activities.NetCore.ViewModels
{
@@ -15,40 +17,73 @@ public DownloadFilesViewModel(IDesignServices services) : base(services)
///
/// The path of the files on the FTP server that are to be downloaded.
///
- public DesignInArgument RemotePath { get; set; }
+ public DesignInArgument RemotePath { get; set; } = new DesignInArgument();
///
/// The local path for the files that are to be downloaded.
///
- public DesignInArgument LocalPath { get; set; }
+ public DesignInArgument LocalPath { get; set; } = new DesignInArgument();
///
/// If this box is checked, the folders will be downloaded with their respective subfolders.
///
- public DesignProperty Recursive { get; set; }
+ public DesignProperty Recursive { get; set; } = new DesignProperty();
///
/// If this box is checked, the folder path will be created locally in case it does not already exist.
///
- public DesignProperty Create { get; set; }
+ public DesignProperty Create { get; set; } = new DesignProperty();
///
/// If this box is checked, the files will be overwritten locally if they're already stored there.
///
- public DesignProperty Overwrite { get; set; }
+ public DesignProperty Overwrite { get; set; } = new DesignProperty();
protected override void InitializeModel()
{
base.InitializeModel();
- PersistValuesChangedDuringInit();
- int propertyOrderIndex = 1;
+ int orderIndex = 1;
- RemotePath.OrderIndex = propertyOrderIndex++;
- LocalPath.OrderIndex = propertyOrderIndex++;
- Create.OrderIndex = propertyOrderIndex++;
- Recursive.OrderIndex = propertyOrderIndex++;
- Overwrite.OrderIndex = propertyOrderIndex;
+ // source first, then destination
+ RemotePath.DisplayName = Resources.Activity_DownloadFiles_Property_RemotePath_Name;
+ RemotePath.Tooltip = Resources.Activity_DownloadFiles_Property_RemotePath_Description;
+ RemotePath.EditPlaceholder = Resources.Activity_DownloadFiles_Property_RemotePath_Placeholder;
+ RemotePath.IsRequired = true;
+ RemotePath.IsPrincipal = true;
+ RemotePath.OrderIndex = orderIndex++;
+ RemotePath.Category = Resources.Input;
+
+ LocalPath.DisplayName = Resources.Activity_DownloadFiles_Property_LocalPath_Name;
+ LocalPath.Tooltip = Resources.Activity_DownloadFiles_Property_LocalPath_Description;
+ LocalPath.EditPlaceholder = Resources.Activity_DownloadFiles_Property_LocalPath_Placeholder;
+ LocalPath.IsRequired = true;
+ LocalPath.IsPrincipal = true;
+ LocalPath.OrderIndex = orderIndex++;
+ LocalPath.Category = Resources.Input;
+
+ Create.DisplayName = Resources.Activity_DownloadFiles_Property_Create_Name;
+ Create.Tooltip = Resources.Activity_DownloadFiles_Property_Create_Description;
+ Create.IsPrincipal = false;
+ Create.OrderIndex = orderIndex++;
+ Create.Category = Resources.Options;
+ Create.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+
+ Recursive.DisplayName = Resources.Activity_DownloadFiles_Property_Recursive_Name;
+ Recursive.Tooltip = Resources.Activity_DownloadFiles_Property_Recursive_Description;
+ Recursive.IsPrincipal = false;
+ Recursive.OrderIndex = orderIndex++;
+ Recursive.Category = Resources.Options;
+ Recursive.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+
+ Overwrite.DisplayName = Resources.Activity_DownloadFiles_Property_Overwrite_Name;
+ Overwrite.Tooltip = Resources.Activity_DownloadFiles_Property_Overwrite_Description;
+ Overwrite.IsPrincipal = false;
+ Overwrite.OrderIndex = orderIndex++;
+ Overwrite.Category = Resources.Options;
+ Overwrite.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+
+ ConfigureContinueOnError(ref orderIndex);
}
}
}
diff --git a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/EnumerateObjectsViewModel.cs b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/EnumerateObjectsViewModel.cs
index 1d35551f4..f228a6ff0 100644
--- a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/EnumerateObjectsViewModel.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/EnumerateObjectsViewModel.cs
@@ -23,41 +23,63 @@ public EnumerateObjectsViewModel(IDesignServices services) : base(services)
///
/// The path of the directory on the FTP server whose files are to be enumerated.
///
- public DesignInArgument RemotePath { get; set; }
+ public DesignInArgument RemotePath { get; set; } = new DesignInArgument();
///
/// If this check box is selected, the subfolders are also included in the enumeration of the files on the FTP server.
///
- public DesignProperty Recursive { get; set; }
+ public DesignProperty Recursive { get; set; } = new DesignProperty();
///
- /// Configure what type of objects to filter
+ /// Configure what type of objects to filter
///
- public DesignProperty Filter { get; set; }
+ public DesignProperty Filter { get; set; } = new DesignProperty();
///
/// A collection of files that have been found on the FTP server.
///
- public DesignOutArgument> Files { get; set; }
+ public DesignOutArgument> Files { get; set; } = new DesignOutArgument>();
private static DataSource _filterObjectDataSource;
protected override void InitializeModel()
{
base.InitializeModel();
- PersistValuesChangedDuringInit();
-
- int propertyOrderIndex = 1;
-
- RemotePath.OrderIndex = propertyOrderIndex++;
- Files.OrderIndex = propertyOrderIndex++;
- Recursive.OrderIndex = propertyOrderIndex++;
- Filter.OrderIndex = propertyOrderIndex;
+ int orderIndex = 1;
+
+ RemotePath.DisplayName = Resources.Activity_EnumerateObjects_Property_RemotePath_Name;
+ RemotePath.Tooltip = Resources.Activity_EnumerateObjects_Property_RemotePath_Description;
+ RemotePath.EditPlaceholder = Resources.Activity_EnumerateObjects_Property_RemotePath_Placeholder;
+ RemotePath.IsRequired = true;
+ RemotePath.IsPrincipal = true;
+ RemotePath.OrderIndex = orderIndex++;
+ RemotePath.Category = Resources.Input;
+
+ Recursive.DisplayName = Resources.Activity_EnumerateObjects_Property_Recursive_Name;
+ Recursive.Tooltip = Resources.Activity_EnumerateObjects_Property_Recursive_Description;
+ Recursive.IsPrincipal = false;
+ Recursive.OrderIndex = orderIndex++;
+ Recursive.Category = Resources.Options;
Recursive.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
- Filter.Widget = new DefaultWidget { Type = ViewModelWidgetType.MultiSelect };
+ Filter.DisplayName = Resources.Activity_EnumerateObjects_Property_Filter_Name;
+ Filter.Tooltip = Resources.Activity_EnumerateObjects_Property_Filter_Description;
+ Filter.EditPlaceholder = Resources.Activity_EnumerateObjects_Property_Filter_Placeholder;
+ Filter.IsPrincipal = false;
+ Filter.OrderIndex = orderIndex++;
+ Filter.Category = Resources.Options;
Filter.DataSource = _filterObjectDataSource;
+ Filter.Widget = new DefaultWidget { Type = ViewModelWidgetType.MultiSelect };
+
+ ConfigureContinueOnError(ref orderIndex);
+
+ // the output closes the property list, after the Options section
+ Files.DisplayName = Resources.Activity_EnumerateObjects_Property_Files_Name;
+ Files.Tooltip = Resources.Activity_EnumerateObjects_Property_Files_Description;
+ Files.IsPrincipal = false;
+ Files.OrderIndex = orderIndex;
+ Files.Category = Resources.Output;
}
private static void InitializeFilterObjectsDataSource()
diff --git a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/FileExistsViewModel.cs b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/FileExistsViewModel.cs
index 058b39465..2f68aa1c1 100644
--- a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/FileExistsViewModel.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/FileExistsViewModel.cs
@@ -1,38 +1,50 @@
-using System.Activities.DesignViewModels;
+using System.Activities.DesignViewModels;
+using UiPath.FTP.Activities.Properties;
namespace UiPath.FTP.Activities.NetCore.ViewModels
{
internal class FileExistsViewModel : BaseFtpViewModel
{
///
- /// Basic constructor
+ /// The path of the FTP directory in which to check whether the indicated file exists.
///
- ///
- public FileExistsViewModel(IDesignServices services) : base(services)
- {
- }
+ public DesignInArgument RemotePath { get; set; } = new DesignInArgument();
///
/// A boolean variable that states whether the indicated file was found or not.
///
- public DesignInArgument RemotePath { get; set; }
+ public DesignOutArgument Exists { get; set; } = new DesignOutArgument();
///
- /// The path of the FTP directory in which to check whether the indicated file exists.
+ /// Basic constructor
///
- public DesignOutArgument Exists { get; set; }
+ ///
+ public FileExistsViewModel(IDesignServices services) : base(services)
+ {
+ }
protected override void InitializeModel()
{
base.InitializeModel();
- PersistValuesChangedDuringInit();
- int propertyOrderIndex = 1;
+ int orderIndex = 1;
+ RemotePath.DisplayName = Resources.Activity_FileExists_Property_RemotePath_Name;
+ RemotePath.Tooltip = Resources.Activity_FileExists_Property_RemotePath_Description;
+ RemotePath.EditPlaceholder = Resources.Activity_FileExists_Property_RemotePath_Placeholder;
+ RemotePath.IsRequired = true;
RemotePath.IsPrincipal = true;
- RemotePath.OrderIndex = propertyOrderIndex++;
+ RemotePath.OrderIndex = orderIndex++;
+ RemotePath.Category = Resources.Input;
+
+ ConfigureContinueOnError(ref orderIndex);
- Exists.OrderIndex = propertyOrderIndex;
+ // the output closes the property list, after the Options section
+ Exists.DisplayName = Resources.Activity_FileExists_Property_Exists_Name;
+ Exists.Tooltip = Resources.Activity_FileExists_Property_Exists_Description;
+ Exists.IsPrincipal = false;
+ Exists.OrderIndex = orderIndex;
+ Exists.Category = Resources.Output;
}
}
}
diff --git a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/MoveItemViewModel.cs b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/MoveItemViewModel.cs
index 86fb3b2d9..bb295c36c 100644
--- a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/MoveItemViewModel.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/MoveItemViewModel.cs
@@ -1,5 +1,6 @@
-using System.Activities.DesignViewModels;
+using System.Activities.DesignViewModels;
using System.Activities.ViewModels;
+using UiPath.FTP.Activities.Properties;
namespace UiPath.FTP.Activities.NetCore.ViewModels
{
@@ -16,32 +17,49 @@ public MoveItemViewModel(IDesignServices services) : base(services)
///
/// The remote path on the FTP server where the file is currently located.
///
- public DesignInArgument RemotePath { get; set; }
+ public DesignInArgument RemotePath { get; set; } = new DesignInArgument();
///
/// The remote path on the FTP server where the file will be moved.
///
- public DesignInArgument NewPath { get; set; }
+ public DesignInArgument NewPath { get; set; } = new DesignInArgument();
///
/// If this box is checked, the files will be overwritten in the new remote directory if they're already stored there.
///
- public DesignProperty Overwrite { get; set; }
+ public DesignProperty Overwrite { get; set; } = new DesignProperty();
protected override void InitializeModel()
{
base.InitializeModel();
- PersistValuesChangedDuringInit();
- int propertyOrderIndex = 1;
+ int orderIndex = 1;
- RemotePath.OrderIndex = propertyOrderIndex++;
- NewPath.OrderIndex = propertyOrderIndex++;
- Overwrite.OrderIndex = propertyOrderIndex++;
- ContinueOnError.OrderIndex = propertyOrderIndex;
+ // source first, then destination
+ RemotePath.DisplayName = Resources.Activity_MoveItem_Property_RemotePath_Name;
+ RemotePath.Tooltip = Resources.Activity_MoveItem_Property_RemotePath_Description;
+ RemotePath.EditPlaceholder = Resources.Activity_MoveItem_Property_RemotePath_Placeholder;
+ RemotePath.IsRequired = true;
+ RemotePath.IsPrincipal = true;
+ RemotePath.OrderIndex = orderIndex++;
+ RemotePath.Category = Resources.Input;
- Overwrite.Widget = new DefaultWidget { Type = ViewModelWidgetType.NullableBoolean };
- ContinueOnError.Widget = new DefaultWidget { Type = ViewModelWidgetType.NullableBoolean };
+ NewPath.DisplayName = Resources.Activity_MoveItem_Property_NewPath_Name;
+ NewPath.Tooltip = Resources.Activity_MoveItem_Property_NewPath_Description;
+ NewPath.EditPlaceholder = Resources.Activity_MoveItem_Property_NewPath_Placeholder;
+ NewPath.IsRequired = true;
+ NewPath.IsPrincipal = true;
+ NewPath.OrderIndex = orderIndex++;
+ NewPath.Category = Resources.Input;
+
+ Overwrite.DisplayName = Resources.Activity_MoveItem_Property_Overwrite_Name;
+ Overwrite.Tooltip = Resources.Activity_MoveItem_Property_Overwrite_Description;
+ Overwrite.IsPrincipal = false;
+ Overwrite.OrderIndex = orderIndex++;
+ Overwrite.Category = Resources.Options;
+ Overwrite.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+
+ ConfigureContinueOnError(ref orderIndex);
}
}
}
diff --git a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/UploadFilesViewModel.cs b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/UploadFilesViewModel.cs
index ff77d3a9d..67a0ba7a1 100644
--- a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/UploadFilesViewModel.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/UploadFilesViewModel.cs
@@ -1,4 +1,6 @@
-using System.Activities.DesignViewModels;
+using System.Activities.DesignViewModels;
+using System.Activities.ViewModels;
+using UiPath.FTP.Activities.Properties;
namespace UiPath.FTP.Activities.NetCore.ViewModels
{
@@ -15,40 +17,73 @@ public UploadFilesViewModel(IDesignServices services) : base(services)
///
/// The local path of the files that are to be uploaded.
///
- public DesignInArgument LocalPath { get; set; }
+ public DesignInArgument LocalPath { get; set; } = new DesignInArgument();
///
/// The path on the FTP server where the file is to be uploaded.
///
- public DesignInArgument RemotePath { get; set; }
+ public DesignInArgument RemotePath { get; set; } = new DesignInArgument();
///
/// If this box is checked, the folders will be uploaded with their respective subfolders.
///
- public DesignProperty Recursive { get; set; }
+ public DesignProperty Recursive { get; set; } = new DesignProperty();
///
/// If this box is checked, the folder path will be created on the FTP server in case it does not already exist.
///
- public DesignProperty Create { get; set; }
+ public DesignProperty Create { get; set; } = new DesignProperty();
///
/// If this box is checked, the files will be overwritten on the FTP server if they're already stored there.
///
- public DesignProperty Overwrite { get; set; }
+ public DesignProperty Overwrite { get; set; } = new DesignProperty();
protected override void InitializeModel()
{
base.InitializeModel();
- PersistValuesChangedDuringInit();
- int propertyOrderIndex = 1;
+ int orderIndex = 1;
- RemotePath.OrderIndex = propertyOrderIndex++;
- LocalPath.OrderIndex = propertyOrderIndex++;
- Create.OrderIndex = propertyOrderIndex++;
- Recursive.OrderIndex = propertyOrderIndex++;
- Overwrite.OrderIndex = propertyOrderIndex;
+ // source first, then destination
+ LocalPath.DisplayName = Resources.Activity_UploadFiles_Property_LocalPath_Name;
+ LocalPath.Tooltip = Resources.Activity_UploadFiles_Property_LocalPath_Description;
+ LocalPath.EditPlaceholder = Resources.Activity_UploadFiles_Property_LocalPath_Placeholder;
+ LocalPath.IsRequired = true;
+ LocalPath.IsPrincipal = true;
+ LocalPath.OrderIndex = orderIndex++;
+ LocalPath.Category = Resources.Input;
+
+ RemotePath.DisplayName = Resources.Activity_UploadFiles_Property_RemotePath_Name;
+ RemotePath.Tooltip = Resources.Activity_UploadFiles_Property_RemotePath_Description;
+ RemotePath.EditPlaceholder = Resources.Activity_UploadFiles_Property_RemotePath_Placeholder;
+ RemotePath.IsRequired = true;
+ RemotePath.IsPrincipal = true;
+ RemotePath.OrderIndex = orderIndex++;
+ RemotePath.Category = Resources.Input;
+
+ Create.DisplayName = Resources.Activity_UploadFiles_Property_Create_Name;
+ Create.Tooltip = Resources.Activity_UploadFiles_Property_Create_Description;
+ Create.IsPrincipal = false;
+ Create.OrderIndex = orderIndex++;
+ Create.Category = Resources.Options;
+ Create.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+
+ Recursive.DisplayName = Resources.Activity_UploadFiles_Property_Recursive_Name;
+ Recursive.Tooltip = Resources.Activity_UploadFiles_Property_Recursive_Description;
+ Recursive.IsPrincipal = false;
+ Recursive.OrderIndex = orderIndex++;
+ Recursive.Category = Resources.Options;
+ Recursive.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+
+ Overwrite.DisplayName = Resources.Activity_UploadFiles_Property_Overwrite_Name;
+ Overwrite.Tooltip = Resources.Activity_UploadFiles_Property_Overwrite_Description;
+ Overwrite.IsPrincipal = false;
+ Overwrite.OrderIndex = orderIndex++;
+ Overwrite.Category = Resources.Options;
+ Overwrite.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+
+ ConfigureContinueOnError(ref orderIndex);
}
}
}
diff --git a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/WithFtpSessionViewModel.cs b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/WithFtpSessionViewModel.cs
index 8d1968275..0f018afd7 100644
--- a/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/WithFtpSessionViewModel.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/NetCore/ViewModels/WithFtpSessionViewModel.cs
@@ -1,4 +1,5 @@
using System;
+using System.Activities;
using System.Activities.DesignViewModels;
using System.Activities.ViewModels;
using System.Collections.Generic;
@@ -8,6 +9,7 @@
using UiPath.FTP.Enums;
using UiPath.Shared;
using UiPath.Shared.Activities;
+using FtpsModeEnum = UiPath.FTP.FtpsMode;
namespace UiPath.FTP.Activities.NetCore.ViewModels
{
@@ -19,158 +21,161 @@ internal class WithFtpSessionViewModel : BaseFtpViewModel
///
public WithFtpSessionViewModel(IDesignServices services) : base(services)
{
+ InitializeSslProtocolsDataSource();
InitializeFtpsModeDataSource();
InitializeProxyModeDataSource();
}
+ ///
+ /// The child activities that run against the open session. It is rendered as the scope's
+ /// drop area on the canvas, never as a property row — see .
+ ///
+ public DesignProperty> Body { get; set; } = new DesignProperty>();
+
///
/// The URL of the FTP server that you want to connect to.
///
- public DesignInArgument Host { get; set; }
+ public DesignInArgument Host { get; set; } = new DesignInArgument();
///
/// The port of the FTP server that you want to connect to.
///
- public DesignInArgument Port { get; set; }
+ public DesignInArgument Port { get; set; } = new DesignInArgument();
///
/// The connection timeout in milliseconds.
///
- public DesignInArgument Timeout { get; set; }
+ public DesignInArgument Timeout { get; set; } = new DesignInArgument();
///
/// The username that will be used to connect to the FTP server.
///
- public DesignInArgument Username { get; set; }
+ public DesignInArgument Username { get; set; } = new DesignInArgument();
///
/// The password that will be used to connect to the FTP server.
///
- public DesignInArgument Password { get; set; }
+ public DesignInArgument Password { get; set; } = new DesignInArgument();
///
/// The secure password that will be used to connect to the FTP server.
///
- public DesignInArgument SecurePassword { get; set; }
+ public DesignInArgument SecurePassword { get; set; } = new DesignInArgument();
///
/// Switches Password as string or secure string
///
- public DesignProperty PasswordInputModeSwitch { get; set; }
+ public DesignProperty PasswordInputModeSwitch { get; set; } = new DesignProperty();
///
/// When this box is checked, the username and password fields are ignored, and a standard anonymous user is used instead.
///
- public DesignProperty UseAnonymousLogin { get; set; }
+ public DesignProperty UseAnonymousLogin { get; set; } = new DesignProperty();
///
/// Switches to the FTPS protocol.
///
- public DesignProperty FtpsMode { get; set; }
+ public DesignProperty FtpsMode { get; set; } = new DesignProperty();
///
/// Select the SSL protocol to be used for the FTPS connection
///
- public DesignProperty SslProtocols { get; set; }
+ public DesignProperty SslProtocols { get; set; } = new DesignProperty();
///
/// Check this box if you want to use the SFTP transfer protocol.
///
- public DesignProperty UseSftp { get; set; }
+ public DesignProperty UseSftp { get; set; } = new DesignProperty();
///
/// The path to the certificate used to verify the identity of the client.
///
- public DesignInArgument ClientCertificatePath { get; set; }
+ public DesignInArgument ClientCertificatePath { get; set; } = new DesignInArgument();
///
/// The password for the client certificate.
///
- public DesignInArgument ClientCertificatePassword { get; set; }
+ public DesignInArgument ClientCertificatePassword { get; set; } = new DesignInArgument();
///
/// The secure password that will be used to connect to the FTP server.
///
- public DesignInArgument ClientCertificateSecurePassword { get; set; }
+ public DesignInArgument ClientCertificateSecurePassword { get; set; } = new DesignInArgument();
///
/// Switches Password as string or secure string
///
- public DesignProperty CertificatePasswordInputModeSwitch { get; set; }
+ public DesignProperty CertificatePasswordInputModeSwitch { get; set; } = new DesignProperty();
///
/// If this box is checked, all certificates will be accepted, including the ones that are expired or not verified.
///
- public DesignProperty AcceptAllCertificates { get; set; }
+ public DesignProperty AcceptAllCertificates { get; set; } = new DesignProperty();
///
/// The type of proxy used
///
- public DesignProperty ProxyType { get; set; }
+ public DesignProperty ProxyType { get; set; } = new DesignProperty();
///
/// The proxy host
///
- public DesignInArgument ProxyServer { get; set; }
+ public DesignInArgument ProxyServer { get; set; } = new DesignInArgument();
///
/// The proxy port
///
- public DesignInArgument ProxyPort { get; set; }
+ public DesignInArgument ProxyPort { get; set; } = new DesignInArgument();
///
/// User used for proxy authentification
///
- public DesignInArgument ProxyUser { get; set; }
+ public DesignInArgument ProxyUser { get; set; } = new DesignInArgument();
///
/// Password for proxy
///
- public DesignInArgument ProxyPassword { get; set; }
+ public DesignInArgument ProxyPassword { get; set; } = new DesignInArgument();
///
/// Secured password for proxy
///
- public DesignInArgument ProxySecurePassword { get; set; }
+ public DesignInArgument ProxySecurePassword { get; set; } = new DesignInArgument();
///
/// Switches Proxy Password as string or secure string
///
- public DesignProperty ProxyPasswordInputModeSwitch { get; set; }
+ public DesignProperty ProxyPasswordInputModeSwitch { get; set; } = new DesignProperty();
private static DataSource _sslProtocolsDataSource;
private static IDataSource _proxyTypeDataSource;
+ private static IDataSource _ftpsModeDataSource;
+
protected override void InitializeModel()
{
base.InitializeModel();
- PersistValuesChangedDuringInit();
-
- int propertyOrderIndex = 1;
-
- Host.OrderIndex = propertyOrderIndex++;
- Username.OrderIndex = propertyOrderIndex++;
- Password.OrderIndex = propertyOrderIndex++;
- SecurePassword.OrderIndex = propertyOrderIndex++;
- Port.OrderIndex = propertyOrderIndex++;
- Timeout.OrderIndex = propertyOrderIndex++;
- UseAnonymousLogin.OrderIndex = propertyOrderIndex++;
- ContinueOnError.OrderIndex = propertyOrderIndex++;
- AcceptAllCertificates.OrderIndex = propertyOrderIndex++;
- ClientCertificatePath.OrderIndex = propertyOrderIndex++;
- ClientCertificatePassword.OrderIndex = propertyOrderIndex++;
- ClientCertificateSecurePassword.OrderIndex = propertyOrderIndex++;
- FtpsMode.OrderIndex = propertyOrderIndex++;
- SslProtocols.OrderIndex = propertyOrderIndex++;
- UseSftp.OrderIndex = propertyOrderIndex;
-
- ContinueOnError.Widget = new DefaultWidget { Type = ViewModelWidgetType.NullableBoolean };
- SslProtocols.Widget = new DefaultWidget { Type = ViewModelWidgetType.MultiSelect };
- UseSftp.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
- SslProtocols.DataSource = _sslProtocolsDataSource;
- ProxyType.DataSource = _proxyTypeDataSource;
+ int orderIndex = 1;
+
+ ConfigureConnectionProperties(ref orderIndex);
+ ConfigureOptionProperties(ref orderIndex);
+ ConfigureSecurityProperties(ref orderIndex);
+ ConfigureProxyProperties(ref orderIndex);
+
+ // The scope renders its children as a drop area, not as a property row. OrderIndex must
+ // be set *after* the Configure* calls above (i.e. last, not first/default) -- giving it
+ // an earlier index broke the canvas layout, with Username/Password rendering detached
+ // from the "Use FTP connection" container instead of stacked inside it. Verified in
+ // Studio; keep Body's OrderIndex last if InitializeModel is reordered.
+ Body.OrderIndex = orderIndex++;
+ Body.IsVisible = false;
+
+ // the input-mode switches only back the menu actions below, they are never rendered
+ PasswordInputModeSwitch.IsVisible = false;
+ CertificatePasswordInputModeSwitch.IsVisible = false;
+ ProxyPasswordInputModeSwitch.IsVisible = false;
MenuActionsBuilder.WithValueProperty(PasswordInputModeSwitch)
.AddMenuProperty(Password, PasswordInputMode.Password)
@@ -188,6 +193,180 @@ protected override void InitializeModel()
.BuildAndInsertMenuActions(true);
}
+ ///
+ /// The three fields needed for every connection: server, user and password.
+ /// They form the primary section and are the only principal properties of the activity.
+ ///
+ private void ConfigureConnectionProperties(ref int orderIndex)
+ {
+ Host.DisplayName = Resources.Activity_WithFtpSession_Property_Host_Name;
+ Host.Tooltip = Resources.Activity_WithFtpSession_Property_Host_Description;
+ Host.EditPlaceholder = Resources.Activity_WithFtpSession_Property_Host_Placeholder;
+ Host.IsRequired = true;
+ Host.IsPrincipal = true;
+ Host.OrderIndex = orderIndex++;
+ Host.Category = Resources.Input;
+
+ Username.DisplayName = Resources.Activity_WithFtpSession_Property_Username_Name;
+ Username.Tooltip = Resources.Activity_WithFtpSession_Property_Username_Description;
+ Username.IsPrincipal = true;
+ Username.OrderIndex = orderIndex++;
+ Username.Category = Resources.Input;
+
+ // Password and SecurePassword are two renderings of the same field, only one is ever
+ // visible, so they share an order index.
+ Password.DisplayName = Resources.Activity_WithFtpSession_Property_Password_Name;
+ Password.Tooltip = Resources.Activity_WithFtpSession_Property_Password_Description;
+ Password.IsPrincipal = true;
+ Password.OrderIndex = orderIndex;
+ Password.Category = Resources.Input;
+
+ SecurePassword.DisplayName = Resources.Activity_WithFtpSession_Property_SecurePassword_Name;
+ SecurePassword.Tooltip = Resources.Activity_WithFtpSession_Property_SecurePassword_Description;
+ SecurePassword.IsPrincipal = true;
+ SecurePassword.IsVisible = false;
+ SecurePassword.OrderIndex = orderIndex++;
+ SecurePassword.Category = Resources.Input;
+ }
+
+ ///
+ /// Connection knobs that have a working default: anonymous login, port, timeout and
+ /// ContinueOnError. None of them belong in the primary section.
+ ///
+ private void ConfigureOptionProperties(ref int orderIndex)
+ {
+ UseAnonymousLogin.DisplayName = Resources.Activity_WithFtpSession_Property_UseAnonymousLogin_Name;
+ UseAnonymousLogin.Tooltip = Resources.Activity_WithFtpSession_Property_UseAnonymousLogin_Description;
+ UseAnonymousLogin.IsPrincipal = false;
+ UseAnonymousLogin.OrderIndex = orderIndex++;
+ UseAnonymousLogin.Category = Resources.Options;
+ UseAnonymousLogin.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+
+ Port.DisplayName = Resources.Activity_WithFtpSession_Property_Port_Name;
+ Port.Tooltip = Resources.Activity_WithFtpSession_Property_Port_Description;
+ Port.EditPlaceholder = Resources.Activity_WithFtpSession_Property_Port_Placeholder;
+ Port.IsPrincipal = false;
+ Port.OrderIndex = orderIndex++;
+ Port.Category = Resources.Options;
+ Port.Widget = new DefaultWidget { Type = ViewModelWidgetType.Number };
+
+ Timeout.DisplayName = Resources.Activity_WithFtpSession_Property_Timeout_Name;
+ Timeout.Tooltip = Resources.Activity_WithFtpSession_Property_Timeout_Description;
+ Timeout.EditPlaceholder = Resources.Activity_WithFtpSession_Property_Timeout_Placeholder;
+ Timeout.IsPrincipal = false;
+ Timeout.OrderIndex = orderIndex++;
+ Timeout.Category = Resources.Options;
+ Timeout.Widget = new DefaultWidget { Type = ViewModelWidgetType.Number };
+
+ ConfigureContinueOnError(ref orderIndex);
+ }
+
+ ///
+ /// Transport and certificate configuration. UseSftp comes first because it decides which of
+ /// the fields below apply.
+ ///
+ private void ConfigureSecurityProperties(ref int orderIndex)
+ {
+ UseSftp.DisplayName = Resources.Activity_WithFtpSession_Property_UseSftp_Name;
+ UseSftp.Tooltip = Resources.Activity_WithFtpSession_Property_UseSftp_Description;
+ UseSftp.IsPrincipal = false;
+ UseSftp.OrderIndex = orderIndex++;
+ UseSftp.Category = Resources.Security;
+ UseSftp.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+
+ FtpsMode.DisplayName = Resources.Activity_WithFtpSession_Property_FtpsMode_Name;
+ FtpsMode.Tooltip = Resources.Activity_WithFtpSession_Property_FtpsMode_Description;
+ FtpsMode.IsPrincipal = false;
+ FtpsMode.OrderIndex = orderIndex++;
+ FtpsMode.Category = Resources.Security;
+ FtpsMode.DataSource = _ftpsModeDataSource;
+ FtpsMode.Widget = new DefaultWidget { Type = ViewModelWidgetType.Dropdown };
+
+ SslProtocols.DisplayName = Resources.Activity_WithFtpSession_Property_SslProtocols_Name;
+ SslProtocols.Tooltip = Resources.Activity_WithFtpSession_Property_SslProtocols_Description;
+ SslProtocols.EditPlaceholder = Resources.Activity_WithFtpSession_Property_SslProtocols_Placeholder;
+ SslProtocols.IsPrincipal = false;
+ SslProtocols.OrderIndex = orderIndex++;
+ SslProtocols.Category = Resources.Security;
+ SslProtocols.DataSource = _sslProtocolsDataSource;
+ SslProtocols.Widget = new DefaultWidget { Type = ViewModelWidgetType.MultiSelect };
+
+ ClientCertificatePath.DisplayName = Resources.Activity_WithFtpSession_Property_ClientCertificatePath_Name;
+ ClientCertificatePath.Tooltip = Resources.Activity_WithFtpSession_Property_ClientCertificatePath_Description;
+ ClientCertificatePath.EditPlaceholder = Resources.Activity_WithFtpSession_Property_ClientCertificatePath_Placeholder;
+ ClientCertificatePath.IsPrincipal = false;
+ ClientCertificatePath.OrderIndex = orderIndex++;
+ ClientCertificatePath.Category = Resources.Security;
+
+ ClientCertificatePassword.DisplayName = Resources.Activity_WithFtpSession_Property_ClientCertificatePassword_Name;
+ ClientCertificatePassword.Tooltip = Resources.Activity_WithFtpSession_Property_ClientCertificatePassword_Description;
+ ClientCertificatePassword.IsPrincipal = false;
+ ClientCertificatePassword.OrderIndex = orderIndex;
+ ClientCertificatePassword.Category = Resources.Security;
+
+ ClientCertificateSecurePassword.DisplayName = Resources.Activity_WithFtpSession_Property_ClientCertificateSecurePassword_Name;
+ ClientCertificateSecurePassword.Tooltip = Resources.Activity_WithFtpSession_Property_ClientCertificateSecurePassword_Description;
+ ClientCertificateSecurePassword.IsPrincipal = false;
+ ClientCertificateSecurePassword.IsVisible = false;
+ ClientCertificateSecurePassword.OrderIndex = orderIndex++;
+ ClientCertificateSecurePassword.Category = Resources.Security;
+
+ AcceptAllCertificates.DisplayName = Resources.Activity_WithFtpSession_Property_AcceptAllCertificates_Name;
+ AcceptAllCertificates.Tooltip = Resources.Activity_WithFtpSession_Property_AcceptAllCertificates_Description;
+ AcceptAllCertificates.IsPrincipal = false;
+ AcceptAllCertificates.OrderIndex = orderIndex++;
+ AcceptAllCertificates.Category = Resources.Security;
+ AcceptAllCertificates.Widget = new DefaultWidget { Type = ViewModelWidgetType.Toggle };
+ }
+
+ ///
+ /// Proxy configuration. Everything below ProxyType is revealed by
+ /// once a proxy type is picked.
+ ///
+ private void ConfigureProxyProperties(ref int orderIndex)
+ {
+ ProxyType.DisplayName = Resources.Activity_WithFtpSession_Property_ProxyType_Name;
+ ProxyType.Tooltip = Resources.Activity_WithFtpSession_Property_ProxyType_Description;
+ ProxyType.IsPrincipal = false;
+ ProxyType.OrderIndex = orderIndex++;
+ ProxyType.Category = Resources.Proxy;
+ ProxyType.DataSource = _proxyTypeDataSource;
+ ProxyType.Widget = new DefaultWidget { Type = ViewModelWidgetType.Dropdown };
+
+ ProxyServer.DisplayName = Resources.Activity_WithFtpSession_Property_ProxyServer_Name;
+ ProxyServer.Tooltip = Resources.Activity_WithFtpSession_Property_ProxyServer_Description;
+ ProxyServer.EditPlaceholder = Resources.Activity_WithFtpSession_Property_ProxyServer_Placeholder;
+ ProxyServer.IsPrincipal = false;
+ ProxyServer.OrderIndex = orderIndex++;
+ ProxyServer.Category = Resources.Proxy;
+
+ ProxyPort.DisplayName = Resources.Activity_WithFtpSession_Property_ProxyPort_Name;
+ ProxyPort.Tooltip = Resources.Activity_WithFtpSession_Property_ProxyPort_Description;
+ ProxyPort.IsPrincipal = false;
+ ProxyPort.OrderIndex = orderIndex++;
+ ProxyPort.Category = Resources.Proxy;
+ ProxyPort.Widget = new DefaultWidget { Type = ViewModelWidgetType.Number };
+
+ ProxyUser.DisplayName = Resources.Activity_WithFtpSession_Property_ProxyUser_Name;
+ ProxyUser.Tooltip = Resources.Activity_WithFtpSession_Property_ProxyUser_Description;
+ ProxyUser.IsPrincipal = false;
+ ProxyUser.OrderIndex = orderIndex++;
+ ProxyUser.Category = Resources.Proxy;
+
+ ProxyPassword.DisplayName = Resources.Activity_WithFtpSession_Property_ProxyPassword_Name;
+ ProxyPassword.Tooltip = Resources.Activity_WithFtpSession_Property_ProxyPassword_Description;
+ ProxyPassword.IsPrincipal = false;
+ ProxyPassword.OrderIndex = orderIndex;
+ ProxyPassword.Category = Resources.Proxy;
+
+ ProxySecurePassword.DisplayName = Resources.Activity_WithFtpSession_Property_ProxySecurePassword_Name;
+ ProxySecurePassword.Tooltip = Resources.Activity_WithFtpSession_Property_ProxySecurePassword_Description;
+ ProxySecurePassword.IsPrincipal = false;
+ ProxySecurePassword.IsVisible = false;
+ ProxySecurePassword.OrderIndex = orderIndex++;
+ ProxySecurePassword.Category = Resources.Proxy;
+ }
+
///
protected override void InitializeRules()
{
@@ -214,7 +393,7 @@ protected override void ManualRegisterDependencies()
///
/// Password input Mode has changed. Set controls visibility based on selection
///
- private void PasswordInputModeChanged_Action()
+ internal void PasswordInputModeChanged_Action()
{
switch (PasswordInputModeSwitch.Value)
{
@@ -234,7 +413,7 @@ private void PasswordInputModeChanged_Action()
///
/// CertificatePassword input Mode has changed. Set controls visibility based on selection
///
- private void CertificatePasswordInputModeChanged_Action()
+ internal void CertificatePasswordInputModeChanged_Action()
{
switch (CertificatePasswordInputModeSwitch.Value)
{
@@ -254,7 +433,7 @@ private void CertificatePasswordInputModeChanged_Action()
///
/// CertificatePassword input Mode has changed. Set controls visibility based on selection
///
- private void ProxyPasswordInputModeChanged_Action()
+ internal void ProxyPasswordInputModeChanged_Action()
{
switch (ProxyPasswordInputModeSwitch.Value)
{
@@ -271,7 +450,7 @@ private void ProxyPasswordInputModeChanged_Action()
}
}
- private void FtpEncryptionModeChanged_Action()
+ internal void FtpEncryptionModeChanged_Action()
{
if (FtpsMode.Value == FTP.FtpsMode.None)
{
@@ -282,7 +461,7 @@ private void FtpEncryptionModeChanged_Action()
SslProtocols.IsVisible = true;
}
- private void ProxyModeChanged_Action()
+ internal void ProxyModeChanged_Action()
{
bool proxyConfigVisible = ProxyType.Value != FtpProxyType.None;
ProxyServer.IsVisible = proxyConfigVisible;
@@ -294,18 +473,34 @@ private void ProxyModeChanged_Action()
}
private static void InitializeFtpsModeDataSource()
+ {
+ _ftpsModeDataSource ??= DataSourceBuilder
+ .WithId(m => Enum.GetName(m))
+ .WithLabel(m => LocalizedEnum.GetLocalizedValue(typeof(FtpsModeEnum), m).Name)
+ .WithData(new List
+ {
+ FtpsModeEnum.None,
+ FtpsModeEnum.Explicit,
+ FtpsModeEnum.Implicit,
+ })
+ .Build();
+ }
+
+ private static void InitializeSslProtocolsDataSource()
{
if (_sslProtocolsDataSource is not null)
{
return;
}
+#pragma warning disable CS0618 // FtpSslProtocols.Default remains a selectable option for backwards compatibility with workflows that already use it
var protocols = Enum.GetValues()
.Where(s => s != FtpSslProtocols.Auto && s != FtpSslProtocols.Default)
.OrderBy(s => s)
.Reverse() // newer, non-obsolete protocols first
.ToList();
protocols.Add(FtpSslProtocols.Default); // add Default as the last option, by default it would have been between Tls and Tls11
+#pragma warning restore CS0618
_sslProtocolsDataSource = DataSourceBuilder
.WithId(s => Enum.GetName(s))
diff --git a/Activities/FTP/UiPath.FTP.Activities/Properties/AssemblyInfo.cs b/Activities/FTP/UiPath.FTP.Activities/Properties/AssemblyInfo.cs
index 0a9bdb882..08984e3bb 100644
--- a/Activities/FTP/UiPath.FTP.Activities/Properties/AssemblyInfo.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/Properties/AssemblyInfo.cs
@@ -3,7 +3,6 @@
using System.Windows.Markup;
[assembly: XmlnsDefinition("http://schemas.uipath.com/workflow/activities/ftp", "UiPath.FTP.Activities")]
-[assembly: XmlnsDefinition("http://schemas.uipath.com/workflow/activities/ftp", "UiPath.FTP.Activities.Design")]
// Setting ComVisible to false makes the types in this assembly not visible to COM
diff --git a/Activities/FTP/UiPath.FTP.Activities/Properties/UiPath.FTP.Activities.Designer.cs b/Activities/FTP/UiPath.FTP.Activities/Properties/UiPath.FTP.Activities.Designer.cs
index 2de148989..81183ff8c 100644
--- a/Activities/FTP/UiPath.FTP.Activities/Properties/UiPath.FTP.Activities.Designer.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/Properties/UiPath.FTP.Activities.Designer.cs
@@ -70,7 +70,7 @@ public static string AcceptAllCertificates {
}
///
- /// Looks up a localized string similar to Removes a specified file from an FTP server. This activity only works if it is placed inside a With FTP Session scope activity..
+ /// Looks up a localized string similar to Removes a file or folder from an FTP server. This activity only works if it is placed inside a Use FTP Connection activity..
///
public static string Activity_Delete_Description {
get {
@@ -106,7 +106,16 @@ public static string Activity_Delete_Property_RemotePath_Name {
}
///
- /// Looks up a localized string similar to Checks whether a certain directory exists on an FTP server. This activity only works if it is placed inside a With FTP Session scope activity..
+ /// Looks up a localized string similar to /remote/folder/file.txt.
+ ///
+ public static string Activity_Delete_Property_RemotePath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_Delete_Property_RemotePath_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Checks whether a folder exists on an FTP server. This activity only works if it is placed inside a Use FTP Connection activity..
///
public static string Activity_DirectoryExists_Description {
get {
@@ -115,7 +124,7 @@ public static string Activity_DirectoryExists_Description {
}
///
- /// Looks up a localized string similar to Directory Exists.
+ /// Looks up a localized string similar to Check If Folder Exists.
///
public static string Activity_DirectoryExists_Name {
get {
@@ -151,7 +160,7 @@ public static string Activity_DirectoryExists_Property_RemotePath_Description {
}
///
- /// Looks up a localized string similar to Folder Path.
+ /// Looks up a localized string similar to Folder path.
///
public static string Activity_DirectoryExists_Property_RemotePath_Name {
get {
@@ -160,7 +169,16 @@ public static string Activity_DirectoryExists_Property_RemotePath_Name {
}
///
- /// Looks up a localized string similar to Downloads the specified files from an FTP server to the specified local folder. This activity only works if it is placed inside a With FTP Session scope activity..
+ /// Looks up a localized string similar to /remote/folder.
+ ///
+ public static string Activity_DirectoryExists_Property_RemotePath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_DirectoryExists_Property_RemotePath_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Downloads the specified files from an FTP server to the specified local folder. This activity only works if it is placed inside a Use FTP Connection activity..
///
public static string Activity_DownloadFiles_Description {
get {
@@ -178,7 +196,7 @@ public static string Activity_DownloadFiles_Name {
}
///
- /// Looks up a localized string similar to If this box is checked, the folder path will be created locally in case it does not already exist..
+ /// Looks up a localized string similar to If turned on, the folder path is created locally in case it does not already exist..
///
public static string Activity_DownloadFiles_Property_Create_Description {
get {
@@ -187,7 +205,7 @@ public static string Activity_DownloadFiles_Property_Create_Description {
}
///
- /// Looks up a localized string similar to Create.
+ /// Looks up a localized string similar to Create folder if missing.
///
public static string Activity_DownloadFiles_Property_Create_Name {
get {
@@ -214,7 +232,16 @@ public static string Activity_DownloadFiles_Property_LocalPath_Name {
}
///
- /// Looks up a localized string similar to If this box is checked, the files will be overwritten locally if they're already stored there..
+ /// Looks up a localized string similar to C:\Local\folder.
+ ///
+ public static string Activity_DownloadFiles_Property_LocalPath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_DownloadFiles_Property_LocalPath_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to If turned on, the files are overwritten locally if they are already stored there..
///
public static string Activity_DownloadFiles_Property_Overwrite_Description {
get {
@@ -223,7 +250,7 @@ public static string Activity_DownloadFiles_Property_Overwrite_Description {
}
///
- /// Looks up a localized string similar to Overwrite.
+ /// Looks up a localized string similar to Overwrite existing files.
///
public static string Activity_DownloadFiles_Property_Overwrite_Name {
get {
@@ -232,7 +259,7 @@ public static string Activity_DownloadFiles_Property_Overwrite_Name {
}
///
- /// Looks up a localized string similar to If this box is checked, the folders will be downloaded with their respective subfolders..
+ /// Looks up a localized string similar to If turned on, the folders are downloaded with their respective subfolders..
///
public static string Activity_DownloadFiles_Property_Recursive_Description {
get {
@@ -268,7 +295,16 @@ public static string Activity_DownloadFiles_Property_RemotePath_Name {
}
///
- /// Looks up a localized string similar to Generates a collection of files that have been found on the FTP server. Subfolders can also be included in the search by checking the Includes subfolders box. This activity only works if it is placed inside a With FTP Session scope activity..
+ /// Looks up a localized string similar to /remote/folder.
+ ///
+ public static string Activity_DownloadFiles_Property_RemotePath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_DownloadFiles_Property_RemotePath_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Generates a collection of the files and folders found on the FTP server. Subfolders can also be included by turning on Include subfolders. This activity only works if it is placed inside a Use FTP Connection activity..
///
public static string Activity_EnumerateObjects_Description {
get {
@@ -277,7 +313,7 @@ public static string Activity_EnumerateObjects_Description {
}
///
- /// Looks up a localized string similar to Enumerate Objects.
+ /// Looks up a localized string similar to List Files and Folders.
///
public static string Activity_EnumerateObjects_Name {
get {
@@ -286,7 +322,7 @@ public static string Activity_EnumerateObjects_Name {
}
///
- /// Looks up a localized string similar to A collection of files that have been found on the FTP server..
+ /// Looks up a localized string similar to The collection of files and folders found on the FTP server..
///
public static string Activity_EnumerateObjects_Property_Files_Description {
get {
@@ -295,7 +331,7 @@ public static string Activity_EnumerateObjects_Property_Files_Description {
}
///
- /// Looks up a localized string similar to Files.
+ /// Looks up a localized string similar to Files and folders.
///
public static string Activity_EnumerateObjects_Property_Files_Name {
get {
@@ -313,7 +349,7 @@ public static string Activity_EnumerateObjects_Property_Filter_Description {
}
///
- /// Looks up a localized string similar to Object types.
+ /// Looks up a localized string similar to Item types to include.
///
public static string Activity_EnumerateObjects_Property_Filter_Name {
get {
@@ -322,7 +358,7 @@ public static string Activity_EnumerateObjects_Property_Filter_Name {
}
///
- /// Looks up a localized string similar to Select object types to include.
+ /// Looks up a localized string similar to Select the item types to include.
///
public static string Activity_EnumerateObjects_Property_Filter_Placeholder {
get {
@@ -331,7 +367,7 @@ public static string Activity_EnumerateObjects_Property_Filter_Placeholder {
}
///
- /// Looks up a localized string similar to If this check box is selected, the subfolders are also included in the enumeration of the files on the FTP server..
+ /// Looks up a localized string similar to If turned on, the subfolders are also included in the listing..
///
public static string Activity_EnumerateObjects_Property_Recursive_Description {
get {
@@ -349,7 +385,7 @@ public static string Activity_EnumerateObjects_Property_Recursive_Name {
}
///
- /// Looks up a localized string similar to The path of the directory on the FTP server whose files are to be enumerated..
+ /// Looks up a localized string similar to The path of the folder on the FTP server whose contents are listed..
///
public static string Activity_EnumerateObjects_Property_RemotePath_Description {
get {
@@ -358,7 +394,7 @@ public static string Activity_EnumerateObjects_Property_RemotePath_Description {
}
///
- /// Looks up a localized string similar to Remote Path.
+ /// Looks up a localized string similar to Folder path.
///
public static string Activity_EnumerateObjects_Property_RemotePath_Name {
get {
@@ -367,7 +403,16 @@ public static string Activity_EnumerateObjects_Property_RemotePath_Name {
}
///
- /// Looks up a localized string similar to Checks whether a certain file exists in the specified FTP directory. This activity only works if it is placed inside a With FTP Session scope activity..
+ /// Looks up a localized string similar to /remote/folder.
+ ///
+ public static string Activity_EnumerateObjects_Property_RemotePath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_EnumerateObjects_Property_RemotePath_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Checks whether a file exists in the specified FTP folder. This activity only works if it is placed inside a Use FTP Connection activity..
///
public static string Activity_FileExists_Description {
get {
@@ -376,7 +421,7 @@ public static string Activity_FileExists_Description {
}
///
- /// Looks up a localized string similar to File Exists.
+ /// Looks up a localized string similar to Check If File Exists.
///
public static string Activity_FileExists_Name {
get {
@@ -412,7 +457,7 @@ public static string Activity_FileExists_Property_RemotePath_Description {
}
///
- /// Looks up a localized string similar to File Path.
+ /// Looks up a localized string similar to File path.
///
public static string Activity_FileExists_Property_RemotePath_Name {
get {
@@ -421,7 +466,16 @@ public static string Activity_FileExists_Property_RemotePath_Name {
}
///
- /// Looks up a localized string similar to Moves an item on an FTP server to a different remote path. This activity only works if it is placed inside a With FTP.
+ /// Looks up a localized string similar to /remote/folder/file.txt.
+ ///
+ public static string Activity_FileExists_Property_RemotePath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_FileExists_Property_RemotePath_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Moves an item on an FTP server to a different remote path. This activity only works if it is placed inside a Use FTP Connection activity..
///
public static string Activity_MoveItem_Description {
get {
@@ -475,7 +529,16 @@ public static string Activity_MoveItem_Property_NewPath_Name {
}
///
- /// Looks up a localized string similar to If this box is checked, the files will be overwritten in the new remote directory if they're already stored there..
+ /// Looks up a localized string similar to /remote/new-folder/file.txt.
+ ///
+ public static string Activity_MoveItem_Property_NewPath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_MoveItem_Property_NewPath_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to If turned on, the files are overwritten in the new remote folder if they are already stored there..
///
public static string Activity_MoveItem_Property_Overwrite_Description {
get {
@@ -484,7 +547,7 @@ public static string Activity_MoveItem_Property_Overwrite_Description {
}
///
- /// Looks up a localized string similar to Overwrite.
+ /// Looks up a localized string similar to Overwrite existing files.
///
public static string Activity_MoveItem_Property_Overwrite_Name {
get {
@@ -511,7 +574,16 @@ public static string Activity_MoveItem_Property_RemotePath_Name {
}
///
- /// Looks up a localized string similar to Uploads a file to an FTP server. This activity only works if it is placed inside a With FTP Session scope activity..
+ /// Looks up a localized string similar to /remote/folder/file.txt.
+ ///
+ public static string Activity_MoveItem_Property_RemotePath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_MoveItem_Property_RemotePath_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Uploads files to an FTP server. This activity only works if it is placed inside a Use FTP Connection activity..
///
public static string Activity_UploadFiles_Description {
get {
@@ -529,7 +601,7 @@ public static string Activity_UploadFiles_Name {
}
///
- /// Looks up a localized string similar to If this box is checked, the folder path will be created on the FTP server in case it does not already exist..
+ /// Looks up a localized string similar to If turned on, the folder path is created on the FTP server in case it does not already exist..
///
public static string Activity_UploadFiles_Property_Create_Description {
get {
@@ -538,7 +610,7 @@ public static string Activity_UploadFiles_Property_Create_Description {
}
///
- /// Looks up a localized string similar to Create.
+ /// Looks up a localized string similar to Create folder if missing.
///
public static string Activity_UploadFiles_Property_Create_Name {
get {
@@ -565,7 +637,16 @@ public static string Activity_UploadFiles_Property_LocalPath_Name {
}
///
- /// Looks up a localized string similar to If this box is checked, the files will be overwritten on the FTP server if they're already stored there..
+ /// Looks up a localized string similar to C:\Local\folder.
+ ///
+ public static string Activity_UploadFiles_Property_LocalPath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_UploadFiles_Property_LocalPath_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to If turned on, the files are overwritten on the FTP server if they are already stored there..
///
public static string Activity_UploadFiles_Property_Overwrite_Description {
get {
@@ -574,7 +655,7 @@ public static string Activity_UploadFiles_Property_Overwrite_Description {
}
///
- /// Looks up a localized string similar to Overwrite.
+ /// Looks up a localized string similar to Overwrite existing files.
///
public static string Activity_UploadFiles_Property_Overwrite_Name {
get {
@@ -583,7 +664,7 @@ public static string Activity_UploadFiles_Property_Overwrite_Name {
}
///
- /// Looks up a localized string similar to If this box is checked, the folders will be uploaded with their respective subfolders..
+ /// Looks up a localized string similar to If turned on, the folders are uploaded with their respective subfolders..
///
public static string Activity_UploadFiles_Property_Recursive_Description {
get {
@@ -618,6 +699,15 @@ public static string Activity_UploadFiles_Property_RemotePath_Name {
}
}
+ ///
+ /// Looks up a localized string similar to /remote/folder.
+ ///
+ public static string Activity_UploadFiles_Property_RemotePath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_UploadFiles_Property_RemotePath_Placeholder", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Connects to FTP server and provides a scope for other FTP activities..
///
@@ -637,7 +727,7 @@ public static string Activity_WithFtpSession_Name {
}
///
- /// Looks up a localized string similar to If this box is checked, all certificates will be accepted, including the ones that are expired or not verified..
+ /// Looks up a localized string similar to If turned on, all certificates are accepted, including the ones that are expired or not verified..
///
public static string Activity_WithFtpSession_Property_AcceptAllCertificates_Description {
get {
@@ -646,7 +736,7 @@ public static string Activity_WithFtpSession_Property_AcceptAllCertificates_Desc
}
///
- /// Looks up a localized string similar to Accept All Certificates.
+ /// Looks up a localized string similar to Accept all certificates.
///
public static string Activity_WithFtpSession_Property_AcceptAllCertificates_Name {
get {
@@ -682,7 +772,7 @@ public static string Activity_WithFtpSession_Property_ClientCertificatePassword_
}
///
- /// Looks up a localized string similar to Client Certificate Password.
+ /// Looks up a localized string similar to Client certificate password.
///
public static string Activity_WithFtpSession_Property_ClientCertificatePassword_Name {
get {
@@ -700,7 +790,7 @@ public static string Activity_WithFtpSession_Property_ClientCertificatePath_Desc
}
///
- /// Looks up a localized string similar to Client Certificate File.
+ /// Looks up a localized string similar to Client certificate file.
///
public static string Activity_WithFtpSession_Property_ClientCertificatePath_Name {
get {
@@ -708,6 +798,15 @@ public static string Activity_WithFtpSession_Property_ClientCertificatePath_Name
}
}
+ ///
+ /// Looks up a localized string similar to C:\Certificates\client.pfx.
+ ///
+ public static string Activity_WithFtpSession_Property_ClientCertificatePath_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_WithFtpSession_Property_ClientCertificatePath_Placeholder", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The password for client certificate in secure string format.
///
@@ -718,7 +817,7 @@ public static string Activity_WithFtpSession_Property_ClientCertificateSecurePas
}
///
- /// Looks up a localized string similar to Client Certificate Secure Password.
+ /// Looks up a localized string similar to Client certificate secure password.
///
public static string Activity_WithFtpSession_Property_ClientCertificateSecurePassword_Name {
get {
@@ -736,7 +835,7 @@ public static string Activity_WithFtpSession_Property_ContinueOnError_Descriptio
}
///
- /// Looks up a localized string similar to Continue On Error.
+ /// Looks up a localized string similar to Continue on error.
///
public static string Activity_WithFtpSession_Property_ContinueOnError_Name {
get {
@@ -745,7 +844,7 @@ public static string Activity_WithFtpSession_Property_ContinueOnError_Name {
}
///
- /// Looks up a localized string similar to FTP Session Scope.
+ /// Looks up a localized string similar to Use FTP Connection.
///
public static string Activity_WithFtpSession_Property_DisplayName_Name {
get {
@@ -763,7 +862,7 @@ public static string Activity_WithFtpSession_Property_FtpsMode_Description {
}
///
- /// Looks up a localized string similar to FTPS Mode.
+ /// Looks up a localized string similar to FTPS mode.
///
public static string Activity_WithFtpSession_Property_FtpsMode_Name {
get {
@@ -789,6 +888,15 @@ public static string Activity_WithFtpSession_Property_Host_Name {
}
}
+ ///
+ /// Looks up a localized string similar to ftp.example.com.
+ ///
+ public static string Activity_WithFtpSession_Property_Host_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_WithFtpSession_Property_Host_Placeholder", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The password that will be used to connect to the FTP server..
///
@@ -843,6 +951,15 @@ public static string Activity_WithFtpSession_Property_Port_Name {
}
}
+ ///
+ /// Looks up a localized string similar to 21 for FTP, 22 for SFTP.
+ ///
+ public static string Activity_WithFtpSession_Property_Port_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_WithFtpSession_Property_Port_Placeholder", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The password used for proxy if authentication is required.
///
@@ -853,7 +970,7 @@ public static string Activity_WithFtpSession_Property_ProxyPassword_Description
}
///
- /// Looks up a localized string similar to Proxy Password.
+ /// Looks up a localized string similar to Proxy password.
///
public static string Activity_WithFtpSession_Property_ProxyPassword_Name {
get {
@@ -871,7 +988,7 @@ public static string Activity_WithFtpSession_Property_ProxyPort_Description {
}
///
- /// Looks up a localized string similar to Proxy Host Port.
+ /// Looks up a localized string similar to Proxy port.
///
public static string Activity_WithFtpSession_Property_ProxyPort_Name {
get {
@@ -889,7 +1006,7 @@ public static string Activity_WithFtpSession_Property_ProxySecurePassword_Descri
}
///
- /// Looks up a localized string similar to Proxy Secure Password.
+ /// Looks up a localized string similar to Proxy secure password.
///
public static string Activity_WithFtpSession_Property_ProxySecurePassword_Name {
get {
@@ -907,7 +1024,7 @@ public static string Activity_WithFtpSession_Property_ProxyServer_Description {
}
///
- /// Looks up a localized string similar to Proxy Host.
+ /// Looks up a localized string similar to Proxy host.
///
public static string Activity_WithFtpSession_Property_ProxyServer_Name {
get {
@@ -915,6 +1032,15 @@ public static string Activity_WithFtpSession_Property_ProxyServer_Name {
}
}
+ ///
+ /// Looks up a localized string similar to proxy.example.com.
+ ///
+ public static string Activity_WithFtpSession_Property_ProxyServer_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_WithFtpSession_Property_ProxyServer_Placeholder", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The type of proxy.
///
@@ -925,7 +1051,7 @@ public static string Activity_WithFtpSession_Property_ProxyType_Description {
}
///
- /// Looks up a localized string similar to Proxy Type.
+ /// Looks up a localized string similar to Proxy type.
///
public static string Activity_WithFtpSession_Property_ProxyType_Name {
get {
@@ -943,7 +1069,7 @@ public static string Activity_WithFtpSession_Property_ProxyUser_Description {
}
///
- /// Looks up a localized string similar to Proxy Username.
+ /// Looks up a localized string similar to Proxy username.
///
public static string Activity_WithFtpSession_Property_ProxyUser_Name {
get {
@@ -961,7 +1087,7 @@ public static string Activity_WithFtpSession_Property_SecurePassword_Description
}
///
- /// Looks up a localized string similar to Secure Password.
+ /// Looks up a localized string similar to Secure password.
///
public static string Activity_WithFtpSession_Property_SecurePassword_Name {
get {
@@ -979,7 +1105,7 @@ public static string Activity_WithFtpSession_Property_SslProtocols_Description {
}
///
- /// Looks up a localized string similar to SSL Protocols.
+ /// Looks up a localized string similar to SSL protocols.
///
public static string Activity_WithFtpSession_Property_SslProtocols_Name {
get {
@@ -988,7 +1114,7 @@ public static string Activity_WithFtpSession_Property_SslProtocols_Name {
}
///
- /// Looks up a localized string similar to Leave empty for auto configuration.
+ /// Looks up a localized string similar to Auto: negotiate the best available protocol.
///
public static string Activity_WithFtpSession_Property_SslProtocols_Placeholder {
get {
@@ -1006,7 +1132,7 @@ public static string Activity_WithFtpSession_Property_Timeout_Description {
}
///
- /// Looks up a localized string similar to Timeout (milliseconds).
+ /// Looks up a localized string similar to Timeout.
///
public static string Activity_WithFtpSession_Property_Timeout_Name {
get {
@@ -1015,7 +1141,16 @@ public static string Activity_WithFtpSession_Property_Timeout_Name {
}
///
- /// Looks up a localized string similar to When this box is checked, the username and password fields are ignored, and a standard anonymous user is used instead..
+ /// Looks up a localized string similar to Milliseconds.
+ ///
+ public static string Activity_WithFtpSession_Property_Timeout_Placeholder {
+ get {
+ return ResourceManager.GetString("Activity_WithFtpSession_Property_Timeout_Placeholder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to If turned on, the username and password fields are ignored, and a standard anonymous user is used instead..
///
public static string Activity_WithFtpSession_Property_UseAnonymousLogin_Description {
get {
@@ -1024,7 +1159,7 @@ public static string Activity_WithFtpSession_Property_UseAnonymousLogin_Descript
}
///
- /// Looks up a localized string similar to Use Anonymous Login.
+ /// Looks up a localized string similar to Use anonymous login.
///
public static string Activity_WithFtpSession_Property_UseAnonymousLogin_Name {
get {
@@ -1051,7 +1186,7 @@ public static string Activity_WithFtpSession_Property_Username_Name {
}
///
- /// Looks up a localized string similar to Check this box if you want to use the SFTP transfer protocol..
+ /// Looks up a localized string similar to Turn on to use the SFTP transfer protocol..
///
public static string Activity_WithFtpSession_Property_UseSftp_Description {
get {
@@ -1067,7 +1202,61 @@ public static string Activity_WithFtpSession_Property_UseSftp_Name {
return ResourceManager.GetString("Activity_WithFtpSession_Property_UseSftp_Name", resourceCulture);
}
}
-
+
+ ///
+ /// Looks up a localized string similar to Delete.
+ ///
+ public static string ActivitySynonymDeleteFileOrFolder {
+ get {
+ return ResourceManager.GetString("ActivitySynonymDeleteFileOrFolder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Move Item.
+ ///
+ public static string ActivitySynonymMoveFileOrFolder {
+ get {
+ return ResourceManager.GetString("ActivitySynonymMoveFileOrFolder", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to With FTP connection.
+ ///
+ public static string ActivitySynonymUseFtpConnection {
+ get {
+ return ResourceManager.GetString("ActivitySynonymUseFtpConnection", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Directory Exists.
+ ///
+ public static string ActivitySynonymCheckIfFolderExists {
+ get {
+ return ResourceManager.GetString("ActivitySynonymCheckIfFolderExists", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to File Exists.
+ ///
+ public static string ActivitySynonymCheckIfFileExists {
+ get {
+ return ResourceManager.GetString("ActivitySynonymCheckIfFileExists", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Enumerate Objects.
+ ///
+ public static string ActivitySynonymListFilesAndFolders {
+ get {
+ return ResourceManager.GetString("ActivitySynonymListFilesAndFolders", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Credentials.
///
@@ -1472,7 +1661,16 @@ public static string NoValidAuthenticationMethod {
return ResourceManager.GetString("NoValidAuthenticationMethod", resourceCulture);
}
}
-
+
+ ///
+ /// Looks up a localized string similar to Anonymous login is not supported over SFTP. Turn off Use Anonymous Login or Use SFTP.
+ ///
+ public static string AnonymousLoginNotSupportedOnSftp {
+ get {
+ return ResourceManager.GetString("AnonymousLoginNotSupportedOnSftp", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to {0} (Obsolete).
///
@@ -1537,7 +1735,7 @@ public static string PasswordDescription {
}
///
- /// Looks up a localized string similar to Path "{0}" not found..
+ /// Looks up a localized string similar to Path "{0}" not found..
///
public static string PathNotFoundException {
get {
diff --git a/Activities/FTP/UiPath.FTP.Activities/Properties/UiPath.FTP.Activities.resx b/Activities/FTP/UiPath.FTP.Activities/Properties/UiPath.FTP.Activities.resx
index e57e9acdd..33ba32bb2 100644
--- a/Activities/FTP/UiPath.FTP.Activities/Properties/UiPath.FTP.Activities.resx
+++ b/Activities/FTP/UiPath.FTP.Activities/Properties/UiPath.FTP.Activities.resx
@@ -222,6 +222,9 @@
No valid authentication method found: You need to supply either Private Key file (and optionally passphrase) or Password
+
+ Anonymous login is not supported over SFTP. Turn off Use Anonymous Login or Use SFTP.
+
New remote path
@@ -321,10 +324,10 @@
Common
- FTP Session Scope
+ Use FTP Connection
- Removes a specified file from an FTP server. This activity only works if it is placed inside a With FTP Session scope activity.
+ Removes a file or folder from an FTP server. This activity only works if it is placed inside a Use FTP Connection activity.Activity description
@@ -340,11 +343,11 @@
Property name
- Checks whether a certain directory exists on an FTP server. This activity only works if it is placed inside a With FTP Session scope activity.
+ Checks whether a folder exists on an FTP server. This activity only works if it is placed inside a Use FTP Connection activity.Activity description
- Directory Exists
+ Check If Folder ExistsActivity name
@@ -360,27 +363,27 @@
Property description
- Folder Path
+ Folder pathProperty name
- Generates a collection of files that have been found on the FTP server. Subfolders can also be included in the search by checking the Includes subfolders box. This activity only works if it is placed inside a With FTP Session scope activity.
+ Generates a collection of the files and folders found on the FTP server. Subfolders can also be included by turning on Include subfolders. This activity only works if it is placed inside a Use FTP Connection activity.Activity description
- Enumerate Objects
+ List Files and FoldersActivity name
- A collection of files that have been found on the FTP server.
+ The collection of files and folders found on the FTP server.Property description
- Files
+ Files and foldersProperty name
- If this check box is selected, the subfolders are also included in the enumeration of the files on the FTP server.
+ If turned on, the subfolders are also included in the listing.Property description
@@ -388,19 +391,19 @@
Property name
- The path of the directory on the FTP server whose files are to be enumerated.
+ The path of the folder on the FTP server whose contents are listed.Property description
- Remote Path
+ Folder pathProperty name
- Checks whether a certain file exists in the specified FTP directory. This activity only works if it is placed inside a With FTP Session scope activity.
+ Checks whether a file exists in the specified FTP folder. This activity only works if it is placed inside a Use FTP Connection activity.Activity description
- File Exists
+ Check If File ExistsActivity name
@@ -416,11 +419,11 @@
Property description
- File Path
+ File pathProperty name
- Uploads a file to an FTP server. This activity only works if it is placed inside a With FTP Session scope activity.
+ Uploads files to an FTP server. This activity only works if it is placed inside a Use FTP Connection activity.Activity description
@@ -428,11 +431,11 @@
Activity name
- If this box is checked, the folder path will be created on the FTP server in case it does not already exist.
+ If turned on, the folder path is created on the FTP server in case it does not already exist.Property description
- Create
+ Create folder if missingProperty name
@@ -444,15 +447,15 @@
Property name
- If this box is checked, the files will be overwritten on the FTP server if they're already stored there.
+ If turned on, the files are overwritten on the FTP server if they are already stored there.Property description
- Overwrite
+ Overwrite existing filesProperty name
- If this box is checked, the folders will be uploaded with their respective subfolders.
+ If turned on, the folders are uploaded with their respective subfolders.Property description
@@ -476,11 +479,11 @@
Activity name
- If this box is checked, all certificates will be accepted, including the ones that are expired or not verified.
+ If turned on, all certificates are accepted, including the ones that are expired or not verified.Property description
- Accept All Certificates
+ Accept all certificatesProperty name
@@ -488,7 +491,7 @@
Property description
- Client Certificate Password
+ Client certificate passwordProperty name
@@ -496,7 +499,7 @@
Property description
- Client Certificate File
+ Client certificate fileProperty name
@@ -504,7 +507,7 @@
Property description
- Continue On Error
+ Continue on errorProperty name
@@ -512,7 +515,7 @@
Property description
- FTPS Mode
+ FTPS modeProperty name
@@ -548,19 +551,19 @@
Property description
- Timeout (milliseconds)
+ TimeoutProperty name
- SSL Protocols
+ SSL protocolsProperty name
- When this box is checked, the username and password fields are ignored, and a standard anonymous user is used instead.
+ If turned on, the username and password fields are ignored, and a standard anonymous user is used instead.Property description
- Use Anonymous Login
+ Use anonymous loginProperty name
@@ -572,7 +575,7 @@
Property name
- Check this box if you want to use the SFTP transfer protocol.
+ Turn on to use the SFTP transfer protocol.Property description
@@ -580,7 +583,7 @@
Property name
- Downloads the specified files from an FTP server to the specified local folder. This activity only works if it is placed inside a With FTP Session scope activity.
+ Downloads the specified files from an FTP server to the specified local folder. This activity only works if it is placed inside a Use FTP Connection activity.Activity description
@@ -588,11 +591,11 @@
Activity name
- If this box is checked, the folder path will be created locally in case it does not already exist.
+ If turned on, the folder path is created locally in case it does not already exist.Property description
- Create
+ Create folder if missingProperty name
@@ -604,15 +607,15 @@
Property name
- If this box is checked, the files will be overwritten locally if they're already stored there.
+ If turned on, the files are overwritten locally if they are already stored there.Property description
- Overwrite
+ Overwrite existing filesProperty name
- If this box is checked, the folders will be downloaded with their respective subfolders.
+ If turned on, the folders are downloaded with their respective subfolders.Property description
@@ -628,7 +631,7 @@
Property name
- Moves an item on an FTP server to a different remote path. This activity only works if it is placed inside a With FTP
+ Moves an item on an FTP server to a different remote path. This activity only works if it is placed inside a Use FTP Connection activity.Activity description
@@ -652,11 +655,11 @@
Property name
- If this box is checked, the files will be overwritten in the new remote directory if they're already stored there.
+ If turned on, the files are overwritten in the new remote folder if they are already stored there.Property description
- Overwrite
+ Overwrite existing filesProperty name
@@ -705,7 +708,7 @@
The password for client certificate in secure string format
- Client Certificate Secure Password
+ Client certificate secure passwordThe switch for password input mode
@@ -719,7 +722,7 @@
The password in secure string format
- Secure Password
+ Secure passwordClientCertificatePassword and ClientCertificateSecurePassword must not be both null
@@ -731,31 +734,31 @@
The password used for proxy if authentication is required
- Proxy Password
+ Proxy passwordProxy port number
- Proxy Host Port
+ Proxy portProxy host name
- Proxy Host
+ Proxy hostThe type of proxy
- Proxy Type
+ Proxy typeThe user used for proxy if authentication is required
- Proxy Username
+ Proxy usernameProxy
@@ -769,23 +772,92 @@
it is used to mark the obsolete values in a dropdown
- Leave empty for auto configuration
+ Auto: negotiate the best available protocolThe proxy password in secure string format
- Proxy Secure Password
+ Proxy secure passwordFilters items based on type (what is selected will be included)Property description
- Object types
+ Item types to includeProperty name
- Select object types to include
+ Select the item types to include
+
+
+ /remote/folder/file.txt
+
+
+ /remote/folder
+
+
+ /remote/folder/file.txt
+
+
+ /remote/folder
+
+
+ /remote/folder
+
+
+ C:\Local\folder
+
+
+ C:\Local\folder
+
+
+ /remote/folder
+
+
+ /remote/folder/file.txt
+
+
+ /remote/new-folder/file.txt
+
+
+ ftp.example.com
+
+
+ 21 for FTP, 22 for SFTP
+
+
+ Milliseconds
+
+
+ C:\Certificates\client.pfx
+
+
+ proxy.example.com
+
+
+ Delete
+ Activity search alias
+
+
+ Move Item
+ Activity search alias
+
+
+ With FTP connection
+ Activity search alias
+
+
+ Directory Exists
+ Activity search alias
+
+
+ File Exists
+ Activity search alias
+
+
+ Enumerate Objects
+ Activity search alias
\ No newline at end of file
diff --git a/Activities/FTP/UiPath.FTP.Activities/Resources/ActivitiesMetadata.json b/Activities/FTP/UiPath.FTP.Activities/Resources/ActivitiesMetadata.json
index 936f4cd27..056a8c097 100644
--- a/Activities/FTP/UiPath.FTP.Activities/Resources/ActivitiesMetadata.json
+++ b/Activities/FTP/UiPath.FTP.Activities/Resources/ActivitiesMetadata.json
@@ -5,76 +5,21 @@
"FullName": "UiPath.FTP.Activities.Delete",
"ShortName": "Delete",
"DisplayNameKey": "Activity_Delete_Name",
+ "DisplayNameAliasKeys": [ "ActivitySynonymDeleteFileOrFolder" ],
"DescriptionKey": "Activity_Delete_Description",
"IconKey": "Delete_file_or_folder.svg",
- "Properties": [
- {
- "Name": "RemotePath",
- "DisplayNameKey": "Activity_Delete_Property_RemotePath_Name",
- "TooltipKey": "Activity_Delete_Property_RemotePath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Input"
- }
- },
- {
- "Name": "ContinueOnError",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ContinueOnError_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ContinueOnError_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- }
- ],
- "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.DeleteViewModel"
+ "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.DeleteViewModel",
+ "Properties": []
},
{
"FullName": "UiPath.FTP.Activities.DirectoryExists",
"ShortName": "DirectoryExists",
"DisplayNameKey": "Activity_DirectoryExists_Name",
+ "DisplayNameAliasKeys": [ "ActivitySynonymCheckIfFolderExists" ],
"DescriptionKey": "Activity_DirectoryExists_Description",
"IconKey": "Folder_exists.svg",
- "Properties": [
- {
- "Name": "RemotePath",
- "DisplayNameKey": "Activity_DirectoryExists_Property_RemotePath_Name",
- "TooltipKey": "Activity_DirectoryExists_Property_RemotePath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Input"
- }
- },
- {
- "Name": "ContinueOnError",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ContinueOnError_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ContinueOnError_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "Exists",
- "DisplayNameKey": "Activity_DirectoryExists_Property_Exists_Name",
- "TooltipKey": "Activity_DirectoryExists_Property_Exists_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Output"
- }
- }
- ],
- "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.DirectoryExistsViewModel"
+ "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.DirectoryExistsViewModel",
+ "Properties": []
},
{
"FullName": "UiPath.FTP.Activities.DownloadFiles",
@@ -82,238 +27,38 @@
"DisplayNameKey": "Activity_DownloadFiles_Name",
"DescriptionKey": "Activity_DownloadFiles_Description",
"IconKey": "Download_files.svg",
- "Properties": [
- {
- "Name": "RemotePath",
- "DisplayNameKey": "Activity_DownloadFiles_Property_RemotePath_Name",
- "TooltipKey": "Activity_DownloadFiles_Property_RemotePath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Principal_Name"
- }
- },
- {
- "Name": "LocalPath",
- "DisplayNameKey": "Activity_DownloadFiles_Property_LocalPath_Name",
- "TooltipKey": "Activity_DownloadFiles_Property_LocalPath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Principal_Name"
- }
- },
- {
- "Name": "Recursive",
- "DisplayNameKey": "Activity_DownloadFiles_Property_Recursive_Name",
- "TooltipKey": "Activity_DownloadFiles_Property_Recursive_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "Create",
- "DisplayNameKey": "Activity_DownloadFiles_Property_Create_Name",
- "TooltipKey": "Activity_DownloadFiles_Property_Create_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "Overwrite",
- "DisplayNameKey": "Activity_DownloadFiles_Property_Overwrite_Name",
- "TooltipKey": "Activity_DownloadFiles_Property_Overwrite_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "ContinueOnError",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ContinueOnError_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ContinueOnError_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- }
- ],
- "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.DownloadFilesViewModel"
+ "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.DownloadFilesViewModel",
+ "Properties": []
},
{
"FullName": "UiPath.FTP.Activities.EnumerateObjects",
"ShortName": "EnumerateObjects",
"DisplayNameKey": "Activity_EnumerateObjects_Name",
+ "DisplayNameAliasKeys": [ "ActivitySynonymListFilesAndFolders" ],
"DescriptionKey": "Activity_EnumerateObjects_Description",
"IconKey": "Get_files.svg",
- "Properties": [
- {
- "Name": "RemotePath",
- "DisplayNameKey": "Activity_EnumerateObjects_Property_RemotePath_Name",
- "TooltipKey": "Activity_EnumerateObjects_Property_RemotePath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Principal_Name"
- }
- },
- {
- "Name": "Recursive",
- "DisplayNameKey": "Activity_EnumerateObjects_Property_Recursive_Name",
- "TooltipKey": "Activity_EnumerateObjects_Property_Recursive_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "ContinueOnError",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ContinueOnError_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ContinueOnError_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "Filter",
- "DisplayNameKey": "Activity_EnumerateObjects_Property_Filter_Name",
- "TooltipKey": "Activity_EnumerateObjects_Property_Filter_Description",
- "placeholderKey": "Activity_EnumerateObjects_Property_Filter_Placeholder",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "Files",
- "DisplayNameKey": "Activity_EnumerateObjects_Property_Files_Name",
- "TooltipKey": "Activity_EnumerateObjects_Property_Files_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Output_Name"
- }
- }
- ],
- "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.EnumerateObjectsViewModel"
+ "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.EnumerateObjectsViewModel",
+ "Properties": []
},
{
"FullName": "UiPath.FTP.Activities.FileExists",
"ShortName": "FileExists",
"DisplayNameKey": "Activity_FileExists_Name",
+ "DisplayNameAliasKeys": [ "ActivitySynonymCheckIfFileExists" ],
"DescriptionKey": "Activity_FileExists_Description",
"IconKey": "File_exists.svg",
- "Properties": [
- {
- "Name": "RemotePath",
- "DisplayNameKey": "Activity_FileExists_Property_RemotePath_Name",
- "TooltipKey": "Activity_FileExists_Property_RemotePath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Principal_Name"
- }
- },
- {
- "Name": "ContinueOnError",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ContinueOnError_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ContinueOnError_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "Exists",
- "DisplayNameKey": "Activity_FileExists_Property_Exists_Name",
- "TooltipKey": "Activity_FileExists_Property_Exists_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Output_Name"
- }
- }
- ],
- "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.FileExistsViewModel"
+ "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.FileExistsViewModel",
+ "Properties": []
},
{
"FullName": "UiPath.FTP.Activities.MoveItem",
"ShortName": "MoveItem",
"DisplayNameKey": "Activity_MoveItem_Name",
+ "DisplayNameAliasKeys": [ "ActivitySynonymMoveFileOrFolder" ],
"DescriptionKey": "Activity_MoveItem_Description",
"IconKey": "Move_file_or_folder.svg",
- "Properties": [
- {
- "Name": "RemotePath",
- "DisplayNameKey": "Activity_MoveItem_Property_RemotePath_Name",
- "TooltipKey": "Activity_MoveItem_Property_RemotePath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Principal_Name"
- }
- },
- {
- "Name": "NewPath",
- "DisplayNameKey": "Activity_MoveItem_Property_NewPath_Name",
- "TooltipKey": "Activity_MoveItem_Property_NewPath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Principal_Name"
- }
- },
- {
- "Name": "Overwrite",
- "DisplayNameKey": "Activity_MoveItem_Property_Overwrite_Name",
- "TooltipKey": "Activity_MoveItem_Property_Overwrite_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "ContinueOnError",
- "DisplayNameKey": "Activity_MoveItem_Property_ContinueOnError_Name",
- "TooltipKey": "Activity_MoveItem_Property_ContinueOnError_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- }
- ],
- "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.MoveItemViewModel"
+ "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.MoveItemViewModel",
+ "Properties": []
},
{
"FullName": "UiPath.FTP.Activities.UploadFiles",
@@ -321,328 +66,21 @@
"DisplayNameKey": "Activity_UploadFiles_Name",
"DescriptionKey": "Activity_UploadFiles_Description",
"IconKey": "Upload_files.svg",
- "Properties": [
- {
- "Name": "LocalPath",
- "DisplayNameKey": "Activity_UploadFiles_Property_LocalPath_Name",
- "TooltipKey": "Activity_UploadFiles_Property_LocalPath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Principal_Name"
- }
- },
- {
- "Name": "RemotePath",
- "DisplayNameKey": "Activity_UploadFiles_Property_RemotePath_Name",
- "TooltipKey": "Activity_UploadFiles_Property_RemotePath_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Principal_Name"
- }
- },
- {
- "Name": "Recursive",
- "DisplayNameKey": "Activity_UploadFiles_Property_Recursive_Name",
- "TooltipKey": "Activity_UploadFiles_Property_Recursive_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "Create",
- "DisplayNameKey": "Activity_UploadFiles_Property_Create_Name",
- "TooltipKey": "Activity_UploadFiles_Property_Create_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "Overwrite",
- "DisplayNameKey": "Activity_UploadFiles_Property_Overwrite_Name",
- "TooltipKey": "Activity_UploadFiles_Property_Overwrite_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- },
- {
- "Name": "ContinueOnError",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ContinueOnError_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ContinueOnError_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Others_Name"
- }
- }
- ],
- "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.UploadFilesViewModel"
+ "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.UploadFilesViewModel",
+ "Properties": []
},
{
"FullName": "UiPath.FTP.Activities.WithFtpSession",
"ShortName": "WithFtpSession",
"DisplayNameKey": "Activity_WithFtpSession_Name",
+ "DisplayNameAliasKeys": [ "ActivitySynonymUseFtpConnection" ],
"DescriptionKey": "Activity_WithFtpSession_Description",
"IconKey": "FTP_Connection.svg",
- "Properties": [
- {
- "Name": "Body",
- "IsVisible": false
- },
- {
- "Name": "Host",
- "DisplayNameKey": "Activity_WithFtpSession_Property_Host_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_Host_Description",
- "IsRequired": true,
- "IsPrincipal": true,
- "IsVisible": true
- },
- {
- "Name": "Port",
- "DisplayNameKey": "Activity_WithFtpSession_Property_Port_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_Port_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true
- },
- {
- "Name": "Timeout",
- "DisplayNameKey": "Activity_WithFtpSession_Property_Timeout_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_Timeout_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true
- },
- {
- "Name": "Username",
- "DisplayNameKey": "Activity_WithFtpSession_Property_Username_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_Username_Description",
- "IsRequired": false,
- "IsPrincipal": true,
- "IsVisible": true
- },
- {
- "Name": "Password",
- "DisplayNameKey": "Activity_WithFtpSession_Property_Password_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_Password_Description",
- "IsRequired": false,
- "IsPrincipal": true,
- "IsVisible": true
- },
- {
- "Name": "SecurePassword",
- "DisplayNameKey": "Activity_WithFtpSession_Property_SecurePassword_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_SecurePassword_Description",
- "IsRequired": false,
- "IsPrincipal": true,
- "IsVisible": false
- },
- {
- "Name": "PasswordInputModeSwitch",
- "DisplayNameKey": "Activity_WithFtpSession_Property_PasswordInputModeSwitch_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_PasswordInputModeSwitch_Description",
- "IsRequired": false,
- "IsVisible": false,
- "Category": {
- "DisplayNameKey": "Input"
- }
- },
- {
- "Name": "UseAnonymousLogin",
- "DisplayNameKey": "Activity_WithFtpSession_Property_UseAnonymousLogin_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_UseAnonymousLogin_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true
- },
- {
- "Name": "FtpsMode",
- "DisplayNameKey": "Activity_WithFtpSession_Property_FtpsMode_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_FtpsMode_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Security_Name"
- }
- },
- {
- "Name": "SslProtocols",
- "DisplayNameKey": "Activity_WithFtpSession_Property_SslProtocols_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_SslProtocols_Description",
- "placeholderKey": "Activity_WithFtpSession_Property_SslProtocols_Placeholder",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Security_Name"
- }
- },
- {
- "Name": "UseSftp",
- "DisplayNameKey": "Activity_WithFtpSession_Property_UseSftp_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_UseSftp_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Security_Name"
- }
- },
- {
- "Name": "ClientCertificatePath",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ClientCertificatePath_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ClientCertificatePath_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Security_Name"
- }
- },
- {
- "Name": "ClientCertificatePassword",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ClientCertificatePassword_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ClientCertificatePassword_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Security_Name"
- }
- },
- {
- "Name": "ClientCertificateSecurePassword",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ClientCertificateSecurePassword_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ClientCertificateSecurePassword_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": false,
- "Category": {
- "DisplayNameKey": "Category_Security_Name"
- }
- },
- {
- "Name": "CertificatePasswordInputModeSwitch",
- "DisplayNameKey": "Activity_WithFtpSession_Property_CertificatePasswordInputModeSwitch_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_CertificatePasswordInputModeSwitch_Description",
- "IsRequired": false,
- "IsVisible": false,
- "Category": {
- "DisplayNameKey": "Input"
- }
- },
- {
- "Name": "AcceptAllCertificates",
- "DisplayNameKey": "Activity_WithFtpSession_Property_AcceptAllCertificates_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_AcceptAllCertificates_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Category_Security_Name"
- }
- },
- {
- "Name": "ContinueOnError",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ContinueOnError_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ContinueOnError_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true
- },
- {
- "Name": "ProxyType",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ProxyType_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ProxyType_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Proxy"
- }
- },
- {
- "Name": "ProxyServer",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ProxyServer_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ProxyServer_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Proxy"
- }
- },
- {
- "Name": "ProxyPort",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ProxyPort_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ProxyPort_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Proxy"
- }
- },
- {
- "Name": "ProxyUser",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ProxyUser_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ProxyUser_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Proxy"
- }
- },
- {
- "Name": "ProxyPassword",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ProxyPassword_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ProxyPassword_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": true,
- "Category": {
- "DisplayNameKey": "Proxy"
- }
- },
- {
- "Name": "ProxySecurePassword",
- "DisplayNameKey": "Activity_WithFtpSession_Property_ProxySecurePassword_Name",
- "TooltipKey": "Activity_WithFtpSession_Property_ProxySecurePassword_Description",
- "IsRequired": false,
- "IsPrincipal": false,
- "IsVisible": false,
- "Category": {
- "DisplayNameKey": "Proxy"
- }
- },
- {
- "Name": "ProxyPasswordInputModeSwitch",
- "IsRequired": false,
- "IsVisible": false,
- "Category": {
- "DisplayNameKey": "Proxy"
- }
- }
- ],
- "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.WithFtpSessionViewModel"
+ "ViewModelType": "UiPath.FTP.Activities.NetCore.ViewModels.WithFtpSessionViewModel",
+ "Properties": []
}
],
"DefaultActivityColor": "#526069",
"DefaultActivityNameBackgroundColor": "#FFFFFF",
"ResourceManagerName": "UiPath.FTP.Activities.Properties.UiPath.FTP.Activities"
-}
\ No newline at end of file
+}
diff --git a/Activities/FTP/UiPath.FTP.Activities/UiPath.FTP.Activities.csproj b/Activities/FTP/UiPath.FTP.Activities/UiPath.FTP.Activities.csproj
index 553a9e2e3..ee74439e9 100644
--- a/Activities/FTP/UiPath.FTP.Activities/UiPath.FTP.Activities.csproj
+++ b/Activities/FTP/UiPath.FTP.Activities/UiPath.FTP.Activities.csproj
@@ -46,9 +46,6 @@
-
-
-
diff --git a/Activities/FTP/UiPath.FTP.Activities/WithFtpSession.cs b/Activities/FTP/UiPath.FTP.Activities/WithFtpSession.cs
index debbc51c0..29f76c77a 100644
--- a/Activities/FTP/UiPath.FTP.Activities/WithFtpSession.cs
+++ b/Activities/FTP/UiPath.FTP.Activities/WithFtpSession.cs
@@ -1,5 +1,6 @@
using System;
using System.Activities;
+using System.Activities.Expressions;
using System.Activities.Statements;
using System.ComponentModel;
using System.Threading;
@@ -30,27 +31,27 @@ public partial class WithFtpSession : ContinuableAsyncNativeActivity
public ActivityAction Body { get; set; }
[RequiredArgument]
- [LocalizedCategory(nameof(Resources.Server))]
+ [LocalizedCategory(nameof(Resources.Input))]
[LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_Host_Name))]
[LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_Host_Description))]
public InArgument Host { get; set; }
- [LocalizedCategory(nameof(Resources.Server))]
+ [LocalizedCategory(nameof(Resources.Options))]
[LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_Port_Name))]
[LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_Port_Description))]
public InArgument Port { get; set; }
- [LocalizedCategory(nameof(Resources.Credentials))]
+ [LocalizedCategory(nameof(Resources.Input))]
[LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_Username_Name))]
[LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_Username_Description))]
public InArgument Username { get; set; }
- [LocalizedCategory(nameof(Resources.Credentials))]
+ [LocalizedCategory(nameof(Resources.Input))]
[LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_Password_Name))]
[LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_Password_Description))]
public InArgument Password { get; set; }
- [LocalizedCategory(nameof(Resources.Credentials))]
+ [LocalizedCategory(nameof(Resources.Input))]
[LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_SecurePassword_Name))]
[LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_SecurePassword_Description))]
public InArgument SecurePassword { get; set; }
@@ -62,7 +63,7 @@ public partial class WithFtpSession : ContinuableAsyncNativeActivity
public PasswordInputMode PasswordInputModeSwitch { get; set; }
[DefaultValue(false)]
- [LocalizedCategory(nameof(Resources.Credentials))]
+ [LocalizedCategory(nameof(Resources.Options))]
[LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_UseAnonymousLogin_Name))]
[LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_UseAnonymousLogin_Description))]
public bool UseAnonymousLogin { get; set; }
@@ -113,12 +114,12 @@ public partial class WithFtpSession : ContinuableAsyncNativeActivity
public bool AcceptAllCertificates { get; set; }
[DefaultValue(null)]
- [LocalizedCategory(nameof(Resources.Server))]
+ [LocalizedCategory(nameof(Resources.Options))]
[LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_Timeout_Name))]
[LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_Timeout_Description))]
public InArgument Timeout { get; set; }
- [LocalizedCategory(nameof(Resources.Common))]
+ [LocalizedCategory(nameof(Resources.Options))]
[LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_ContinueOnError_Name))]
[LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_ContinueOnError_Description))]
public override InArgument ContinueOnError { get; set; } = false;
@@ -149,8 +150,8 @@ public partial class WithFtpSession : ContinuableAsyncNativeActivity
[DefaultValue(null)]
[LocalizedCategory(nameof(Resources.Proxy))]
- [LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_SecurePassword_Name))]
- [LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_SecurePassword_Description))]
+ [LocalizedDisplayName(nameof(Resources.Activity_WithFtpSession_Property_ProxySecurePassword_Name))]
+ [LocalizedDescription(nameof(Resources.Activity_WithFtpSession_Property_ProxySecurePassword_Description))]
public InArgument ProxySecurePassword { get; set; }
[Browsable(false)]
@@ -180,12 +181,67 @@ internal WithFtpSession(IFtpSession setFtpSession): this()
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
- if (ProxyType != FtpProxyType.None && ProxyServer?.Expression == null)
+
+ ValidateProxyConfiguration(metadata);
+ ValidateAuthenticationMethod(metadata);
+ ValidateTimeout(metadata);
+ }
+
+ private void ValidateProxyConfiguration(NativeActivityMetadata metadata)
+ {
+ if (ProxyType == FtpProxyType.None)
+ {
+ return;
+ }
+
+ if (ProxyServer?.Expression == null)
metadata.AddValidationError(new ValidationError(string.Format(Resources.ValidationErrorFormat, Resources.Activity_WithFtpSession_Property_ProxyServer_Name), false, nameof(ProxyServer)));
- if (ProxyType != FtpProxyType.None && ProxyPort?.Expression == null)
+ if (ProxyPort?.Expression == null)
metadata.AddValidationError(new ValidationError(string.Format(Resources.ValidationErrorFormat, Resources.Activity_WithFtpSession_Property_ProxyPort_Name), false, nameof(ProxyPort)));
}
+ ///
+ /// Surfaces at design time what ExecuteAsync would otherwise only throw at runtime, so the
+ /// fields get an error indicator and an entry in the Issues panel.
+ ///
+ private void ValidateAuthenticationMethod(NativeActivityMetadata metadata)
+ {
+ // SFTP has no concept of anonymous login: unlike FtpSession, SftpSession always builds
+ // its authentication methods from Username plus a password/keyboard-interactive or
+ // private-key credential, and ExecuteAsync never populates Username when
+ // UseAnonymousLogin is on. That combination reaches OpenAsync and always throws
+ // NoValidAuthenticationMethod, regardless of what else is configured.
+ if (UseSftp && UseAnonymousLogin)
+ metadata.AddValidationError(new ValidationError(Resources.AnonymousLoginNotSupportedOnSftp, false, nameof(UseAnonymousLogin)));
+
+ if (UseAnonymousLogin)
+ {
+ return;
+ }
+
+ if (Username?.Expression == null)
+ metadata.AddValidationError(new ValidationError(Resources.EmptyUsernameException, false, nameof(Username)));
+
+ bool passwordProvided = PasswordInputModeSwitch == PasswordInputMode.Password
+ ? Password?.Expression != null
+ : SecurePassword?.Expression != null;
+ if (passwordProvided || ClientCertificatePath?.Expression != null)
+ {
+ return;
+ }
+
+ string passwordPropertyName = PasswordInputModeSwitch == PasswordInputMode.Password
+ ? nameof(Password)
+ : nameof(SecurePassword);
+ metadata.AddValidationError(new ValidationError(Resources.NoValidAuthenticationMethod, false, passwordPropertyName));
+ }
+
+ private void ValidateTimeout(NativeActivityMetadata metadata)
+ {
+ if (Timeout?.Expression is Literal timeoutLiteral && timeoutLiteral.Value < 0)
+ metadata.AddValidationError(new ValidationError(Resources.InvalidTimeoutException, false, nameof(Timeout)));
+ }
+
protected override async Task> ExecuteAsync(NativeActivityContext context, CancellationToken cancellationToken)
{
ITelemetryOperationWrapper telemetryOperation = null;
@@ -195,92 +251,99 @@ protected override async Task> ExecuteAsync(Native
try
{
- string passwordValue = Password.Get(context);
- SecureString securePasswordValue = SecurePassword.Get(context);
- string clientCertificatePasswordValue = ClientCertificatePassword.Get(context);
- SecureString clientCertificateSecurePasswordValue = ClientCertificateSecurePassword.Get(context);
-
- FtpConfiguration ftpConfiguration = new FtpConfiguration(Host.Get(context));
- ftpConfiguration.Port = Port.Expression == null ? null : (int?)Port.Get(context);
- int? timeout = Timeout.Expression == null ? null : (int?)Timeout.Get(context);
- if (timeout.HasValue && timeout.Value < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(Timeout), Resources.InvalidTimeoutException);
- }
- ftpConfiguration.Timeout = timeout;
- ftpConfiguration.UseAnonymousLogin = UseAnonymousLogin;
- ftpConfiguration.SslProtocols = SslProtocols;
- ftpConfiguration.ProxyType = ProxyType;
-
- if (PasswordInputModeSwitch == PasswordInputMode.Password)
- {
- ftpConfiguration.Password = passwordValue;
- }
- else
- {
- ftpConfiguration.Password = new NetworkCredential("", securePasswordValue).Password;
- }
-
- if (ftpConfiguration.ProxyType != FtpProxyType.None)
- {
- ftpConfiguration.ProxyServer = ProxyServer.Get(context);
- ftpConfiguration.ProxyPort = ProxyPort.Expression == null ? null : (int?)ProxyPort.Get(context);
- ftpConfiguration.ProxyUsername = ProxyUser.Get(context);
-
- if (ProxyPasswordInputModeSwitch == PasswordInputMode.Password)
- ftpConfiguration.ProxyPassword = ProxyPassword.Get(context);
- else
- ftpConfiguration.ProxyPassword = new NetworkCredential(string.Empty, ProxySecurePassword.Get(context)).Password;
- }
-
- ftpConfiguration.ClientCertificatePath = ClientCertificatePath.Get(context);
- ftpConfiguration.ClientCertificatePassword = clientCertificatePasswordValue;
- if (ftpConfiguration.ClientCertificatePassword == null)
- {
- ftpConfiguration.ClientCertificatePassword = new NetworkCredential("", clientCertificateSecurePasswordValue).Password;
- }
-
- ftpConfiguration.AcceptAllCertificates = AcceptAllCertificates;
-
- if (ftpConfiguration.UseAnonymousLogin == false)
- {
- ftpConfiguration.Username = Username.Get(context);
- if (string.IsNullOrWhiteSpace(ftpConfiguration.Username))
- {
- throw new ArgumentNullException(Resources.EmptyUsernameException);
- }
-
- if (string.IsNullOrWhiteSpace(ftpConfiguration.Password) && string.IsNullOrWhiteSpace(ftpConfiguration.ClientCertificatePath))
- {
- throw new ArgumentNullException(Resources.NoValidAuthenticationMethod);
- }
- }
-
- IFtpSession ftpSession = _setFtpSession;
-
- if (UseSftp)
- ftpSession ??= new SftpSession(ftpConfiguration);
- else
- ftpSession ??= new FtpSession(ftpConfiguration, FtpsMode);
+ FtpConfiguration ftpConfiguration = BuildFtpConfiguration(context);
+ IFtpSession ftpSession = _setFtpSession ?? CreateFtpSession(ftpConfiguration);
await ftpSession.OpenAsync(cancellationToken);
- var result = new Action(nativeActivityContext =>
- {
- if (Body != null)
- {
- _ftpSession = ftpSession;
- nativeActivityContext.ScheduleAction(Body, ftpSession, OnCompleted, OnFaulted);
- }
- });
- return result;
+ return nativeActivityContext => ScheduleBody(nativeActivityContext, ftpSession);
}
catch (Exception ex)
{
telemetryOperation?.SendWithException(ex);
throw;
}
+ }
+
+ private FtpConfiguration BuildFtpConfiguration(NativeActivityContext context)
+ {
+ string passwordValue = Password.Get(context);
+ SecureString securePasswordValue = SecurePassword.Get(context);
+ string clientCertificatePasswordValue = ClientCertificatePassword.Get(context);
+ SecureString clientCertificateSecurePasswordValue = ClientCertificateSecurePassword.Get(context);
+
+ FtpConfiguration ftpConfiguration = new FtpConfiguration(Host.Get(context));
+ ftpConfiguration.Port = Port.Expression == null ? null : (int?)Port.Get(context);
+ int? timeout = Timeout.Expression == null ? null : (int?)Timeout.Get(context);
+ if (timeout.HasValue && timeout.Value < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(Timeout), Resources.InvalidTimeoutException);
+ }
+ ftpConfiguration.Timeout = timeout;
+ ftpConfiguration.UseAnonymousLogin = UseAnonymousLogin;
+ ftpConfiguration.SslProtocols = SslProtocols;
+ ftpConfiguration.ProxyType = ProxyType;
+ ftpConfiguration.Password = PasswordInputModeSwitch == PasswordInputMode.Password
+ ? passwordValue
+ : new NetworkCredential("", securePasswordValue).Password;
+
+ ConfigureProxy(ftpConfiguration, context);
+
+ ftpConfiguration.ClientCertificatePath = ClientCertificatePath.Get(context);
+ ftpConfiguration.ClientCertificatePassword = clientCertificatePasswordValue
+ ?? new NetworkCredential("", clientCertificateSecurePasswordValue).Password;
+
+ ftpConfiguration.AcceptAllCertificates = AcceptAllCertificates;
+
+ if (ftpConfiguration.UseAnonymousLogin == false)
+ {
+ ResolveCredentials(context, ftpConfiguration);
+ }
+
+ return ftpConfiguration;
+ }
+
+ private void ConfigureProxy(FtpConfiguration ftpConfiguration, NativeActivityContext context)
+ {
+ if (ftpConfiguration.ProxyType == FtpProxyType.None)
+ {
+ return;
+ }
+
+ ftpConfiguration.ProxyServer = ProxyServer.Get(context);
+ ftpConfiguration.ProxyPort = ProxyPort.Expression == null ? null : (int?)ProxyPort.Get(context);
+ ftpConfiguration.ProxyUsername = ProxyUser.Get(context);
+ ftpConfiguration.ProxyPassword = ProxyPasswordInputModeSwitch == PasswordInputMode.Password
+ ? ProxyPassword.Get(context)
+ : new NetworkCredential(string.Empty, ProxySecurePassword.Get(context)).Password;
+ }
+
+ private void ResolveCredentials(NativeActivityContext context, FtpConfiguration ftpConfiguration)
+ {
+ ftpConfiguration.Username = Username.Get(context);
+ if (string.IsNullOrWhiteSpace(ftpConfiguration.Username))
+ {
+ throw new ArgumentNullException(Resources.EmptyUsernameException);
+ }
+
+ if (string.IsNullOrWhiteSpace(ftpConfiguration.Password) && string.IsNullOrWhiteSpace(ftpConfiguration.ClientCertificatePath))
+ {
+ throw new ArgumentNullException(Resources.NoValidAuthenticationMethod);
+ }
+ }
+
+ private IFtpSession CreateFtpSession(FtpConfiguration ftpConfiguration)
+ => UseSftp ? new SftpSession(ftpConfiguration) : new FtpSession(ftpConfiguration, FtpsMode);
+
+ private void ScheduleBody(NativeActivityContext nativeActivityContext, IFtpSession ftpSession)
+ {
+ if (Body == null)
+ {
+ return;
+ }
+ _ftpSession = ftpSession;
+ nativeActivityContext.ScheduleAction(Body, ftpSession, OnCompleted, OnFaulted);
}
private void OnCompleted(NativeActivityContext context, ActivityInstance completedInstance)
diff --git a/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/DeleteViewModelTests.cs b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/DeleteViewModelTests.cs
new file mode 100644
index 000000000..dee4a35a2
--- /dev/null
+++ b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/DeleteViewModelTests.cs
@@ -0,0 +1,47 @@
+using System.Activities.DesignViewModels;
+using System.Activities.ViewModels;
+using System.Threading.Tasks;
+using Moq;
+using UiPath.FTP.Activities.NetCore.ViewModels;
+using UiPath.FTP.Activities.Properties;
+using Xunit;
+
+namespace UiPath.FTP.Tests
+{
+ ///
+ /// Coverage for : the only design-time behavior this
+ /// ViewModel has is the property configuration below (no rules, no dependencies, no data sources).
+ ///
+ public class DeleteViewModelTests
+ {
+ private static DeleteViewModel NewViewModel() =>
+ new DeleteViewModel(Mock.Of());
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresRemotePath()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.True(vm.RemotePath.IsRequired);
+ Assert.True(vm.RemotePath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.RemotePath.Category);
+ Assert.Equal(1, vm.RemotePath.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresContinueOnError()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.ContinueOnError.IsPrincipal);
+ Assert.False(vm.ContinueOnError.IsRequired);
+ Assert.Equal(Resources.Options, vm.ContinueOnError.Category);
+ Assert.Equal(ViewModelWidgetType.NullableBoolean, vm.ContinueOnError.Widget.Type);
+ Assert.Equal(2, vm.ContinueOnError.OrderIndex);
+ }
+ }
+}
diff --git a/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/DirectoryExistsViewModelTests.cs b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/DirectoryExistsViewModelTests.cs
new file mode 100644
index 000000000..0445b0126
--- /dev/null
+++ b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/DirectoryExistsViewModelTests.cs
@@ -0,0 +1,56 @@
+using System.Activities.DesignViewModels;
+using System.Threading.Tasks;
+using Moq;
+using UiPath.FTP.Activities.NetCore.ViewModels;
+using UiPath.FTP.Activities.Properties;
+using Xunit;
+
+namespace UiPath.FTP.Tests
+{
+ ///
+ /// Coverage for : property configuration
+ /// only, no rules, no dependencies, no data sources.
+ ///
+ public class DirectoryExistsViewModelTests
+ {
+ private static DirectoryExistsViewModel NewViewModel() =>
+ new DirectoryExistsViewModel(Mock.Of());
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresRemotePath()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.True(vm.RemotePath.IsRequired);
+ Assert.True(vm.RemotePath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.RemotePath.Category);
+ Assert.Equal(1, vm.RemotePath.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresContinueOnError()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.ContinueOnError.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.ContinueOnError.Category);
+ Assert.Equal(2, vm.ContinueOnError.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresExistsAsTrailingOutput()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.Exists.IsPrincipal);
+ Assert.Equal(Resources.Output, vm.Exists.Category);
+ Assert.Equal(3, vm.Exists.OrderIndex);
+ }
+ }
+}
diff --git a/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/DownloadFilesViewModelTests.cs b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/DownloadFilesViewModelTests.cs
new file mode 100644
index 000000000..5211edab7
--- /dev/null
+++ b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/DownloadFilesViewModelTests.cs
@@ -0,0 +1,73 @@
+using System.Activities.DesignViewModels;
+using System.Activities.ViewModels;
+using System.Threading.Tasks;
+using Moq;
+using UiPath.FTP.Activities.NetCore.ViewModels;
+using UiPath.FTP.Activities.Properties;
+using Xunit;
+
+namespace UiPath.FTP.Tests
+{
+ ///
+ /// Coverage for : property configuration
+ /// only, no rules, no dependencies, no data sources.
+ ///
+ public class DownloadFilesViewModelTests
+ {
+ private static DownloadFilesViewModel NewViewModel() =>
+ new DownloadFilesViewModel(Mock.Of());
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresRemotePathBeforeLocalPath()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.True(vm.RemotePath.IsRequired);
+ Assert.True(vm.RemotePath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.RemotePath.Category);
+ Assert.Equal(1, vm.RemotePath.OrderIndex);
+
+ Assert.True(vm.LocalPath.IsRequired);
+ Assert.True(vm.LocalPath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.LocalPath.Category);
+ Assert.Equal(2, vm.LocalPath.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresCreateRecursiveOverwriteAsToggles()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.Create.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.Create.Category);
+ Assert.Equal(ViewModelWidgetType.Toggle, vm.Create.Widget.Type);
+ Assert.Equal(3, vm.Create.OrderIndex);
+
+ Assert.False(vm.Recursive.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.Recursive.Category);
+ Assert.Equal(ViewModelWidgetType.Toggle, vm.Recursive.Widget.Type);
+ Assert.Equal(4, vm.Recursive.OrderIndex);
+
+ Assert.False(vm.Overwrite.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.Overwrite.Category);
+ Assert.Equal(ViewModelWidgetType.Toggle, vm.Overwrite.Widget.Type);
+ Assert.Equal(5, vm.Overwrite.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresContinueOnErrorLast()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.ContinueOnError.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.ContinueOnError.Category);
+ Assert.Equal(6, vm.ContinueOnError.OrderIndex);
+ }
+ }
+}
diff --git a/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/EnumerateObjectsViewModelTests.cs b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/EnumerateObjectsViewModelTests.cs
new file mode 100644
index 000000000..e178778ea
--- /dev/null
+++ b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/EnumerateObjectsViewModelTests.cs
@@ -0,0 +1,84 @@
+using System.Activities.DesignViewModels;
+using System.Activities.ViewModels;
+using System.Threading.Tasks;
+using Moq;
+using UiPath.FTP.Activities.NetCore.ViewModels;
+using UiPath.FTP.Activities.Properties;
+using Xunit;
+
+namespace UiPath.FTP.Tests
+{
+ ///
+ /// Coverage for : property configuration
+ /// and the Filter data source built in the constructor. No rules, no dependencies.
+ ///
+ public class EnumerateObjectsViewModelTests
+ {
+ private static EnumerateObjectsViewModel NewViewModel() =>
+ new EnumerateObjectsViewModel(Mock.Of());
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresRemotePath()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.True(vm.RemotePath.IsRequired);
+ Assert.True(vm.RemotePath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.RemotePath.Category);
+ Assert.Equal(1, vm.RemotePath.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresRecursiveAsToggle()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.Recursive.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.Recursive.Category);
+ Assert.Equal(ViewModelWidgetType.Toggle, vm.Recursive.Widget.Type);
+ Assert.Equal(2, vm.Recursive.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresFilterWithDataSource()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.Filter.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.Filter.Category);
+ Assert.Equal(ViewModelWidgetType.MultiSelect, vm.Filter.Widget.Type);
+ Assert.Equal(3, vm.Filter.OrderIndex);
+ Assert.NotNull(vm.Filter.DataSource);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresContinueOnError()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.ContinueOnError.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.ContinueOnError.Category);
+ Assert.Equal(4, vm.ContinueOnError.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresFilesAsTrailingOutput()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.Files.IsPrincipal);
+ Assert.Equal(Resources.Output, vm.Files.Category);
+ Assert.Equal(5, vm.Files.OrderIndex);
+ }
+ }
+}
diff --git a/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/FileExistsViewModelTests.cs b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/FileExistsViewModelTests.cs
new file mode 100644
index 000000000..ea737e6bf
--- /dev/null
+++ b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/FileExistsViewModelTests.cs
@@ -0,0 +1,56 @@
+using System.Activities.DesignViewModels;
+using System.Threading.Tasks;
+using Moq;
+using UiPath.FTP.Activities.NetCore.ViewModels;
+using UiPath.FTP.Activities.Properties;
+using Xunit;
+
+namespace UiPath.FTP.Tests
+{
+ ///
+ /// Coverage for : property configuration only,
+ /// no rules, no dependencies, no data sources.
+ ///
+ public class FileExistsViewModelTests
+ {
+ private static FileExistsViewModel NewViewModel() =>
+ new FileExistsViewModel(Mock.Of());
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresRemotePath()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.True(vm.RemotePath.IsRequired);
+ Assert.True(vm.RemotePath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.RemotePath.Category);
+ Assert.Equal(1, vm.RemotePath.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresContinueOnError()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.ContinueOnError.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.ContinueOnError.Category);
+ Assert.Equal(2, vm.ContinueOnError.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresExistsAsTrailingOutput()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.Exists.IsPrincipal);
+ Assert.Equal(Resources.Output, vm.Exists.Category);
+ Assert.Equal(3, vm.Exists.OrderIndex);
+ }
+ }
+}
diff --git a/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/MoveItemViewModelTests.cs b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/MoveItemViewModelTests.cs
new file mode 100644
index 000000000..f3886f4a7
--- /dev/null
+++ b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/MoveItemViewModelTests.cs
@@ -0,0 +1,63 @@
+using System.Activities.DesignViewModels;
+using System.Activities.ViewModels;
+using System.Threading.Tasks;
+using Moq;
+using UiPath.FTP.Activities.NetCore.ViewModels;
+using UiPath.FTP.Activities.Properties;
+using Xunit;
+
+namespace UiPath.FTP.Tests
+{
+ ///
+ /// Coverage for : property configuration only, no
+ /// rules, no dependencies, no data sources.
+ ///
+ public class MoveItemViewModelTests
+ {
+ private static MoveItemViewModel NewViewModel() =>
+ new MoveItemViewModel(Mock.Of());
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresRemotePathBeforeNewPath()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.True(vm.RemotePath.IsRequired);
+ Assert.True(vm.RemotePath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.RemotePath.Category);
+ Assert.Equal(1, vm.RemotePath.OrderIndex);
+
+ Assert.True(vm.NewPath.IsRequired);
+ Assert.True(vm.NewPath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.NewPath.Category);
+ Assert.Equal(2, vm.NewPath.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresOverwriteAsToggle()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.Overwrite.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.Overwrite.Category);
+ Assert.Equal(ViewModelWidgetType.Toggle, vm.Overwrite.Widget.Type);
+ Assert.Equal(3, vm.Overwrite.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresContinueOnErrorLast()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.ContinueOnError.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.ContinueOnError.Category);
+ Assert.Equal(4, vm.ContinueOnError.OrderIndex);
+ }
+ }
+}
diff --git a/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/UploadFilesViewModelTests.cs b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/UploadFilesViewModelTests.cs
new file mode 100644
index 000000000..dac2b42b6
--- /dev/null
+++ b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/UploadFilesViewModelTests.cs
@@ -0,0 +1,73 @@
+using System.Activities.DesignViewModels;
+using System.Activities.ViewModels;
+using System.Threading.Tasks;
+using Moq;
+using UiPath.FTP.Activities.NetCore.ViewModels;
+using UiPath.FTP.Activities.Properties;
+using Xunit;
+
+namespace UiPath.FTP.Tests
+{
+ ///
+ /// Coverage for : property configuration only,
+ /// no rules, no dependencies, no data sources.
+ ///
+ public class UploadFilesViewModelTests
+ {
+ private static UploadFilesViewModel NewViewModel() =>
+ new UploadFilesViewModel(Mock.Of());
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresLocalPathBeforeRemotePath()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.True(vm.LocalPath.IsRequired);
+ Assert.True(vm.LocalPath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.LocalPath.Category);
+ Assert.Equal(1, vm.LocalPath.OrderIndex);
+
+ Assert.True(vm.RemotePath.IsRequired);
+ Assert.True(vm.RemotePath.IsPrincipal);
+ Assert.Equal(Resources.Input, vm.RemotePath.Category);
+ Assert.Equal(2, vm.RemotePath.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresCreateRecursiveOverwriteAsToggles()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.Create.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.Create.Category);
+ Assert.Equal(ViewModelWidgetType.Toggle, vm.Create.Widget.Type);
+ Assert.Equal(3, vm.Create.OrderIndex);
+
+ Assert.False(vm.Recursive.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.Recursive.Category);
+ Assert.Equal(ViewModelWidgetType.Toggle, vm.Recursive.Widget.Type);
+ Assert.Equal(4, vm.Recursive.OrderIndex);
+
+ Assert.False(vm.Overwrite.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.Overwrite.Category);
+ Assert.Equal(ViewModelWidgetType.Toggle, vm.Overwrite.Widget.Type);
+ Assert.Equal(5, vm.Overwrite.OrderIndex);
+ }
+
+ [Fact]
+ public async Task InitializeAsync_ConfiguresContinueOnErrorLast()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.ContinueOnError.IsPrincipal);
+ Assert.Equal(Resources.Options, vm.ContinueOnError.Category);
+ Assert.Equal(6, vm.ContinueOnError.OrderIndex);
+ }
+ }
+}
diff --git a/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/WithFtpSessionValidationTests.cs b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/WithFtpSessionValidationTests.cs
new file mode 100644
index 000000000..86f22db72
--- /dev/null
+++ b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/WithFtpSessionValidationTests.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Activities;
+using System.Activities.Validation;
+using System.Linq;
+using UiPath.FTP.Activities;
+using Xunit;
+using FtpRes = UiPath.FTP.Activities.Properties.Resources;
+
+namespace UiPath.FTP.Tests
+{
+ ///
+ /// Coverage for the design-time validation errors emitted by
+ /// . The runtime already enforces these
+ /// constraints ( / ); these
+ /// tests pin the design-time surface so a refactor cannot quietly drop an error the studio
+ /// author depends on.
+ ///
+ public class WithFtpSessionValidationTests
+ {
+ // SFTP has no concept of anonymous login: SftpSession always requires Username plus a
+ // password/keyboard-interactive or private-key credential, and ExecuteAsync never
+ // populates Username when UseAnonymousLogin is on. That combination reaches OpenAsync
+ // and always throws NoValidAuthenticationMethod. CacheMetadata must catch it at design
+ // time instead of letting the workflow run and fail every time.
+ [Fact]
+ public void UseSftpWithAnonymousLogin_EmitsValidationError()
+ {
+ var activity = new WithFtpSession
+ {
+ Host = new InArgument("host"),
+ UseSftp = true,
+ UseAnonymousLogin = true,
+ };
+
+ ValidationError[] errors = ValidateAndGetErrors(activity);
+
+ Assert.Contains(errors, e =>
+ e.Message == FtpRes.AnonymousLoginNotSupportedOnSftp
+ && e.PropertyName == nameof(WithFtpSession.UseAnonymousLogin));
+ }
+
+ // The error must fire regardless of whether a password/certificate is also configured:
+ // Username is never populated when UseAnonymousLogin is on, so the combination is broken
+ // independently of what other authentication properties are set.
+ [Fact]
+ public void UseSftpWithAnonymousLogin_EmitsValidationError_EvenWithPasswordConfigured()
+ {
+ var activity = new WithFtpSession
+ {
+ Host = new InArgument("host"),
+ UseSftp = true,
+ UseAnonymousLogin = true,
+ Password = new InArgument("irrelevant"),
+ };
+
+ ValidationError[] errors = ValidateAndGetErrors(activity);
+
+ Assert.Contains(errors, e => e.Message == FtpRes.AnonymousLoginNotSupportedOnSftp);
+ }
+
+ // FTP/FTPS supports anonymous login (FtpSession skips setting credentials and relies on
+ // the underlying library's anonymous default), so the combination must not be flagged.
+ [Fact]
+ public void UseFtpWithAnonymousLogin_NoValidationError()
+ {
+ var activity = new WithFtpSession
+ {
+ Host = new InArgument("host"),
+ UseSftp = false,
+ UseAnonymousLogin = true,
+ };
+
+ ValidationError[] errors = ValidateAndGetErrors(activity);
+
+ Assert.DoesNotContain(errors, e => e.Message == FtpRes.AnonymousLoginNotSupportedOnSftp);
+ }
+
+ // SFTP with a real (non-anonymous) login must not be flagged by this check.
+ [Fact]
+ public void UseSftpWithoutAnonymousLogin_NoValidationError()
+ {
+ var activity = new WithFtpSession
+ {
+ Host = new InArgument("host"),
+ UseSftp = true,
+ UseAnonymousLogin = false,
+ Username = new InArgument("user"),
+ Password = new InArgument("pass"),
+ };
+
+ ValidationError[] errors = ValidateAndGetErrors(activity);
+
+ Assert.DoesNotContain(errors, e => e.Message == FtpRes.AnonymousLoginNotSupportedOnSftp);
+ }
+
+ // ActivityValidationServices.Validate runs CacheMetadata on the activity tree and
+ // collects every error/warning into the returned ValidationResults. Then we filter to
+ // errors only (isWarning=false entries).
+ private static ValidationError[] ValidateAndGetErrors(Activity activity) =>
+ ActivityValidationServices.Validate(activity).Errors.ToArray();
+ }
+}
diff --git a/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/WithFtpSessionViewModelTests.cs b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/WithFtpSessionViewModelTests.cs
new file mode 100644
index 000000000..0b7e550e8
--- /dev/null
+++ b/Activities/FTP/UiPath.FTP.Tests/ActivitiesTests/WithFtpSessionViewModelTests.cs
@@ -0,0 +1,244 @@
+using System.Activities.DesignViewModels;
+using System.Threading.Tasks;
+using Moq;
+using UiPath.FTP.Activities.NetCore.ViewModels;
+using UiPath.FTP.Enums;
+using Xunit;
+
+namespace UiPath.FTP.Tests
+{
+ ///
+ /// Coverage for the unified-canvas migration's additions to
+ /// : InitializeModel (the Configure* property setup
+ /// and menu-action wiring) and the reactive rule/dependency wiring
+ /// (InitializeRules/ManualRegisterDependencies + PasswordInputModeChanged_Action /
+ /// CertificatePasswordInputModeChanged_Action / ProxyPasswordInputModeChanged_Action /
+ /// FtpEncryptionModeChanged_Action / ProxyModeChanged_Action). None of this had a test before.
+ ///
+ /// "Initial state" and "restored values" drive the SDK's own InitializeAsync pipeline end
+ /// to end (InitializeModel, then InitializeRules/ManualRegisterDependencies, then ExecuteAll of
+ /// the runOnInit rules registered by the 2-arg Rule() overload) rather than only calling
+ /// the *_Changed_Action methods directly -- this is what actually proves the canvas ends up in
+ /// the right state, instead of assuming the SDK wiring works. Setting a DesignProperty's
+ /// .Value before calling InitializeAsync() simulates a persisted value a saved
+ /// workflow restores before the canvas renders it; the SDK does not overwrite an already-set
+ /// value when no matching persisted entry is passed in, so it survives into the render pass, and
+ /// ExecuteAll's runOnInit rules react to whatever value is present at that point -- confirmed
+ /// directly against the real pipeline, not simulated.
+ ///
+ ///
+ /// "Mode transitions" call the *_Changed_Action methods directly, mirroring the pattern used for
+ /// the Cryptography ViewModels' equivalent handlers (e.g. FormatChanged_Action): this is
+ /// what the SDK's dependency-triggered dispatch does for a single already-initialized property
+ /// change, without re-running the whole init pipeline.
+ ///
+ ///
+ public class WithFtpSessionViewModelTests
+ {
+ private static WithFtpSessionViewModel NewViewModel() =>
+ new WithFtpSessionViewModel(Mock.Of());
+
+ // --- Initial state: a brand-new activity, every switch at its schema default ---
+
+ [Fact]
+ public async Task InitialState_DefaultValues_HidesConditionalFields()
+ {
+ var vm = NewViewModel();
+
+ await vm.InitializeAsync();
+
+ // InitializeModel ran: the scope body is never a property row, and the primary
+ // connection field carries its configured metadata.
+ Assert.False(vm.Body.IsVisible);
+ Assert.True(vm.Host.IsRequired);
+ Assert.True(vm.Host.IsPrincipal);
+
+ Assert.True(vm.Password.IsVisible);
+ Assert.False(vm.SecurePassword.IsVisible);
+ Assert.True(vm.ClientCertificatePassword.IsVisible);
+ Assert.False(vm.ClientCertificateSecurePassword.IsVisible);
+ Assert.False(vm.SslProtocols.IsVisible); // FtpsMode == None
+ Assert.False(vm.ProxyServer.IsVisible); // ProxyType == None
+ Assert.False(vm.ProxyPort.IsVisible);
+ Assert.False(vm.ProxyUser.IsVisible);
+ Assert.False(vm.ProxyPassword.IsVisible);
+ Assert.False(vm.ProxySecurePassword.IsVisible);
+
+ // The input-mode switches back menu actions only; they are never rendered themselves.
+ Assert.False(vm.PasswordInputModeSwitch.IsVisible);
+ Assert.False(vm.CertificatePasswordInputModeSwitch.IsVisible);
+ Assert.False(vm.ProxyPasswordInputModeSwitch.IsVisible);
+ }
+
+ // --- Restored values: reopening a workflow where the switches were already set ---
+ //
+ // Setting .Value before InitializeAsync simulates the persisted state a saved workflow
+ // restores into the DesignProperty before the canvas renders it. If the rules didn't run
+ // against the restored value (or ran before InitializeModel's defaults were applied), these
+ // fields would render with the wrong visibility on every reopen.
+
+ [Fact]
+ public async Task RestoredValues_SecurePasswordMode_ShowsSecurePasswordNotPassword()
+ {
+ var vm = NewViewModel();
+ vm.PasswordInputModeSwitch.Value = PasswordInputMode.SecurePassword;
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.Password.IsVisible);
+ Assert.True(vm.SecurePassword.IsVisible);
+ }
+
+ [Fact]
+ public async Task RestoredValues_CertificateSecurePasswordMode_ShowsCertificateSecurePassword()
+ {
+ var vm = NewViewModel();
+ vm.CertificatePasswordInputModeSwitch.Value = PasswordInputMode.SecurePassword;
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.ClientCertificatePassword.IsVisible);
+ Assert.True(vm.ClientCertificateSecurePassword.IsVisible);
+ }
+
+ [Fact]
+ public async Task RestoredValues_FtpsModeExplicit_ShowsSslProtocols()
+ {
+ var vm = NewViewModel();
+ vm.FtpsMode.Value = FTP.FtpsMode.Explicit;
+
+ await vm.InitializeAsync();
+
+ Assert.True(vm.SslProtocols.IsVisible);
+ }
+
+ [Fact]
+ public async Task RestoredValues_ProxyTypeHttp_ShowsProxyFields()
+ {
+ var vm = NewViewModel();
+ vm.ProxyType.Value = FtpProxyType.Http;
+
+ await vm.InitializeAsync();
+
+ Assert.True(vm.ProxyServer.IsVisible);
+ Assert.True(vm.ProxyPort.IsVisible);
+ Assert.True(vm.ProxyUser.IsVisible);
+ Assert.True(vm.ProxyPassword.IsVisible); // default ProxyPasswordInputModeSwitch == Password
+ Assert.False(vm.ProxySecurePassword.IsVisible);
+ }
+
+ [Fact]
+ public async Task RestoredValues_ProxyTypeHttpWithSecurePassword_ShowsProxySecurePasswordNotProxyPassword()
+ {
+ var vm = NewViewModel();
+ vm.ProxyType.Value = FtpProxyType.Http;
+ vm.ProxyPasswordInputModeSwitch.Value = PasswordInputMode.SecurePassword;
+
+ await vm.InitializeAsync();
+
+ Assert.False(vm.ProxyPassword.IsVisible);
+ Assert.True(vm.ProxySecurePassword.IsVisible);
+ }
+
+ // --- Mode transitions: the user flips a switch after the canvas is already open ---
+
+ [Fact]
+ public void ModeTransition_PasswordInputModeSwitch_TogglesPasswordFields()
+ {
+ var vm = NewViewModel();
+
+ vm.PasswordInputModeSwitch.Value = PasswordInputMode.SecurePassword;
+ vm.PasswordInputModeChanged_Action();
+ Assert.False(vm.Password.IsVisible);
+ Assert.True(vm.SecurePassword.IsVisible);
+
+ vm.PasswordInputModeSwitch.Value = PasswordInputMode.Password;
+ vm.PasswordInputModeChanged_Action();
+ Assert.True(vm.Password.IsVisible);
+ Assert.False(vm.SecurePassword.IsVisible);
+ }
+
+ [Fact]
+ public void ModeTransition_CertificatePasswordInputModeSwitch_TogglesCertificatePasswordFields()
+ {
+ var vm = NewViewModel();
+
+ vm.CertificatePasswordInputModeSwitch.Value = PasswordInputMode.SecurePassword;
+ vm.CertificatePasswordInputModeChanged_Action();
+ Assert.False(vm.ClientCertificatePassword.IsVisible);
+ Assert.True(vm.ClientCertificateSecurePassword.IsVisible);
+
+ vm.CertificatePasswordInputModeSwitch.Value = PasswordInputMode.Password;
+ vm.CertificatePasswordInputModeChanged_Action();
+ Assert.True(vm.ClientCertificatePassword.IsVisible);
+ Assert.False(vm.ClientCertificateSecurePassword.IsVisible);
+ }
+
+ [Fact]
+ public void ModeTransition_FtpsModeToNone_HidesSslProtocols()
+ {
+ var vm = NewViewModel();
+ vm.FtpsMode.Value = FTP.FtpsMode.Explicit;
+ vm.FtpEncryptionModeChanged_Action();
+ Assert.True(vm.SslProtocols.IsVisible);
+
+ vm.FtpsMode.Value = FTP.FtpsMode.None;
+ vm.FtpEncryptionModeChanged_Action();
+ Assert.False(vm.SslProtocols.IsVisible);
+ }
+
+ [Fact]
+ public void ModeTransition_ProxyTypeOnThenOff_TogglesAllProxyFields()
+ {
+ var vm = NewViewModel();
+
+ vm.ProxyType.Value = FtpProxyType.Http;
+ vm.ProxyModeChanged_Action();
+ Assert.True(vm.ProxyServer.IsVisible);
+ Assert.True(vm.ProxyPort.IsVisible);
+ Assert.True(vm.ProxyUser.IsVisible);
+ Assert.True(vm.ProxyPassword.IsVisible);
+
+ vm.ProxyType.Value = FtpProxyType.None;
+ vm.ProxyModeChanged_Action();
+ Assert.False(vm.ProxyServer.IsVisible);
+ Assert.False(vm.ProxyPort.IsVisible);
+ Assert.False(vm.ProxyUser.IsVisible);
+ Assert.False(vm.ProxyPassword.IsVisible);
+ Assert.False(vm.ProxySecurePassword.IsVisible);
+ }
+
+ [Fact]
+ public void ModeTransition_ProxyPasswordInputModeSwitch_TogglesProxyPasswordFieldsWhileProxyOn()
+ {
+ var vm = NewViewModel();
+ vm.ProxyType.Value = FtpProxyType.Http;
+ vm.ProxyModeChanged_Action();
+
+ vm.ProxyPasswordInputModeSwitch.Value = PasswordInputMode.SecurePassword;
+ vm.ProxyPasswordInputModeChanged_Action();
+
+ Assert.False(vm.ProxyPassword.IsVisible);
+ Assert.True(vm.ProxySecurePassword.IsVisible);
+ }
+
+ // Pins a real asymmetry in the current implementation: ProxyPasswordInputModeChanged_Action
+ // does not consult ProxyType, unlike ProxyModeChanged_Action which recomputes all five proxy
+ // fields together. In the live canvas this switch's menu is only reachable from the
+ // ProxyPassword/ProxySecurePassword fields themselves, which are hidden while proxy is off,
+ // so the action should not fire in that state in practice -- but if it ever did, it would
+ // incorrectly reveal ProxyPassword even though the rest of the proxy section stays hidden.
+ [Fact]
+ public void ModeTransition_ProxyPasswordInputModeSwitch_IgnoresProxyOffState_KnownAsymmetry()
+ {
+ var vm = NewViewModel();
+ // ProxyType left at its default (None) -- proxy section is off.
+
+ vm.ProxyPasswordInputModeSwitch.Value = PasswordInputMode.Password;
+ vm.ProxyPasswordInputModeChanged_Action();
+
+ Assert.True(vm.ProxyPassword.IsVisible);
+ Assert.False(vm.ProxySecurePassword.IsVisible);
+ }
+ }
+}
diff --git a/Activities/FTP/UiPath.FTP.Tests/SessionsTests/SftpSessionTests.cs b/Activities/FTP/UiPath.FTP.Tests/SessionsTests/SftpSessionTests.cs
index ef69f1686..822f22801 100644
--- a/Activities/FTP/UiPath.FTP.Tests/SessionsTests/SftpSessionTests.cs
+++ b/Activities/FTP/UiPath.FTP.Tests/SessionsTests/SftpSessionTests.cs
@@ -4,6 +4,7 @@
using Renci.SshNet.Sftp;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
@@ -254,7 +255,7 @@ public async Task SFTP_DeleteAsync_DoesNotRecurseIntoSymbolicLink()
{
// A symlink that points at a directory must be unlinked, not walked into.
var deleted = new List();
- var link = FakeItem("/link", "link", isDirectory: true, deleted: deleted, isSymbolicLink: true);
+ var link = FakeItem("/link", "link", isDirectory: false, deleted: deleted, isSymbolicLink: true);
var insideLink = FakeItem("/link/should-not-touch.txt", "should-not-touch.txt", isDirectory: false, deleted: deleted);
using var session = new SftpSessionWithFakeTree(
@@ -333,8 +334,429 @@ public void SFTP_Delete_Sync_RemovesDirectoryContentsThenDirectory()
Assert.Equal(new[] { "/root/a.txt", "/root" }, deleted);
}
+ // --- Recursive listing (Enumerate Objects) ---
+
+ [Fact]
+ public async Task SFTP_EnumerateObjectsAsync_DoesNotRecurseIntoSymbolicLink()
+ {
+ // A link is reported with S_IFLNK, never S_IFDIR, so it never enters the recursion set --
+ // which is what keeps a link cycle from recursing forever.
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var aTxt = FakeItem("/root/a.txt", "a.txt", isDirectory: false);
+ var link = FakeItem("/root/link", "link", isDirectory: false, isSymbolicLink: true);
+ var hidden = FakeItem("/root/link/should-not-appear.txt", "should-not-appear.txt", isDirectory: false);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { aTxt, link },
+ ["/root/link"] = new[] { hidden },
+ });
+
+ var result = await ((IFtpSession)session).EnumerateObjectsAsync("/root", recursive: true, CancellationToken.None);
+
+ // The link itself is reported; what it points at is not enumerated.
+ Assert.Equal(
+ new[] { "/root/a.txt", "/root/link" },
+ result.Select(o => o.FullName).OrderBy(n => n, StringComparer.Ordinal));
+ Assert.Equal(1, session.ListDirectoryCallCount);
+ }
+
+ [Fact]
+ public async Task SFTP_EnumerateObjectsAsync_ReportsSymbolicLinkAsFile_KnownLimitation()
+ {
+ // Characterisation test, not an endorsement: FtpObjectType.Link is unreachable on the
+ // SFTP path (see SFTP_GetFtpObjectType_ClassifiesSymbolicLinkAsFile), so List Files and
+ // Folders' Link filter matches nothing and links arrive as File. Changing that alters
+ // output for shipped workflows, so it is left alone and pinned here instead.
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var link = FakeItem("/root/link", "link", isDirectory: false, isSymbolicLink: true);
+ var aTxt = FakeItem("/root/a.txt", "a.txt", isDirectory: false);
+ var sub = FakeItem("/root/sub", "sub", isDirectory: true);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { link, aTxt, sub },
+ });
+
+ var result = await ((IFtpSession)session).EnumerateObjectsAsync("/root", recursive: false, CancellationToken.None);
+
+ Assert.Equal(
+ new[]
+ {
+ ("/root/a.txt", FtpObjectType.File),
+ ("/root/link", FtpObjectType.File), // <-- would ideally be Link; see above
+ ("/root/sub", FtpObjectType.Directory),
+ },
+ result.Select(o => (o.FullName, o.Type)).OrderBy(t => t.FullName, StringComparer.Ordinal));
+ }
+
+ [Fact]
+ public async Task SFTP_EnumerateObjectsAsync_SkipsUnreadableSubdirectory_AndKeepsSiblings()
+ {
+ // The reported failure: a plain directory (not a link) that readdir returns but opendir
+ // rejects. One such entry must not discard the rest of the enumeration.
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var bad = FakeItem("/root/bad", "bad", isDirectory: true);
+ var good = FakeItem("/root/good", "good", isDirectory: true);
+ var bTxt = FakeItem("/root/good/b.txt", "b.txt", isDirectory: false);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { bad, good },
+ ["/root/good"] = new[] { bTxt },
+ },
+ listFailures: Failures(("/root/bad", () => new SftpPathNotFoundException("No such file"))));
+
+ var result = await ((IFtpSession)session).EnumerateObjectsAsync("/root", recursive: true, CancellationToken.None);
+
+ // The unreadable directory is still reported; only its contents are missing. Its sibling
+ // is walked normally.
+ Assert.Equal(
+ new[] { "/root/bad", "/root/good", "/root/good/b.txt" },
+ result.Select(o => o.FullName).OrderBy(n => n, StringComparer.Ordinal));
+ }
+
+ [Fact]
+ public async Task SFTP_EnumerateObjectsAsync_SkipsSubdirectoryOnPermissionDenied()
+ {
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var locked = FakeItem("/root/locked", "locked", isDirectory: true);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { locked },
+ },
+ listFailures: Failures(("/root/locked", () => new SftpPermissionDeniedException("Permission denied"))));
+
+ var result = await ((IFtpSession)session).EnumerateObjectsAsync("/root", recursive: true, CancellationToken.None);
+
+ Assert.Equal(new[] { "/root/locked" }, result.Select(o => o.FullName));
+ }
+
+ [Fact]
+ public async Task SFTP_EnumerateObjectsAsync_PropagatesConnectionFailureFromSubdirectory()
+ {
+ // A dropped connection is not an inaccessible directory and must not be swallowed,
+ // otherwise a half-finished listing would be returned as if it were complete.
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var sub = FakeItem("/root/sub", "sub", isDirectory: true);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { sub },
+ },
+ listFailures: Failures(("/root/sub", () => new SshConnectionException("dropped"))));
+
+ await Assert.ThrowsAsync(
+ () => ((IFtpSession)session).EnumerateObjectsAsync("/root", recursive: true, CancellationToken.None));
+ }
+
+ [Fact]
+ public async Task SFTP_EnumerateObjectsAsync_ThrowsWhenTheRequestedPathCannotBeListed()
+ {
+ // Leniency applies to sub-directories only -- the path the user asked for must still fail.
+ var root = FakeItem("/root", "root", isDirectory: true);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>(),
+ listFailures: Failures(("/root", () => new SftpPathNotFoundException("No such file"))));
+
+ await Assert.ThrowsAsync(
+ () => ((IFtpSession)session).EnumerateObjectsAsync("/root", recursive: true, CancellationToken.None));
+ }
+
+ [Fact]
+ public void SFTP_EnumerateObjects_Sync_SkipsUnreadableSubdirectory()
+ {
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var bad = FakeItem("/root/bad", "bad", isDirectory: true);
+ var aTxt = FakeItem("/root/a.txt", "a.txt", isDirectory: false);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { aTxt, bad },
+ },
+ listFailures: Failures(("/root/bad", () => new SftpPathNotFoundException("No such file"))));
+
+ var result = ((IFtpSession)session).EnumerateObjects("/root", recursive: true);
+
+ Assert.Equal(
+ new[] { "/root/a.txt", "/root/bad" },
+ result.Select(o => o.FullName).OrderBy(n => n, StringComparer.Ordinal));
+ }
+
+ [Fact]
+ public async Task SFTP_EnumerateObjectsAsync_RecursesIntoRealDirectories()
+ {
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var sub = FakeItem("/root/sub", "sub", isDirectory: true);
+ var deep = FakeItem("/root/sub/deep", "deep", isDirectory: true);
+ var bTxt = FakeItem("/root/sub/deep/b.txt", "b.txt", isDirectory: false);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { sub },
+ ["/root/sub"] = new[] { deep },
+ ["/root/sub/deep"] = new[] { bTxt },
+ });
+
+ var result = await ((IFtpSession)session).EnumerateObjectsAsync("/root", recursive: true, CancellationToken.None);
+
+ Assert.Equal(
+ new[] { "/root/sub", "/root/sub/deep", "/root/sub/deep/b.txt" },
+ result.Select(o => o.FullName).OrderBy(n => n, StringComparer.Ordinal));
+ }
+
+ [Fact]
+ public async Task SFTP_EnumerateObjectsAsync_SkipsDotAndDotDotEntries()
+ {
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var dot = FakeItem("/root/.", ".", isDirectory: true);
+ var dotDot = FakeItem("/root/..", "..", isDirectory: true);
+ var aTxt = FakeItem("/root/a.txt", "a.txt", isDirectory: false);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { dot, dotDot, aTxt },
+ });
+
+ var result = await ((IFtpSession)session).EnumerateObjectsAsync("/root", recursive: true, CancellationToken.None);
+
+ // Walking "." or ".." would loop; they are also not reported as results.
+ Assert.Equal(new[] { "/root/a.txt" }, result.Select(o => o.FullName));
+ Assert.Equal(1, session.ListDirectoryCallCount);
+ }
+
+ [Fact]
+ public async Task SFTP_EnumerateObjectsAsync_PassesRemotePathToClientVerbatim()
+ {
+ // Canonicalising a relative path is SSH.NET's job (GetCanonicalPath prepends the working
+ // directory); the walk must not pre-resolve it or mutate the shared session's directory.
+ var root = FakeItem("/home/user", "user", isDirectory: true);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["."] = root },
+ childrenByPath: new Dictionary>());
+
+ await ((IFtpSession)session).EnumerateObjectsAsync(".", recursive: false, CancellationToken.None);
+
+ Assert.Equal(new[] { "." }, session.GetCalls);
+ }
+
+ [Fact]
+ public void SFTP_EnumerateObjects_Sync_DoesNotRecurseIntoSymbolicLink()
+ {
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var link = FakeItem("/root/link", "link", isDirectory: false, isSymbolicLink: true);
+ var hidden = FakeItem("/root/link/should-not-appear.txt", "should-not-appear.txt", isDirectory: false);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { link },
+ ["/root/link"] = new[] { hidden },
+ });
+
+ var result = ((IFtpSession)session).EnumerateObjects("/root", recursive: true);
+
+ Assert.Equal(new[] { "/root/link" }, result.Select(o => o.FullName));
+ Assert.Equal(1, session.ListDirectoryCallCount);
+ }
+
+ // --- Object-type classification ---
+ //
+ // These pin CURRENT behaviour, including a known wart, so that changing it has to be a
+ // deliberate act rather than a tidy-up. See Extensions.GetFtpObjectType for the full story.
+
+ [Fact]
+ public void SFTP_GetFtpObjectType_ClassifiesSymbolicLinkAsFile()
+ {
+ // Not the intuitive answer, and not an accident. SSH.NET's IsRegularFile is a
+ // (mode & S_IFREG) == S_IFREG test and S_IFLNK contains S_IFREG, so every link is also a
+ // "regular file" and wins the first check. Reordering so links come first looks like an
+ // obvious cleanup but would make Download throw NotImplementedException on a symlinked
+ // file and File Exists answer false for one -- both work today.
+ Assert.Equal(FtpObjectType.File, FakeItem("/l", "l", isDirectory: false, isSymbolicLink: true).GetFtpObjectType());
+ Assert.Equal(FtpObjectType.File, FakeItem("/f", "f", isDirectory: false).GetFtpObjectType());
+ Assert.Equal(FtpObjectType.Directory, FakeItem("/d", "d", isDirectory: true).GetFtpObjectType());
+ }
+
+ // --- Recursive listing (Download Files) ---
+ //
+ // The download walk is a separate pair of overloads returning (localPath, remotePath) pairs.
+ // It shares the lenient descent with the enumeration walk, so it needs the same coverage. It
+ // is asserted directly rather than through IFtpSession.Download, which writes to the local
+ // file system and pulls bytes through the real SftpClient.
+ //
+ // Note the asymmetry with enumeration: only IsRegularFile entries become pairs, so a
+ // directory that is unreadable contributes nothing at all to the result.
+
+ [Fact]
+ public async Task SFTP_DownloadListingAsync_TransfersSymbolicLinkAsAFile_WithoutWalkingIt()
+ {
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var aTxt = FakeItem("/root/a.txt", "a.txt", isDirectory: false);
+ var link = FakeItem("/root/link", "link", isDirectory: false, isSymbolicLink: true);
+ var hidden = FakeItem("/root/link/should-not-appear.txt", "should-not-appear.txt", isDirectory: false);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { aTxt, link },
+ ["/root/link"] = new[] { hidden },
+ });
+
+ var listing = await session.GetRemoteListingAsync("/root", @"C:\local", recursive: true, CancellationToken.None);
+
+ // SSH.NET reports IsRegularFile == true for a symbolic link, so the link becomes a
+ // transfer entry of its own; opening it server-side follows it. It is never walked as a
+ // directory, so nothing underneath it is picked up.
+ Assert.Equal(new[] { "/root/a.txt", "/root/link" }, listing.Select(pair => pair.Item2));
+ Assert.Equal(1, session.ListDirectoryCallCount);
+ }
+
+ [Fact]
+ public async Task SFTP_DownloadListingAsync_SkipsUnreadableSubdirectory_AndKeepsSiblings()
+ {
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var bad = FakeItem("/root/bad", "bad", isDirectory: true);
+ var good = FakeItem("/root/good", "good", isDirectory: true);
+ var bTxt = FakeItem("/root/good/b.txt", "b.txt", isDirectory: false);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { bad, good },
+ ["/root/good"] = new[] { bTxt },
+ },
+ listFailures: Failures(("/root/bad", () => new SftpPathNotFoundException("No such file"))));
+
+ var listing = await session.GetRemoteListingAsync("/root", @"C:\local", recursive: true, CancellationToken.None);
+
+ // One unreadable directory must not cost the caller the rest of the download.
+ Assert.Equal(new[] { "/root/good/b.txt" }, listing.Select(pair => pair.Item2));
+ }
+
+ [Fact]
+ public async Task SFTP_DownloadListingAsync_PropagatesConnectionFailureFromSubdirectory()
+ {
+ // A dropped connection must not be reported as a completed download of a subset.
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var sub = FakeItem("/root/sub", "sub", isDirectory: true);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { sub },
+ },
+ listFailures: Failures(("/root/sub", () => new SshConnectionException("dropped"))));
+
+ await Assert.ThrowsAsync(
+ () => session.GetRemoteListingAsync("/root", @"C:\local", recursive: true, CancellationToken.None));
+ }
+
+ [Fact]
+ public async Task SFTP_DownloadListingAsync_MapsNestedFilesToNestedLocalPaths()
+ {
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var aTxt = FakeItem("/root/a.txt", "a.txt", isDirectory: false);
+ var sub = FakeItem("/root/sub", "sub", isDirectory: true);
+ var bTxt = FakeItem("/root/sub/b.txt", "b.txt", isDirectory: false);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { aTxt, sub },
+ ["/root/sub"] = new[] { bTxt },
+ });
+
+ var listing = await session.GetRemoteListingAsync("/root", "local", recursive: true, CancellationToken.None);
+
+ // The remote tree shape is reproduced under the local path, rooted at the directory name.
+ Assert.Equal(
+ new[]
+ {
+ (Path.Combine("local", "root", "a.txt"), "/root/a.txt"),
+ (Path.Combine("local", "root", "sub", "b.txt"), "/root/sub/b.txt"),
+ },
+ listing.Select(pair => (pair.Item1, pair.Item2)));
+ }
+
+ [Fact]
+ public void SFTP_DownloadListing_Sync_TransfersSymbolicLinkAndSkipsUnreadableSubdirectory()
+ {
+ var root = FakeItem("/root", "root", isDirectory: true);
+ var aTxt = FakeItem("/root/a.txt", "a.txt", isDirectory: false);
+ var link = FakeItem("/root/link", "link", isDirectory: false, isSymbolicLink: true);
+ var bad = FakeItem("/root/bad", "bad", isDirectory: true);
+
+ using var session = new SftpSessionWithFakeTree(
+ CreateTestConfig(),
+ itemsByPath: new Dictionary { ["/root"] = root },
+ childrenByPath: new Dictionary>
+ {
+ ["/root"] = new[] { aTxt, link, bad },
+ ["/root/link"] = new[] { FakeItem("/root/link/hidden.txt", "hidden.txt", isDirectory: false) },
+ },
+ listFailures: Failures(("/root/bad", () => new SftpPathNotFoundException("No such file"))));
+
+ var listing = session.GetRemoteListing("/root", @"C:\local", recursive: true);
+
+ // The link transfers as a file (see the async twin); the unreadable directory contributes
+ // nothing but does not fail the walk.
+ Assert.Equal(new[] { "/root/a.txt", "/root/link" }, listing.Select(pair => pair.Item2));
+ }
+
// --- Helpers ---
+ ///
+ /// Builds the listFailures map for : paths whose
+ /// listing throws, modelling a server that returns an entry from readdir and then
+ /// refuses opendir on it.
+ ///
+ private static IReadOnlyDictionary> Failures(
+ params (string Path, Func Throws)[] failures)
+ {
+ return failures.ToDictionary(f => f.Path, f => f.Throws);
+ }
+
///
/// Subclass of that overrides
/// so tests can inject arbitrary behaviour without needing to override the sealed
@@ -363,48 +785,102 @@ private sealed class SftpSessionWithFakeTree : SftpSession
{
private readonly IReadOnlyDictionary _itemsByPath;
private readonly IReadOnlyDictionary> _childrenByPath;
+ private readonly IReadOnlyDictionary> _listFailures;
public SftpSessionWithFakeTree(
FtpConfiguration config,
IReadOnlyDictionary itemsByPath,
- IReadOnlyDictionary> childrenByPath)
+ IReadOnlyDictionary> childrenByPath,
+ IReadOnlyDictionary> listFailures = null)
: base(config)
{
_itemsByPath = itemsByPath;
_childrenByPath = childrenByPath;
+ _listFailures = listFailures ?? new Dictionary>();
}
public int ListDirectoryCallCount { get; private set; }
- protected internal override ISftpFile ClientGet(string path) => _itemsByPath[path];
+ /// Paths passed to ClientGet, in call order.
+ public List GetCalls { get; } = new List();
+
+ protected internal override ISftpFile ClientGet(string path)
+ {
+ GetCalls.Add(path);
+ return _itemsByPath[path];
+ }
protected internal override IEnumerable ClientListDirectory(string path)
{
ListDirectoryCallCount++;
+
+ // Models a path the server lists in its parent but then refuses to open.
+ if (_listFailures.TryGetValue(path, out var failure))
+ {
+ throw failure();
+ }
+
return _childrenByPath.TryGetValue(path, out var children)
? children
: Enumerable.Empty();
}
+
+ protected internal override Task> ClientListDirectoryAsync(string path)
+ => Task.FromResult(ClientListDirectory(path));
}
///
/// Builds a mocked whose Delete records its full name into
/// , so tests can assert both that an item was deleted and the order
/// in which deletions happened.
+ ///
+ /// The three type flags are derived from one kind rather than set independently, so that a
+ /// fake cannot describe an entry SSH.NET could never produce. They are wired to match SSH.NET
+ /// 2024.1.0 exactly, verified against real SftpFileAttributes built from POSIX mode
+ /// words:
+ ///
+ ///
+ /// directory S_IFDIR|0755 -> IsDirectory, not link, not regular file
+ /// symlink S_IFLNK|0777 -> not directory, IsSymbolicLink, and IsRegularFile
+ /// regular S_IFREG|0644 -> not directory, not link, IsRegularFile
+ ///
+ ///
+ /// The surprise is the middle row: SSH.NET tests (mode & S_IFREG) == S_IFREG, and
+ /// S_IFLNK (0xA000) contains S_IFREG (0x8000), so every link is
+ /// also a "regular file". An earlier version of this helper set
+ /// IsRegularFile = !isDirectory && !isSymbolicLink, the opposite, and allowed
+ /// isDirectory: true, isSymbolicLink: true -- a combination no conformant server can
+ /// send, since S_IFDIR and S_IFLNK are distinct values of the same type field.
+ /// Tests written against that fake asserted behaviour the product never exhibits.
+ ///
///
private static ISftpFile FakeItem(
string fullName,
string name,
bool isDirectory,
- List deleted,
+ List deleted = null,
bool isSymbolicLink = false)
{
+ if (isDirectory && isSymbolicLink)
+ {
+ throw new ArgumentException(
+ "A directory and a symbolic link are distinct values of the mode word's type field; " +
+ "no SFTP server can report an entry as both. Pass isSymbolicLink on its own -- " +
+ "a link to a directory is still just a link on the wire.");
+ }
+
var mock = new Mock();
mock.SetupGet(f => f.FullName).Returns(fullName);
mock.SetupGet(f => f.Name).Returns(name);
mock.SetupGet(f => f.IsDirectory).Returns(isDirectory);
mock.SetupGet(f => f.IsSymbolicLink).Returns(isSymbolicLink);
- mock.Setup(f => f.Delete()).Callback(() => deleted.Add(fullName));
+ mock.SetupGet(f => f.IsRegularFile).Returns(!isDirectory);
+
+ if (deleted != null)
+ {
+ mock.Setup(f => f.Delete()).Callback(() => deleted.Add(fullName));
+ }
+
return mock.Object;
}
diff --git a/Activities/FTP/UiPath.FTP.Tests/UiPath.FTP.Tests.csproj b/Activities/FTP/UiPath.FTP.Tests/UiPath.FTP.Tests.csproj
index aa69a6e00..06c5984a3 100644
--- a/Activities/FTP/UiPath.FTP.Tests/UiPath.FTP.Tests.csproj
+++ b/Activities/FTP/UiPath.FTP.Tests/UiPath.FTP.Tests.csproj
@@ -24,6 +24,14 @@
+
+
diff --git a/Activities/FTP/UiPath.FTP/Extensions.cs b/Activities/FTP/UiPath.FTP/Extensions.cs
index 595f4591b..00c4a7ed2 100644
--- a/Activities/FTP/UiPath.FTP/Extensions.cs
+++ b/Activities/FTP/UiPath.FTP/Extensions.cs
@@ -56,6 +56,44 @@ public static UiPath.FTP.FtpObjectType ToFtpObjectType(this FluentFTP.FtpObjectT
}
}
+ ///
+ /// Classifies an SFTP entry. Feeds both — the branch
+ /// Download, File Exists and Directory Exists dispatch on — and the
+ /// that List Files and Folders reports and filters on.
+ ///
+ /// A symbolic link is classified , never
+ /// , and that must not be "fixed" casually. SSH.NET tests
+ /// the mode word with (mode & S_IFREG) == S_IFREG rather than against the type
+ /// mask, and S_IFLNK (0xA000) contains S_IFREG (0x8000), so
+ /// is already for every link and
+ /// wins the first test below. Consequences, all verified against SSH.NET 2024.1.0:
+ ///
+ ///
+ ///
+ /// is unreachable on the SFTP path, so List Files and Folders'
+ /// Link filter matches nothing. The FTP/FTPS path does not share this — FluentFTP has a
+ /// real Link object type — so the two protocols disagree.
+ ///
+ ///
+ /// Testing first would fix that, but it also changes
+ /// what the dispatch callers see: Download would throw
+ /// on a symlinked file and File Exists would
+ /// answer for one, both of which work today because opening a link
+ /// server-side follows it. Separating the two uses is possible, but it still changes
+ /// for existing workflows.
+ ///
+ ///
+ /// A link whose target is a directory is likewise classified as a file. Resolving that needs a
+ /// stat of the target, and SSH.NET's Get, GetAttributes and Exists
+ /// are all lstat.
+ ///
+ ///
+ ///
+ /// All three are pre-existing and deliberately left in place: correcting them is a breaking
+ /// change to output that shipped workflows already consume. Pinned by
+ /// SFTP_GetFtpObjectType_* in SftpSessionTests.
+ ///
+ ///
public static UiPath.FTP.FtpObjectType GetFtpObjectType(this ISftpFile sftpFile)
{
if (sftpFile == null)
@@ -71,10 +109,8 @@ public static UiPath.FTP.FtpObjectType GetFtpObjectType(this ISftpFile sftpFile)
{
return UiPath.FTP.FtpObjectType.Directory;
}
- if (sftpFile.IsSymbolicLink)
- {
- return UiPath.FTP.FtpObjectType.Link;
- }
+ // No IsSymbolicLink branch: IsSymbolicLink implies IsRegularFile (see the remarks above),
+ // so it could never be reached. Its absence is not an oversight.
return UiPath.FTP.FtpObjectType.Other;
}
diff --git a/Activities/FTP/UiPath.FTP/SftpSession.cs b/Activities/FTP/UiPath.FTP/SftpSession.cs
index 0bfbbc529..541d07ed0 100644
--- a/Activities/FTP/UiPath.FTP/SftpSession.cs
+++ b/Activities/FTP/UiPath.FTP/SftpSession.cs
@@ -28,8 +28,35 @@ public SftpSession(FtpConfiguration ftpConfiguration)
throw new ArgumentNullException(nameof(ftpConfiguration));
}
- ConnectionInfo connectionInfo = null;
+ List authMethods = BuildAuthenticationMethods(ftpConfiguration);
+ //Throw an error if we ended up with no authentication method
+ if (authMethods.Count == 0)
+ {
+ throw new ArgumentNullException(Resources.NoValidAuthenticationMethod);
+ }
+
+ ConnectionInfo connectionInfo = BuildConnectionInfo(ftpConfiguration, authMethods);
+
+ TimeSpan? timeoutSpan = ftpConfiguration.Timeout != null
+ ? TimeSpan.FromMilliseconds(ftpConfiguration.Timeout.Value)
+ : null;
+
+ if (timeoutSpan.HasValue)
+ {
+ connectionInfo.Timeout = timeoutSpan.Value;
+ }
+
+ _sftpClient = new SftpClient(connectionInfo);
+
+ if (timeoutSpan.HasValue)
+ {
+ _sftpClient.OperationTimeout = timeoutSpan.Value;
+ }
+ }
+
+ private static List BuildAuthenticationMethods(FtpConfiguration ftpConfiguration)
+ {
var authMethods = new List();
//Add password authentication method if password is provided
@@ -53,63 +80,44 @@ public SftpSession(FtpConfiguration ftpConfiguration)
// a redundant failed auth round-trip on certificate-only connections.
if (!String.IsNullOrEmpty(ftpConfiguration.Password))
{
- var kbiMethod = new KeyboardInteractiveAuthenticationMethod(ftpConfiguration.Username);
- var kbiPassword = ftpConfiguration.Password;
- kbiMethod.AuthenticationPrompt += (sender, e) =>
- {
- foreach (var prompt in e.Prompts)
- {
- if (!prompt.IsEchoed)
- {
- prompt.Response = kbiPassword;
- }
- }
- };
- authMethods.Add(kbiMethod);
+ authMethods.Add(BuildKeyboardInteractiveAuthenticationMethod(ftpConfiguration.Username, ftpConfiguration.Password));
}
- //Throw an error if we ended up with no authentication method
- if (authMethods.Count == 0)
- {
- throw new ArgumentNullException(Resources.NoValidAuthenticationMethod);
- }
- if (ftpConfiguration.ProxyType == FtpProxyType.None)
+ return authMethods;
+ }
+
+ private static KeyboardInteractiveAuthenticationMethod BuildKeyboardInteractiveAuthenticationMethod(string username, string password)
+ {
+ var kbiMethod = new KeyboardInteractiveAuthenticationMethod(username);
+ kbiMethod.AuthenticationPrompt += (sender, e) =>
{
- if (ftpConfiguration.Port == null)
- {
- connectionInfo = new ConnectionInfo(ftpConfiguration.Host, ftpConfiguration.Username, authMethods.ToArray());
- }
- else
+ foreach (var prompt in e.Prompts)
{
- connectionInfo = new ConnectionInfo(ftpConfiguration.Host, ftpConfiguration.Port.Value, ftpConfiguration.Username, authMethods.ToArray());
+ if (!prompt.IsEchoed)
+ {
+ prompt.Response = password;
+ }
}
- }
- else
- {
- int proxyPort = (ftpConfiguration.ProxyPort == null) ? DefaultProxyPort : ftpConfiguration.ProxyPort.Value;
- int ftpPort = (ftpConfiguration.Port == null) ? DefaultFtpPort : ftpConfiguration.Port.Value;
-
- connectionInfo = new ConnectionInfo(ftpConfiguration.Host, ftpPort, ftpConfiguration.Username, ftpConfiguration.ProxyType.ToMaster(),ftpConfiguration.ProxyServer, proxyPort,ftpConfiguration.ProxyUsername,ftpConfiguration.ProxyPassword, authMethods.ToArray());
- }
-
- TimeSpan? timeoutSpan = ftpConfiguration.Timeout != null
- ? TimeSpan.FromMilliseconds(ftpConfiguration.Timeout.Value)
- : null;
+ };
+ return kbiMethod;
+ }
- if (timeoutSpan.HasValue)
+ private static ConnectionInfo BuildConnectionInfo(FtpConfiguration ftpConfiguration, List authMethods)
+ {
+ if (ftpConfiguration.ProxyType == FtpProxyType.None)
{
- connectionInfo.Timeout = timeoutSpan.Value;
+ return ftpConfiguration.Port == null
+ ? new ConnectionInfo(ftpConfiguration.Host, ftpConfiguration.Username, authMethods.ToArray())
+ : new ConnectionInfo(ftpConfiguration.Host, ftpConfiguration.Port.Value, ftpConfiguration.Username, authMethods.ToArray());
}
- _sftpClient = new SftpClient(connectionInfo);
+ int proxyPort = (ftpConfiguration.ProxyPort == null) ? DefaultProxyPort : ftpConfiguration.ProxyPort.Value;
+ int ftpPort = (ftpConfiguration.Port == null) ? DefaultFtpPort : ftpConfiguration.Port.Value;
- if (timeoutSpan.HasValue)
- {
- _sftpClient.OperationTimeout = timeoutSpan.Value;
- }
+ return new ConnectionInfo(ftpConfiguration.Host, ftpPort, ftpConfiguration.Username, ftpConfiguration.ProxyType.ToMaster(), ftpConfiguration.ProxyServer, proxyPort, ftpConfiguration.ProxyUsername, ftpConfiguration.ProxyPassword, authMethods.ToArray());
}
- private IEnumerable> GetLocalListing(string localPath, string remotePath, bool recursive)
+ private static IEnumerable> GetLocalListing(string localPath, string remotePath, bool recursive)
{
if (string.IsNullOrWhiteSpace(localPath))
{
@@ -140,7 +148,12 @@ private IEnumerable> GetLocalListing(string localPath, str
return listing;
}
- private IEnumerable> GetRemoteListing(string remotePath, string localPath, bool recursive)
+ ///
+ /// internal rather than private so the download walk can be exercised directly
+ /// by the tests: the only public entry point, , writes to
+ /// the local file system and pulls bytes through the real .
+ ///
+ internal IEnumerable> GetRemoteListing(string remotePath, string localPath, bool recursive)
{
if (string.IsNullOrWhiteSpace(remotePath))
{
@@ -151,13 +164,14 @@ private IEnumerable> GetRemoteListing(string remotePath, s
throw new ArgumentNullException(nameof(localPath));
}
- string initialWorkingDirectory = _sftpClient.WorkingDirectory;
- _sftpClient.ChangeDirectory(remotePath);
+ return GetRemoteListing(ClientGet(remotePath), localPath, recursive);
+ }
+ private IEnumerable> GetRemoteListing(ISftpFile directory, string localPath, bool recursive)
+ {
List> listing = new List>();
- ISftpFile currentDirectory = _sftpClient.Get(_sftpClient.WorkingDirectory);
- IEnumerable items = _sftpClient.ListDirectory(currentDirectory.FullName);
- string nextLocalPath = Path.Combine(localPath, currentDirectory.Name);
+ List items = ClientListDirectory(directory.FullName).ToList();
+ string nextLocalPath = Path.Combine(localPath, directory.Name);
foreach (var file in items.Where(i => i.IsRegularFile))
{
@@ -166,14 +180,12 @@ private IEnumerable> GetRemoteListing(string remotePath, s
if (recursive)
{
- foreach (var directory in items.Where(i => i.IsDirectory && i.Name != "." && i.Name != ".."))
+ foreach (var child in items.Where(IsWalkableDirectory))
{
- listing.AddRange(GetRemoteListing(directory.FullName, nextLocalPath, recursive));
+ listing.AddRange(Descend(child, () => GetRemoteListing(child, nextLocalPath, recursive)));
}
}
- _sftpClient.ChangeDirectory(initialWorkingDirectory);
-
return listing;
}
@@ -184,30 +196,34 @@ private IEnumerable GetRemoteListing(string remotePath, bool recu
throw new ArgumentNullException(nameof(remotePath));
}
- string initialWorkingDirectory = _sftpClient.WorkingDirectory;
- _sftpClient.ChangeDirectory(remotePath);
-
- var currentDirectory = _sftpClient.Get(_sftpClient.WorkingDirectory);
+ return GetRemoteListing(ClientGet(remotePath), recursive);
+ }
+ private IEnumerable GetRemoteListing(ISftpFile directory, bool recursive)
+ {
List listing = new List();
- var items = _sftpClient.ListDirectory(currentDirectory.FullName).Where(sf => sf.Name != "." && sf.Name != "..");
+ List items = ClientListDirectory(directory.FullName)
+ .Where(sf => sf.Name != "." && sf.Name != "..")
+ .ToList();
listing.AddRange(items.Select(sf => sf.ToFtpObjectInfo()));
if (recursive)
{
- foreach (var directory in items.Where(i => i.IsDirectory))
+ foreach (var child in items.Where(IsWalkableDirectory))
{
- listing.AddRange(GetRemoteListing(directory.FullName, recursive));
+ listing.AddRange(Descend(child, () => GetRemoteListing(child, recursive)));
}
}
- _sftpClient.ChangeDirectory(initialWorkingDirectory);
-
return listing;
}
- private async Task>> GetRemoteListingAsync(string remotePath, string localPath, bool recursive, CancellationToken cancellationToken)
+ ///
+ /// internal for the same reason as its synchronous counterpart
+ /// .
+ ///
+ internal async Task>> GetRemoteListingAsync(string remotePath, string localPath, bool recursive, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(remotePath))
{
@@ -220,13 +236,16 @@ private async Task>> GetRemoteListingAsync(str
cancellationToken.ThrowIfCancellationRequested();
- string initialWorkingDirectory = _sftpClient.WorkingDirectory;
- _sftpClient.ChangeDirectory(remotePath);
+ return await GetRemoteListingAsync(ClientGet(remotePath), localPath, recursive, cancellationToken);
+ }
+
+ private async Task>> GetRemoteListingAsync(ISftpFile directory, string localPath, bool recursive, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
List> listing = new List>();
- var currentDirectory = _sftpClient.Get(_sftpClient.WorkingDirectory);
- var items = await Task.Factory.FromAsync(_sftpClient.BeginListDirectory(currentDirectory.FullName, null, null), _sftpClient.EndListDirectory);
- string nextLocalPath = Path.Combine(localPath, currentDirectory.Name);
+ List items = (await ClientListDirectoryAsync(directory.FullName)).ToList();
+ string nextLocalPath = Path.Combine(localPath, directory.Name);
foreach (var file in items.Where(i => i.IsRegularFile))
{
@@ -235,14 +254,12 @@ private async Task>> GetRemoteListingAsync(str
if (recursive)
{
- foreach (var directory in items.Where(i => i.IsDirectory && i.Name != "." && i.Name != ".."))
+ foreach (var child in items.Where(IsWalkableDirectory))
{
- listing.AddRange(await GetRemoteListingAsync(directory.FullName, nextLocalPath, recursive, cancellationToken));
+ listing.AddRange(await DescendAsync(child, () => GetRemoteListingAsync(child, nextLocalPath, recursive, cancellationToken)));
}
}
- _sftpClient.ChangeDirectory(initialWorkingDirectory);
-
return listing;
}
@@ -253,27 +270,30 @@ private async Task> GetRemoteListingAsync(string remo
throw new ArgumentNullException(nameof(remotePath));
}
- string initialWorkingDirectory = _sftpClient.WorkingDirectory;
- _sftpClient.ChangeDirectory(remotePath);
+ cancellationToken.ThrowIfCancellationRequested();
- var currentDirectory = _sftpClient.Get(_sftpClient.WorkingDirectory);
+ return await GetRemoteListingAsync(ClientGet(remotePath), recursive, cancellationToken);
+ }
+
+ private async Task> GetRemoteListingAsync(ISftpFile directory, bool recursive, CancellationToken cancellationToken)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
List listing = new List();
- var items = await Task.Factory.FromAsync(_sftpClient.BeginListDirectory(currentDirectory.FullName, null, null), _sftpClient.EndListDirectory);
- items = items.Where(sf => sf.Name != "." && sf.Name != "..");
+ List items = (await ClientListDirectoryAsync(directory.FullName))
+ .Where(sf => sf.Name != "." && sf.Name != "..")
+ .ToList();
listing.AddRange(items.Select(sf => sf.ToFtpObjectInfo()));
if (recursive)
{
- foreach (var directory in items.Where(i => i.IsDirectory))
+ foreach (var child in items.Where(IsWalkableDirectory))
{
- listing.AddRange(await GetRemoteListingAsync(directory.FullName, recursive, cancellationToken));
+ listing.AddRange(await DescendAsync(child, () => GetRemoteListingAsync(child, recursive, cancellationToken)));
}
}
- _sftpClient.ChangeDirectory(initialWorkingDirectory);
-
return listing;
}
@@ -341,6 +361,95 @@ private async Task> GetMissingDirectoriesAsync(string remote
///
protected internal virtual IEnumerable ClientListDirectory(string path) => _sftpClient.ListDirectory(path);
+ ///
+ /// Asynchronous counterpart of , kept separate so the
+ /// async listing walks retain SSH.NET's true async APM call rather than blocking a thread
+ /// pool thread. Also a protected internal virtual seam for testability.
+ ///
+ protected internal virtual Task> ClientListDirectoryAsync(string path)
+ => Task.Factory.FromAsync(_sftpClient.BeginListDirectory(path, null, null), _sftpClient.EndListDirectory);
+
+ ///
+ /// Decides whether a listing entry should be descended into during a recursive enumeration:
+ /// a directory that is not . or .., which would loop forever.
+ ///
+ /// There is deliberately no symbolic-link check here. Listing entries come from readdir,
+ /// whose attributes are lstat-like, and /
+ /// both read the type field of the same mode word —
+ /// S_IFDIR and S_IFLNK are distinct values of it, so a link is never reported as
+ /// a directory and can never reach this predicate as one. Links are therefore not followed,
+ /// which is the intended behaviour (a link cycle would recurse until the uncatchable
+ /// , and a link can point outside the requested subtree),
+ /// but it needs no code: an explicit !IsSymbolicLink clause was dead and has been
+ /// removed. still carries one;
+ /// it is equally inert and left alone as pre-existing.
+ ///
+ ///
+ private static bool IsWalkableDirectory(ISftpFile item)
+ => item.IsDirectory && item.Name != "." && item.Name != "..";
+
+ ///
+ /// Runs a recursive-walk step over , yielding nothing instead of
+ /// failing the whole walk when the server will not open that one sub-directory.
+ /// A server can return an entry from readdir and then refuse opendir on it —
+ /// a dangling symbolic link it does not flag as a link, a stale mount point, an entry removed
+ /// by someone else mid-walk, or a name that does not survive the path encoding round-trip.
+ /// Losing an entire enumeration over one such entry is worse than skipping it, so the
+ /// sub-directory is still reported in the results and only its contents are omitted, with the
+ /// offending path traced. Mirrors .
+ /// Only sub-directories are treated this way: the caller's own remote path is resolved by
+ /// before any walk starts, so a bad remote path still throws.
+ ///
+ private static IEnumerable Descend(ISftpFile directory, Func> walk)
+ {
+ try
+ {
+ return walk();
+ }
+ catch (SshException ex) when (IsUnreadablePath(ex))
+ {
+ TraceSkippedDirectory(directory, ex);
+ return Enumerable.Empty();
+ }
+ }
+
+ ///
+ /// Asynchronous counterpart of .
+ ///
+ private static async Task> DescendAsync(ISftpFile directory, Func>> walk)
+ {
+ try
+ {
+ return await walk();
+ }
+ catch (SshException ex) when (IsUnreadablePath(ex))
+ {
+ TraceSkippedDirectory(directory, ex);
+ return Enumerable.Empty();
+ }
+ }
+
+ ///
+ /// True for the SFTP failures that mean "this path cannot be read", as opposed to a broken
+ /// connection or a timeout. Typed subclasses such as and
+ /// deliberately fall through so that real transport
+ /// failures are never mistaken for an inaccessible directory — the same distinction
+ /// makes, including the bare
+ /// (SSH_FX_FAILURE) that some servers return in place of a typed error.
+ ///
+ private static bool IsUnreadablePath(SshException ex)
+ => ex is SftpPathNotFoundException
+ || ex is SftpPermissionDeniedException
+ || ex.GetType() == typeof(SshException);
+
+ private static void TraceSkippedDirectory(ISftpFile directory, SshException ex)
+ {
+ Trace.TraceWarning(
+ "SftpSession: skipping sub-directory '{0}' during recursive enumeration; the server would not open it: {1}",
+ directory.FullName,
+ ex.Message);
+ }
+
///
/// Recursively deletes the SFTP object at .
/// The SFTP protocol's RMDIR (issued by for directories) only
@@ -527,39 +636,41 @@ void IFtpSession.Download(string remotePath, string localPath, bool overwrite, b
UiPath.FTP.FtpObjectType objectType = ((IFtpSession)this).GetObjectType(remotePath);
if (objectType == UiPath.FTP.FtpObjectType.Directory)
{
- IEnumerable> listing = GetRemoteListing(remotePath, localPath, recursive);
+ DownloadDirectory(remotePath, localPath, recursive);
+ return;
+ }
- foreach (Tuple file in listing)
- {
- string directoryPath = Path.GetDirectoryName(file.Item1);
- if (!Directory.Exists(directoryPath))
- {
- Directory.CreateDirectory(directoryPath);
- }
+ if (objectType != UiPath.FTP.FtpObjectType.File)
+ {
+ throw new NotImplementedException(Resources.UnsupportedObjectTypeException);
+ }
- using (Stream fileStream = File.OpenWrite(file.Item1))
- {
- _sftpClient.DownloadFile(file.Item2, fileStream);
- }
- }
+ if (File.Exists(localPath) && !overwrite)
+ {
+ throw new IOException(Resources.FileExistsException);
}
- else
+
+ using (Stream fileStream = File.OpenWrite(localPath))
{
- if (objectType == UiPath.FTP.FtpObjectType.File)
- {
- if (File.Exists(localPath) && !overwrite)
- {
- throw new IOException(Resources.FileExistsException);
- }
+ _sftpClient.DownloadFile(remotePath, fileStream);
+ }
+ }
- using (Stream fileStream = File.OpenWrite(localPath))
- {
- _sftpClient.DownloadFile(remotePath, fileStream);
- }
+ private void DownloadDirectory(string remotePath, string localPath, bool recursive)
+ {
+ IEnumerable> listing = GetRemoteListing(remotePath, localPath, recursive);
+
+ foreach (Tuple file in listing)
+ {
+ string directoryPath = Path.GetDirectoryName(file.Item1);
+ if (!Directory.Exists(directoryPath))
+ {
+ Directory.CreateDirectory(directoryPath);
}
- else
+
+ using (Stream fileStream = File.OpenWrite(file.Item1))
{
- throw new NotImplementedException(Resources.UnsupportedObjectTypeException);
+ _sftpClient.DownloadFile(file.Item2, fileStream);
}
}
}
@@ -578,53 +689,53 @@ async Task IFtpSession.DownloadAsync(string remotePath, string localPath, bool o
UiPath.FTP.FtpObjectType objectType = ((IFtpSession)this).GetObjectType(remotePath);
if (objectType == UiPath.FTP.FtpObjectType.Directory)
{
- IEnumerable> listing = await GetRemoteListingAsync(remotePath, localPath, recursive, cancellationToken);
+ await DownloadDirectoryAsync(remotePath, localPath, overwrite, recursive, cancellationToken);
+ return;
+ }
- foreach (Tuple file in listing)
- {
- if (File.Exists(file.Item1) && !overwrite)
- {
- continue;
- }
+ if (objectType != UiPath.FTP.FtpObjectType.File)
+ {
+ throw new NotImplementedException(Resources.UnsupportedObjectTypeException);
+ }
- cancellationToken.ThrowIfCancellationRequested();
+ if (File.Exists(localPath))
+ {
+ if (!overwrite)
+ {
+ throw new IOException(Resources.FileExistsException);
+ }
- string directoryPath = Path.GetDirectoryName(file.Item1);
- if (!Directory.Exists(directoryPath))
- {
- Directory.CreateDirectory(directoryPath);
- }
+ File.Delete(localPath);
+ }
- using (Stream fileStream = File.OpenWrite(file.Item1))
- {
- await Task.Factory.FromAsync(_sftpClient.BeginDownloadFile(file.Item2, fileStream), _sftpClient.EndDownloadFile);
- }
- }
+ using (Stream fileStream = File.OpenWrite(localPath))
+ {
+ await Task.Factory.FromAsync(_sftpClient.BeginDownloadFile(remotePath, fileStream), _sftpClient.EndDownloadFile);
}
- else
+ }
+
+ private async Task DownloadDirectoryAsync(string remotePath, string localPath, bool overwrite, bool recursive, CancellationToken cancellationToken)
+ {
+ IEnumerable> listing = await GetRemoteListingAsync(remotePath, localPath, recursive, cancellationToken);
+
+ foreach (Tuple file in listing)
{
- if (objectType == UiPath.FTP.FtpObjectType.File)
+ if (File.Exists(file.Item1) && !overwrite)
{
- if (File.Exists(localPath))
- {
- if (overwrite)
- {
- File.Delete(localPath);
- }
- else
- {
- throw new IOException(Resources.FileExistsException);
- }
- }
+ continue;
+ }
- using (Stream fileStream = File.OpenWrite(localPath))
- {
- await Task.Factory.FromAsync(_sftpClient.BeginDownloadFile(remotePath, fileStream), _sftpClient.EndDownloadFile);
- }
+ cancellationToken.ThrowIfCancellationRequested();
+
+ string directoryPath = Path.GetDirectoryName(file.Item1);
+ if (!Directory.Exists(directoryPath))
+ {
+ Directory.CreateDirectory(directoryPath);
}
- else
+
+ using (Stream fileStream = File.OpenWrite(file.Item1))
{
- throw new NotImplementedException(Resources.UnsupportedObjectTypeException);
+ await Task.Factory.FromAsync(_sftpClient.BeginDownloadFile(file.Item2, fileStream), _sftpClient.EndDownloadFile);
}
}
}
@@ -722,38 +833,54 @@ void IFtpSession.Move(string remotePath, string newPath, bool overwrite)
throw new IOException(string.Format(Resources.PathNotFoundException, remotePath));
}
- if (SafeExists(newPath) && _sftpClient.Get(newPath).IsRegularFile && !overwrite)
+ if (SafeExists(newPath) && _sftpClient.Get(newPath).IsRegularFile && !overwrite)
{
throw new IOException(Resources.FileExistsException);
}
var file = _sftpClient.Get(remotePath);
- if(SafeExists(newPath) && file.IsRegularFile)
+ if (SafeExists(newPath) && file.IsRegularFile)
{
- var movePath = _sftpClient.Get(newPath);
- if (movePath.IsDirectory)
- {
- var newFP = string.Format("{0}/{1}", movePath.FullName, file.Name);
- if (SafeExists(newFP) && _sftpClient.Get(newFP).IsRegularFile)
- {
- if (overwrite)
- _sftpClient.DeleteFile(newFP);
- else
- throw new IOException(Resources.FileExistsException);
- }
- }
- else
- {
- if (overwrite)
- movePath.Delete();
- else
- throw new IOException(Resources.FileExistsException);
- }
+ ResolveFileMoveConflict(file, newPath, overwrite);
}
+
file.MoveTo(newPath);
}
+ private void ResolveFileMoveConflict(ISftpFile file, string newPath, bool overwrite)
+ {
+ var movePath = _sftpClient.Get(newPath);
+ if (movePath.IsDirectory)
+ {
+ ResolveDirectoryDestinationConflict(file, movePath, overwrite);
+ return;
+ }
+
+ if (!overwrite)
+ {
+ throw new IOException(Resources.FileExistsException);
+ }
+
+ movePath.Delete();
+ }
+
+ private void ResolveDirectoryDestinationConflict(ISftpFile file, ISftpFile movePath, bool overwrite)
+ {
+ string newFilePath = string.Format("{0}/{1}", movePath.FullName, file.Name);
+ if (!SafeExists(newFilePath) || !_sftpClient.Get(newFilePath).IsRegularFile)
+ {
+ return;
+ }
+
+ if (!overwrite)
+ {
+ throw new IOException(Resources.FileExistsException);
+ }
+
+ _sftpClient.DeleteFile(newFilePath);
+ }
+
void IFtpSession.Upload(string localPath, string remotePath, bool overwrite, bool recursive)
{
if (string.IsNullOrWhiteSpace(localPath))
@@ -767,39 +894,41 @@ void IFtpSession.Upload(string localPath, string remotePath, bool overwrite, boo
if (Directory.Exists(localPath))
{
- IEnumerable> listing = GetLocalListing(localPath, remotePath, recursive);
+ UploadDirectory(localPath, remotePath, overwrite, recursive);
+ return;
+ }
- foreach (Tuple pair in listing)
- {
- string directoryPath = FtpConfiguration.GetDirectoryPath(pair.Item2);
- if (!SafeExists(directoryPath))
- {
- _sftpClient.CreateDirectory(directoryPath);
- }
+ if (!File.Exists(localPath))
+ {
+ throw new ArgumentException(string.Format(Resources.PathNotFoundException, localPath), nameof(localPath));
+ }
- using (Stream fileStream = File.OpenRead(pair.Item1))
- {
- _sftpClient.UploadFile(fileStream, pair.Item2, overwrite);
- }
- }
+ if (SafeExists(remotePath) && !overwrite)
+ {
+ throw new IOException(Resources.FileExistsException);
}
- else
+
+ using (Stream fileStream = File.OpenRead(localPath))
{
- if (File.Exists(localPath))
- {
- if (SafeExists(remotePath) && !overwrite)
- {
- throw new IOException(Resources.FileExistsException);
- }
+ _sftpClient.UploadFile(fileStream, remotePath, overwrite);
+ }
+ }
- using (Stream fileStream = File.OpenRead(localPath))
- {
- _sftpClient.UploadFile(fileStream, remotePath, overwrite);
- }
+ private void UploadDirectory(string localPath, string remotePath, bool overwrite, bool recursive)
+ {
+ IEnumerable> listing = GetLocalListing(localPath, remotePath, recursive);
+
+ foreach (Tuple pair in listing)
+ {
+ string directoryPath = FtpConfiguration.GetDirectoryPath(pair.Item2);
+ if (!SafeExists(directoryPath))
+ {
+ _sftpClient.CreateDirectory(directoryPath);
}
- else
+
+ using (Stream fileStream = File.OpenRead(pair.Item1))
{
- throw new ArgumentException(string.Format(Resources.PathNotFoundException, localPath), nameof(localPath));
+ _sftpClient.UploadFile(fileStream, pair.Item2, overwrite);
}
}
}
@@ -817,41 +946,43 @@ async Task IFtpSession.UploadAsync(string localPath, string remotePath, bool ove
if (Directory.Exists(localPath))
{
- IEnumerable> listing = GetLocalListing(localPath, remotePath, recursive);
+ await UploadDirectoryAsync(localPath, remotePath, overwrite, recursive, cancellationToken);
+ return;
+ }
- foreach (Tuple pair in listing)
- {
- cancellationToken.ThrowIfCancellationRequested();
+ if (!File.Exists(localPath))
+ {
+ throw new ArgumentException(string.Format(Resources.PathNotFoundException, localPath), nameof(localPath));
+ }
- string directoryPath = FtpConfiguration.GetDirectoryPath(pair.Item2);
- if (!SafeExists(directoryPath))
- {
- _sftpClient.CreateDirectory(directoryPath);
- }
+ if (SafeExists(remotePath) && !overwrite)
+ {
+ throw new IOException(Resources.FileExistsException);
+ }
- using (Stream fileStream = File.OpenRead(pair.Item1))
- {
- await Task.Factory.FromAsync(_sftpClient.BeginUploadFile(fileStream, pair.Item2, overwrite, null, null), _sftpClient.EndUploadFile);
- }
- }
+ using (Stream fileStream = File.OpenRead(localPath))
+ {
+ await Task.Factory.FromAsync(_sftpClient.BeginUploadFile(fileStream, remotePath, overwrite, null, null), _sftpClient.EndUploadFile);
}
- else
+ }
+
+ private async Task UploadDirectoryAsync(string localPath, string remotePath, bool overwrite, bool recursive, CancellationToken cancellationToken)
+ {
+ IEnumerable> listing = GetLocalListing(localPath, remotePath, recursive);
+
+ foreach (Tuple pair in listing)
{
- if (File.Exists(localPath))
- {
- if (SafeExists(remotePath) && !overwrite)
- {
- throw new IOException(Resources.FileExistsException);
- }
+ cancellationToken.ThrowIfCancellationRequested();
- using (Stream fileStream = File.OpenRead(localPath))
- {
- await Task.Factory.FromAsync(_sftpClient.BeginUploadFile(fileStream, remotePath, overwrite, null, null), _sftpClient.EndUploadFile);
- }
+ string directoryPath = FtpConfiguration.GetDirectoryPath(pair.Item2);
+ if (!SafeExists(directoryPath))
+ {
+ _sftpClient.CreateDirectory(directoryPath);
}
- else
+
+ using (Stream fileStream = File.OpenRead(pair.Item1))
{
- throw new ArgumentException(string.Format(Resources.PathNotFoundException, localPath), nameof(localPath));
+ await Task.Factory.FromAsync(_sftpClient.BeginUploadFile(fileStream, pair.Item2, overwrite, null, null), _sftpClient.EndUploadFile);
}
}
}
@@ -884,12 +1015,11 @@ protected virtual void Dispose(bool disposing)
// }
// This code added to correctly implement the disposable pattern.
- void IDisposable.Dispose()
+ public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
- // TODO: uncomment the following line if the finalizer is overridden above.
- // GC.SuppressFinalize(this);
+ GC.SuppressFinalize(this);
}
#endregion
}