Merge branch 'feature/files' of https://github.com/ONLYOFFICE/AppServer into feature/files
This commit is contained in:
commit
478e03530b
@ -29,6 +29,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using ASC.Common.Logging;
|
using ASC.Common.Logging;
|
||||||
using ASC.Common.Notify.Patterns;
|
using ASC.Common.Notify.Patterns;
|
||||||
using ASC.Notify.Channels;
|
using ASC.Notify.Channels;
|
||||||
@ -36,6 +37,7 @@ using ASC.Notify.Cron;
|
|||||||
using ASC.Notify.Messages;
|
using ASC.Notify.Messages;
|
||||||
using ASC.Notify.Patterns;
|
using ASC.Notify.Patterns;
|
||||||
using ASC.Notify.Recipients;
|
using ASC.Notify.Recipients;
|
||||||
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
@ -360,9 +362,10 @@ namespace ASC.Notify.Engine
|
|||||||
PrepareRequestFillPatterns(request);
|
PrepareRequestFillPatterns(request);
|
||||||
PrepareRequestFillTags(request);
|
PrepareRequestFillTags(request);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
responses.Add(new SendResponse(request.NotifyAction, null, request.Recipient, SendResult.Impossible));
|
responses.Add(new SendResponse(request.NotifyAction, null, request.Recipient, SendResult.Impossible));
|
||||||
|
log.Error("Prepare", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.SenderNames != null && request.SenderNames.Length > 0)
|
if (request.SenderNames != null && request.SenderNames.Length > 0)
|
||||||
|
@ -26,10 +26,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\products\ASC.Files\Server\ASC.Files.csproj" />
|
<ProjectReference Include="..\..\..\products\ASC.Files\Server\ASC.Files.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\web\ASC.Web.Core\ASC.Web.Core.csproj" />
|
||||||
<ProjectReference Include="..\..\ASC.Common\ASC.Common.csproj" />
|
<ProjectReference Include="..\..\ASC.Common\ASC.Common.csproj" />
|
||||||
<ProjectReference Include="..\..\ASC.Core.Common\ASC.Core.Common.csproj" />
|
<ProjectReference Include="..\..\ASC.Core.Common\ASC.Core.Common.csproj" />
|
||||||
<ProjectReference Include="..\..\ASC.Data.Storage\ASC.Data.Storage.csproj" />
|
<ProjectReference Include="..\..\ASC.Data.Storage\ASC.Data.Storage.csproj" />
|
||||||
<ProjectReference Include="..\ASC.Notify\ASC.Notify.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Protobuf Include="protos\BackupProgress.proto" />
|
<Protobuf Include="protos\BackupProgress.proto" />
|
||||||
|
@ -24,32 +24,37 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using ASC.Common;
|
using ASC.Common;
|
||||||
using ASC.Common.Utils;
|
using ASC.Common.Utils;
|
||||||
|
using ASC.Web.Studio.Core.Notify;
|
||||||
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
namespace ASC.Data.Backup.Service
|
namespace ASC.Data.Backup.Service
|
||||||
{
|
{
|
||||||
internal class BackupServiceLauncher : IHostedService
|
internal class BackupServiceLauncher : IHostedService
|
||||||
{
|
{
|
||||||
|
public IServiceProvider ServiceProvider { get; }
|
||||||
private BackupCleanerService CleanerService { get; set; }
|
private BackupCleanerService CleanerService { get; set; }
|
||||||
private BackupSchedulerService SchedulerService { get; set; }
|
private BackupSchedulerService SchedulerService { get; set; }
|
||||||
private BackupWorker BackupWorker { get; set; }
|
private BackupWorker BackupWorker { get; set; }
|
||||||
private IConfiguration Configuration { get; set; }
|
private IConfiguration Configuration { get; set; }
|
||||||
public BackupServiceNotifier BackupServiceNotifier { get; }
|
public BackupServiceNotifier BackupServiceNotifier { get; }
|
||||||
|
|
||||||
public BackupServiceLauncher(
|
public BackupServiceLauncher(
|
||||||
|
IServiceProvider serviceProvider,
|
||||||
BackupCleanerService cleanerService,
|
BackupCleanerService cleanerService,
|
||||||
BackupSchedulerService schedulerService,
|
BackupSchedulerService schedulerService,
|
||||||
BackupWorker backupWorker,
|
BackupWorker backupWorker,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
BackupServiceNotifier backupServiceNotifier)
|
BackupServiceNotifier backupServiceNotifier)
|
||||||
{
|
{
|
||||||
|
ServiceProvider = serviceProvider;
|
||||||
CleanerService = cleanerService;
|
CleanerService = cleanerService;
|
||||||
SchedulerService = schedulerService;
|
SchedulerService = schedulerService;
|
||||||
BackupWorker = backupWorker;
|
BackupWorker = backupWorker;
|
||||||
@ -58,7 +63,9 @@ namespace ASC.Data.Backup.Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
NotifyConfiguration.Configure(ServiceProvider);
|
||||||
|
|
||||||
var settings = Configuration.GetSetting<BackupSettings>("backup");
|
var settings = Configuration.GetSetting<BackupSettings>("backup");
|
||||||
|
|
||||||
BackupWorker.Start(settings);
|
BackupWorker.Start(settings);
|
||||||
|
@ -25,79 +25,143 @@
|
|||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
using ASC.Common;
|
using ASC.Common;
|
||||||
using ASC.Common.Logging;
|
using ASC.Core;
|
||||||
using Microsoft.Extensions.Options;
|
using ASC.Core.Tenants;
|
||||||
using ASC.Notify;
|
using ASC.Core.Users;
|
||||||
|
using ASC.Notify.Model;
|
||||||
|
using ASC.Notify.Patterns;
|
||||||
|
using ASC.Notify.Recipients;
|
||||||
|
using ASC.Web.Core.Users;
|
||||||
|
using ASC.Web.Studio.Core.Notify;
|
||||||
|
using ASC.Web.Studio.Utility;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace ASC.Data.Backup
|
namespace ASC.Data.Backup
|
||||||
{
|
{
|
||||||
public class NotifyHelper
|
public class NotifyHelper
|
||||||
{
|
{
|
||||||
private const string NotifyService = "ASC.Web.Studio.Core.Notify.StudioNotifyService, ASC.Web.Studio";
|
public IServiceProvider ServiceProvider { get; }
|
||||||
private const string MethodTransferStart = "MigrationPortalStart";
|
|
||||||
private const string MethodTransferCompleted = "MigrationPortalSuccess";
|
public NotifyHelper(IServiceProvider serviceProvider)
|
||||||
private const string MethodTransferError = "MigrationPortalError";
|
{
|
||||||
private const string MethodBackupCompleted = "SendMsgBackupCompleted";
|
ServiceProvider = serviceProvider;
|
||||||
private const string MethodRestoreStarted = "SendMsgRestoreStarted";
|
}
|
||||||
private const string MethodRestoreCompleted = "SendMsgRestoreCompleted";
|
|
||||||
private readonly ILog log;
|
|
||||||
private readonly NotifyService notifyService;
|
|
||||||
|
|
||||||
public NotifyHelper(IOptionsMonitor<ILog> options, NotifyService notifyService)
|
public void SendAboutTransferStart(Tenant tenant, string targetRegion, bool notifyUsers)
|
||||||
{
|
{
|
||||||
this.notifyService = notifyService;
|
MigrationNotify(tenant, Actions.MigrationPortalStart, targetRegion, string.Empty, notifyUsers);
|
||||||
log = options.CurrentValue;
|
|
||||||
}
|
|
||||||
public void SendAboutTransferStart(int tenantId, string targetRegion, bool notifyUsers)
|
|
||||||
{
|
|
||||||
SendNotification(MethodTransferStart, tenantId, targetRegion, notifyUsers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAboutTransferComplete(int tenantId, string targetRegion, string targetAddress, bool notifyOnlyOwner)
|
public void SendAboutTransferComplete(Tenant tenant, string targetRegion, string targetAddress, bool notifyOnlyOwner)
|
||||||
{
|
{
|
||||||
SendNotification(MethodTransferCompleted, tenantId, targetRegion, targetAddress, !notifyOnlyOwner);
|
MigrationNotify(tenant, Actions.MigrationPortalSuccess, targetRegion, targetAddress, !notifyOnlyOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAboutTransferError(int tenantId, string targetRegion, string resultAddress, bool notifyOnlyOwner)
|
public void SendAboutTransferError(Tenant tenant, string targetRegion, string resultAddress, bool notifyOnlyOwner)
|
||||||
{
|
{
|
||||||
SendNotification(MethodTransferError, tenantId, targetRegion, resultAddress, !notifyOnlyOwner);
|
MigrationNotify(tenant, !string.IsNullOrEmpty(targetRegion) ? Actions.MigrationPortalError : Actions.MigrationPortalServerFailure, targetRegion, resultAddress, !notifyOnlyOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAboutBackupCompleted(int tenantId, Guid userId, string link)
|
public void SendAboutBackupCompleted(Guid userId)
|
||||||
{
|
{
|
||||||
SendNotification(MethodBackupCompleted, tenantId, userId, link);
|
using var scope = ServiceProvider.CreateScope();
|
||||||
|
var userManager = scope.ServiceProvider.GetService<UserManager>();
|
||||||
|
var studioNotifyHelper = scope.ServiceProvider.GetService<StudioNotifyHelper>();
|
||||||
|
var notifySource = scope.ServiceProvider.GetService<StudioNotifySource>();
|
||||||
|
var displayUserSettingsHelper = scope.ServiceProvider.GetService<DisplayUserSettingsHelper>();
|
||||||
|
var client = WorkContext.NotifyContext.NotifyService.RegisterClient(notifySource, scope);
|
||||||
|
|
||||||
|
client.SendNoticeToAsync(
|
||||||
|
Actions.BackupCreated,
|
||||||
|
new[] { studioNotifyHelper.ToRecipient(userId) },
|
||||||
|
new[] { StudioNotifyService.EMailSenderName },
|
||||||
|
new TagValue(Tags.OwnerName, userManager.GetUsers(userId).DisplayUserName(displayUserSettingsHelper)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAboutRestoreStarted(int tenantId, bool notifyAllUsers)
|
public void SendAboutRestoreStarted(Tenant tenant, bool notifyAllUsers)
|
||||||
{
|
{
|
||||||
SendNotification(MethodRestoreStarted, tenantId, notifyAllUsers);
|
using var scope = ServiceProvider.CreateScope();
|
||||||
|
var userManager = scope.ServiceProvider.GetService<UserManager>();
|
||||||
|
var studioNotifyHelper = scope.ServiceProvider.GetService<StudioNotifyHelper>();
|
||||||
|
var notifySource = scope.ServiceProvider.GetService<StudioNotifySource>();
|
||||||
|
var displayUserSettingsHelper = scope.ServiceProvider.GetService<DisplayUserSettingsHelper>();
|
||||||
|
var client = WorkContext.NotifyContext.NotifyService.RegisterClient(notifySource, scope);
|
||||||
|
|
||||||
|
var owner = userManager.GetUsers(tenant.OwnerId);
|
||||||
|
var users =
|
||||||
|
notifyAllUsers
|
||||||
|
? studioNotifyHelper.RecipientFromEmail(userManager.GetUsers(EmployeeStatus.Active).Where(r => r.ActivationStatus == EmployeeActivationStatus.Activated).Select(u => u.Email).ToList(), false)
|
||||||
|
: owner.ActivationStatus == EmployeeActivationStatus.Activated ? studioNotifyHelper.RecipientFromEmail(owner.Email, false) : new IDirectRecipient[0];
|
||||||
|
|
||||||
|
client.SendNoticeToAsync(
|
||||||
|
Actions.RestoreStarted,
|
||||||
|
users,
|
||||||
|
new[] { StudioNotifyService.EMailSenderName });
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAboutRestoreCompleted(int tenantId, bool notifyAllUsers)
|
public void SendAboutRestoreCompleted(Tenant tenant, bool notifyAllUsers)
|
||||||
{
|
{
|
||||||
SendNotification(MethodRestoreCompleted, tenantId, notifyAllUsers);
|
using var scope = ServiceProvider.CreateScope();
|
||||||
}
|
var userManager = scope.ServiceProvider.GetService<UserManager>();
|
||||||
|
var studioNotifyHelper = scope.ServiceProvider.GetService<StudioNotifyHelper>();
|
||||||
private void SendNotification(string method, int tenantId, params object[] args)
|
var notifySource = scope.ServiceProvider.GetService<StudioNotifySource>();
|
||||||
{
|
var displayUserSettingsHelper = scope.ServiceProvider.GetService<DisplayUserSettingsHelper>();
|
||||||
try
|
var client = WorkContext.NotifyContext.NotifyService.RegisterClient(notifySource, scope);
|
||||||
{
|
|
||||||
notifyService.InvokeSendMethod(NotifyService, method, tenantId, args);
|
var owner = userManager.GetUsers(tenant.OwnerId);
|
||||||
}
|
|
||||||
catch (Exception error)
|
var users =
|
||||||
{
|
notifyAllUsers
|
||||||
log.Warn("Error while sending notification", error);
|
? userManager.GetUsers(EmployeeStatus.Active).Select(u => studioNotifyHelper.ToRecipient(u.ID)).ToArray()
|
||||||
}
|
: new[] { studioNotifyHelper.ToRecipient(owner.ID) };
|
||||||
|
|
||||||
|
client.SendNoticeToAsync(
|
||||||
|
Actions.RestoreCompleted,
|
||||||
|
users,
|
||||||
|
new[] { StudioNotifyService.EMailSenderName },
|
||||||
|
new TagValue(Tags.OwnerName, owner.DisplayUserName(displayUserSettingsHelper)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigrationNotify(Tenant tenant, INotifyAction action, string region, string url, bool notify)
|
||||||
|
{
|
||||||
|
using var scope = ServiceProvider.CreateScope();
|
||||||
|
var userManager = scope.ServiceProvider.GetService<UserManager>();
|
||||||
|
var studioNotifyHelper = scope.ServiceProvider.GetService<StudioNotifyHelper>();
|
||||||
|
var notifySource = scope.ServiceProvider.GetService<StudioNotifySource>();
|
||||||
|
var client = WorkContext.NotifyContext.NotifyService.RegisterClient(notifySource, scope);
|
||||||
|
|
||||||
|
var users = userManager.GetUsers()
|
||||||
|
.Where(u => notify ? u.ActivationStatus.HasFlag(EmployeeActivationStatus.Activated) : u.IsOwner(tenant))
|
||||||
|
.Select(u => studioNotifyHelper.ToRecipient(u.ID))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (users.Any())
|
||||||
|
{
|
||||||
|
client.SendNoticeToAsync(
|
||||||
|
action,
|
||||||
|
users,
|
||||||
|
new[] { StudioNotifyService.EMailSenderName },
|
||||||
|
new TagValue(Tags.RegionName, TransferResourceHelper.GetRegionDescription(region)),
|
||||||
|
new TagValue(Tags.PortalUrl, url));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static class NotifyHelperExtension
|
public static class NotifyHelperExtension
|
||||||
{
|
{
|
||||||
public static DIHelper AddNotifyHelperService(this DIHelper services)
|
public static DIHelper AddNotifyHelperService(this DIHelper services)
|
||||||
{
|
{
|
||||||
services.TryAddScoped<NotifyHelper>();
|
services.TryAddSingleton<NotifyHelper>();
|
||||||
return services
|
|
||||||
.AddNotifyService();
|
return services
|
||||||
|
.AddNotifyConfiguration()
|
||||||
|
.AddStudioNotifySourceService()
|
||||||
|
.AddUserManagerService()
|
||||||
|
.AddStudioNotifyHelperService()
|
||||||
|
.AddDisplayUserSettingsService();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -376,7 +376,8 @@ namespace ASC.Data.Backup.Service
|
|||||||
var backupWorker = scope.ServiceProvider.GetService<BackupWorker>();
|
var backupWorker = scope.ServiceProvider.GetService<BackupWorker>();
|
||||||
|
|
||||||
|
|
||||||
var backupName = string.Format("{0}_{1:yyyy-MM-dd_HH-mm-ss}.{2}", tenantManager.GetTenant(TenantId).TenantAlias, DateTime.UtcNow, ArchiveFormat);
|
var tenant = tenantManager.GetTenant(TenantId);
|
||||||
|
var backupName = string.Format("{0}_{1:yyyy-MM-dd_HH-mm-ss}.{2}", tenant.TenantAlias, DateTime.UtcNow, ArchiveFormat);
|
||||||
var tempFile = Path.Combine(TempFolder, backupName);
|
var tempFile = Path.Combine(TempFolder, backupName);
|
||||||
var storagePath = tempFile;
|
var storagePath = tempFile;
|
||||||
try
|
try
|
||||||
@ -424,10 +425,11 @@ namespace ASC.Data.Backup.Service
|
|||||||
|
|
||||||
if (UserId != Guid.Empty && !IsScheduled)
|
if (UserId != Guid.Empty && !IsScheduled)
|
||||||
{
|
{
|
||||||
notifyHelper.SendAboutBackupCompleted(TenantId, UserId, Link);
|
notifyHelper.SendAboutBackupCompleted(UserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
IsCompleted = true;
|
IsCompleted = true;
|
||||||
|
backupWorker.PublishProgress(this);
|
||||||
}
|
}
|
||||||
catch (Exception error)
|
catch (Exception error)
|
||||||
{
|
{
|
||||||
@ -437,6 +439,15 @@ namespace ASC.Data.Backup.Service
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
backupWorker.PublishProgress(this);
|
||||||
|
}
|
||||||
|
catch (Exception error)
|
||||||
|
{
|
||||||
|
Log.Error("publish", error);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!(storagePath == tempFile && StorageType == BackupStorageType.Local))
|
if (!(storagePath == tempFile && StorageType == BackupStorageType.Local))
|
||||||
@ -503,13 +514,13 @@ namespace ASC.Data.Backup.Service
|
|||||||
var tempFile = PathHelper.GetTempFileName(TempFolder);
|
var tempFile = PathHelper.GetTempFileName(TempFolder);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
notifyHelper.SendAboutRestoreStarted(TenantId, Notify);
|
tenant = tenantManager.GetTenant(TenantId);
|
||||||
|
notifyHelper.SendAboutRestoreStarted(tenant, Notify);
|
||||||
var storage = backupStorageFactory.GetBackupStorage(StorageType, TenantId, StorageParams);
|
var storage = backupStorageFactory.GetBackupStorage(StorageType, TenantId, StorageParams);
|
||||||
storage.Download(StoragePath, tempFile);
|
storage.Download(StoragePath, tempFile);
|
||||||
|
|
||||||
Percentage = 10;
|
Percentage = 10;
|
||||||
|
|
||||||
tenant = tenantManager.GetTenant(TenantId);
|
|
||||||
tenant.SetStatus(TenantStatus.Restoring);
|
tenant.SetStatus(TenantStatus.Restoring);
|
||||||
tenantManager.SaveTenant(tenant);
|
tenantManager.SaveTenant(tenant);
|
||||||
|
|
||||||
@ -536,7 +547,7 @@ namespace ASC.Data.Backup.Service
|
|||||||
var tenants = tenantManager.GetTenants();
|
var tenants = tenantManager.GetTenants();
|
||||||
foreach (var t in tenants)
|
foreach (var t in tenants)
|
||||||
{
|
{
|
||||||
notifyHelper.SendAboutRestoreCompleted(t.TenantId, Notify);
|
notifyHelper.SendAboutRestoreCompleted(t, Notify);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -557,14 +568,17 @@ namespace ASC.Data.Backup.Service
|
|||||||
// sleep until tenants cache expires
|
// sleep until tenants cache expires
|
||||||
Thread.Sleep(TimeSpan.FromMinutes(2));
|
Thread.Sleep(TimeSpan.FromMinutes(2));
|
||||||
|
|
||||||
notifyHelper.SendAboutRestoreCompleted(restoredTenant.TenantId, Notify);
|
notifyHelper.SendAboutRestoreCompleted(restoredTenant, Notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
Percentage = 75;
|
Percentage = 75;
|
||||||
|
|
||||||
|
backupWorker.PublishProgress(this);
|
||||||
|
|
||||||
File.Delete(tempFile);
|
File.Delete(tempFile);
|
||||||
|
|
||||||
Percentage = 100;
|
Percentage = 100;
|
||||||
|
backupWorker.PublishProgress(this);
|
||||||
}
|
}
|
||||||
catch (Exception error)
|
catch (Exception error)
|
||||||
{
|
{
|
||||||
@ -579,6 +593,15 @@ namespace ASC.Data.Backup.Service
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
backupWorker.PublishProgress(this);
|
||||||
|
}
|
||||||
|
catch (Exception error)
|
||||||
|
{
|
||||||
|
Log.Error("publish", error);
|
||||||
|
}
|
||||||
|
|
||||||
if (File.Exists(tempFile))
|
if (File.Exists(tempFile))
|
||||||
{
|
{
|
||||||
File.Delete(tempFile);
|
File.Delete(tempFile);
|
||||||
@ -649,11 +672,12 @@ namespace ASC.Data.Backup.Service
|
|||||||
var backupWorker = scope.ServiceProvider.GetService<BackupWorker>();
|
var backupWorker = scope.ServiceProvider.GetService<BackupWorker>();
|
||||||
|
|
||||||
var tempFile = PathHelper.GetTempFileName(TempFolder);
|
var tempFile = PathHelper.GetTempFileName(TempFolder);
|
||||||
var alias = tenantManager.GetTenant(TenantId).TenantAlias;
|
var tenant = tenantManager.GetTenant(TenantId);
|
||||||
|
var alias = tenant.TenantAlias;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
notifyHelper.SendAboutTransferStart(TenantId, TargetRegion, Notify);
|
notifyHelper.SendAboutTransferStart(tenant, TargetRegion, Notify);
|
||||||
var transferProgressItem = scope.ServiceProvider.GetService<TransferPortalTask>();
|
var transferProgressItem = scope.ServiceProvider.GetService<TransferPortalTask>();
|
||||||
transferProgressItem.Init(TenantId, ConfigPaths[CurrentRegion], ConfigPaths[TargetRegion], Limit, TempFolder);
|
transferProgressItem.Init(TenantId, ConfigPaths[CurrentRegion], ConfigPaths[TargetRegion], Limit, TempFolder);
|
||||||
transferProgressItem.ProgressChanged += (sender, args) =>
|
transferProgressItem.ProgressChanged += (sender, args) =>
|
||||||
@ -668,7 +692,8 @@ namespace ASC.Data.Backup.Service
|
|||||||
transferProgressItem.RunJob();
|
transferProgressItem.RunJob();
|
||||||
|
|
||||||
Link = GetLink(alias, false);
|
Link = GetLink(alias, false);
|
||||||
notifyHelper.SendAboutTransferComplete(TenantId, TargetRegion, Link, !Notify);
|
notifyHelper.SendAboutTransferComplete(tenant, TargetRegion, Link, !Notify);
|
||||||
|
backupWorker.PublishProgress(this);
|
||||||
}
|
}
|
||||||
catch (Exception error)
|
catch (Exception error)
|
||||||
{
|
{
|
||||||
@ -676,10 +701,19 @@ namespace ASC.Data.Backup.Service
|
|||||||
Error = error;
|
Error = error;
|
||||||
|
|
||||||
Link = GetLink(alias, true);
|
Link = GetLink(alias, true);
|
||||||
notifyHelper.SendAboutTransferError(TenantId, TargetRegion, Link, !Notify);
|
notifyHelper.SendAboutTransferError(tenant, TargetRegion, Link, !Notify);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
backupWorker.PublishProgress(this);
|
||||||
|
}
|
||||||
|
catch (Exception error)
|
||||||
|
{
|
||||||
|
Log.Error("publish", error);
|
||||||
|
}
|
||||||
|
|
||||||
if (File.Exists(tempFile))
|
if (File.Exists(tempFile))
|
||||||
{
|
{
|
||||||
File.Delete(tempFile);
|
File.Delete(tempFile);
|
||||||
|
@ -156,6 +156,7 @@ namespace ASC.Notify
|
|||||||
}
|
}
|
||||||
|
|
||||||
dbContext.SaveChanges();
|
dbContext.SaveChanges();
|
||||||
|
tx.Commit();
|
||||||
|
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { toastr, utils } from "asc-web-components";
|
import { toastr, utils } from "asc-web-components";
|
||||||
import { api } from "asc-web-common";
|
|
||||||
import TreeFolders from "./TreeFolders";
|
import TreeFolders from "./TreeFolders";
|
||||||
import {
|
import {
|
||||||
setFilter,
|
setFilter,
|
||||||
@ -17,8 +16,7 @@ class ArticleBodyContent extends React.Component {
|
|||||||
state = {
|
state = {
|
||||||
expandedKeys: this.props.filter.treeFolders,
|
expandedKeys: this.props.filter.treeFolders,
|
||||||
data: this.props.data,
|
data: this.props.data,
|
||||||
showNewFilesPanel: false,
|
showNewFilesPanel: false
|
||||||
newFiles: []
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
@ -31,6 +29,9 @@ class ArticleBodyContent extends React.Component {
|
|||||||
this.setState({ expandedKeys: filter.treeFolders });
|
this.setState({ expandedKeys: filter.treeFolders });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//console.log(prevProps.data);
|
||||||
|
//console.log(data);
|
||||||
|
|
||||||
if (!utils.array.isArrayEqual(prevProps.data, data)) {
|
if (!utils.array.isArrayEqual(prevProps.data, data)) {
|
||||||
this.setState({ data });
|
this.setState({ data });
|
||||||
}
|
}
|
||||||
@ -41,7 +42,7 @@ class ArticleBodyContent extends React.Component {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelect = data => {
|
onSelect = data => {
|
||||||
@ -60,28 +61,12 @@ class ArticleBodyContent extends React.Component {
|
|||||||
|
|
||||||
onShowNewFilesPanel = (folderId) => {
|
onShowNewFilesPanel = (folderId) => {
|
||||||
const { showNewFilesPanel } = this.state;
|
const { showNewFilesPanel } = this.state;
|
||||||
const { onLoading } = this.props;
|
this.setState({showNewFilesPanel: !showNewFilesPanel, newFolderId: [folderId]});
|
||||||
if(typeof(folderId) === "number") {
|
|
||||||
onLoading(true);
|
|
||||||
api.files
|
|
||||||
.getNewFiles(folderId)
|
|
||||||
.then((res) =>
|
|
||||||
this.setState({
|
|
||||||
showNewFilesPanel: !showNewFilesPanel,
|
|
||||||
newFiles: res,
|
|
||||||
newFolderId: folderId
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch((err) => toastr.error(err))
|
|
||||||
.finally(() => onLoading(false));
|
|
||||||
} else {
|
|
||||||
this.setState({showNewFilesPanel: !showNewFilesPanel});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
setNewFilesCount = (id, filesCount) => {
|
setNewFilesCount = (folderPath, filesCount) => {
|
||||||
const data = this.state.data;
|
const data = this.state.data;
|
||||||
const dataItem = data.find(x => x.id === id);
|
const dataItem = data.find(x => x.id === folderPath[0]);
|
||||||
dataItem.newItems = filesCount ? filesCount : dataItem.newItems - 1;
|
dataItem.newItems = filesCount ? filesCount : dataItem.newItems - 1;
|
||||||
this.setState({ data });
|
this.setState({ data });
|
||||||
}
|
}
|
||||||
@ -106,7 +91,7 @@ class ArticleBodyContent extends React.Component {
|
|||||||
isShare
|
isShare
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const { showNewFilesPanel, expandedKeys, newFiles, newFolderId } = this.state;
|
const { showNewFilesPanel, expandedKeys, newFolderId } = this.state;
|
||||||
|
|
||||||
//console.log("Article Body render", this.props, this.state.expandedKeys);
|
//console.log("Article Body render", this.props, this.state.expandedKeys);
|
||||||
return (
|
return (
|
||||||
@ -118,7 +103,10 @@ class ArticleBodyContent extends React.Component {
|
|||||||
setNewFilesCount={this.setNewFilesCount}
|
setNewFilesCount={this.setNewFilesCount}
|
||||||
onLoading={onLoading}
|
onLoading={onLoading}
|
||||||
folderId={newFolderId}
|
folderId={newFolderId}
|
||||||
files={newFiles}
|
treeFolders={data}
|
||||||
|
setTreeFolders={setTreeFolders}
|
||||||
|
|
||||||
|
//setNewItems={this.setNewItems}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<TreeFolders
|
<TreeFolders
|
||||||
|
@ -5,10 +5,11 @@ import { withRouter } from "react-router";
|
|||||||
import { withTranslation } from "react-i18next";
|
import { withTranslation } from "react-i18next";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { RowContent, Link, Text, Icons, Badge, toastr } from "asc-web-components";
|
import { RowContent, Link, Text, Icons, Badge, toastr } from "asc-web-components";
|
||||||
import { constants } from 'asc-web-common';
|
import { constants, api } from 'asc-web-common';
|
||||||
import { createFile, createFolder, renameFolder, updateFile, setFilter, fetchFiles } from '../../../../../store/files/actions';
|
import { createFile, createFolder, renameFolder, updateFile, fetchFiles, setTreeFolders } from '../../../../../store/files/actions';
|
||||||
import { canWebEdit, isImage, isSound, isVideo, canConvert, getTitleWithoutExst } from '../../../../../store/files/selectors';
|
import { canWebEdit, isImage, isSound, isVideo, canConvert, getTitleWithoutExst } from '../../../../../store/files/selectors';
|
||||||
import store from "../../../../../store/store";
|
import store from "../../../../../store/store";
|
||||||
|
import { NewFilesPanel } from "../../../../panels";
|
||||||
import EditingWrapperComponent from "./EditingWrapperComponent";
|
import EditingWrapperComponent from "./EditingWrapperComponent";
|
||||||
|
|
||||||
const { FileAction } = constants;
|
const { FileAction } = constants;
|
||||||
@ -25,7 +26,10 @@ class FilesRowContent extends React.PureComponent {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
itemTitle: titleWithoutExt,
|
itemTitle: titleWithoutExt,
|
||||||
editingId: props.fileAction.id
|
editingId: props.fileAction.id,
|
||||||
|
showNewFilesPanel: false,
|
||||||
|
newFolderId: [],
|
||||||
|
newItems: props.item.new
|
||||||
//loading: false
|
//loading: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -180,20 +184,48 @@ class FilesRowContent extends React.PureComponent {
|
|||||||
history.push(`${settings.homepage}/${fileId}/history`);
|
history.push(`${settings.homepage}/${fileId}/history`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBadgeClick = () => {
|
||||||
|
const { showNewFilesPanel } = this.state;
|
||||||
|
const { item, treeFolders, setTreeFolders, rootFolderId, newItems, filter } = this.props;
|
||||||
|
if (item.fileExst) {
|
||||||
|
api.files
|
||||||
|
.markAsRead([], [item.id])
|
||||||
|
.then(() => {
|
||||||
|
const data = treeFolders;
|
||||||
|
const dataItem = data.find((x) => x.id === rootFolderId);
|
||||||
|
dataItem.newItems = newItems ? dataItem.newItems - 1 : 0;//////newItems
|
||||||
|
setTreeFolders(data);
|
||||||
|
fetchFiles(this.props.selectedFolder.id, filter.clone(), store.dispatch);
|
||||||
|
})
|
||||||
|
.catch((err) => toastr.error(err))
|
||||||
|
} else {
|
||||||
|
const newFolderId = this.props.selectedFolder.pathParts;
|
||||||
|
newFolderId.push(item.id);
|
||||||
|
this.setState({
|
||||||
|
showNewFilesPanel: !showNewFilesPanel,
|
||||||
|
newFolderId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onShowNewFilesPanel = () => {
|
||||||
|
const { showNewFilesPanel } = this.state;
|
||||||
|
this.setState({showNewFilesPanel: !showNewFilesPanel});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { t, item, fileAction, isLoading, isTrashFolder } = this.props;
|
const { t, item, fileAction, isLoading, isTrashFolder, onLoading, folders } = this.props;
|
||||||
const { itemTitle, editingId/*, loading*/ } = this.state;
|
const { itemTitle, editingId, showNewFilesPanel, newItems, newFolderId } = this.state;
|
||||||
const {
|
const {
|
||||||
contentLength,
|
contentLength,
|
||||||
updated,
|
updated,
|
||||||
createdBy,
|
createdBy,
|
||||||
fileExst,
|
fileExst,
|
||||||
filesCount,
|
filesCount,
|
||||||
fileStatus,
|
|
||||||
foldersCount,
|
foldersCount,
|
||||||
|
fileStatus,
|
||||||
id,
|
id,
|
||||||
versionGroup,
|
versionGroup
|
||||||
newItems
|
|
||||||
} = item;
|
} = item;
|
||||||
|
|
||||||
const SimpleFilesRowContent = styled(RowContent)`
|
const SimpleFilesRowContent = styled(RowContent)`
|
||||||
@ -239,6 +271,7 @@ class FilesRowContent extends React.PureComponent {
|
|||||||
|
|
||||||
const isEdit = (id === editingId) && (fileExst === fileAction.extension);
|
const isEdit = (id === editingId) && (fileExst === fileAction.extension);
|
||||||
const linkStyles = isTrashFolder ? { noHover: true } : { onClick: this.onFilesClick };
|
const linkStyles = isTrashFolder ? { noHover: true } : { onClick: this.onFilesClick };
|
||||||
|
const showNew = item.new && item.new > 0;
|
||||||
|
|
||||||
return isEdit
|
return isEdit
|
||||||
? <EditingWrapperComponent
|
? <EditingWrapperComponent
|
||||||
@ -252,6 +285,16 @@ class FilesRowContent extends React.PureComponent {
|
|||||||
cancelUpdateItem={this.cancelUpdateItem}
|
cancelUpdateItem={this.cancelUpdateItem}
|
||||||
/>
|
/>
|
||||||
: (
|
: (
|
||||||
|
<>
|
||||||
|
{showNewFilesPanel && (
|
||||||
|
<NewFilesPanel
|
||||||
|
visible={showNewFilesPanel}
|
||||||
|
onClose={this.onShowNewFilesPanel}
|
||||||
|
onLoading={onLoading}
|
||||||
|
folderId={newFolderId}
|
||||||
|
folders={folders}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<SimpleFilesRowContent
|
<SimpleFilesRowContent
|
||||||
sideColor="#333"
|
sideColor="#333"
|
||||||
isFile={fileExst}
|
isFile={fileExst}
|
||||||
@ -340,7 +383,7 @@ class FilesRowContent extends React.PureComponent {
|
|||||||
fontWeight={800}
|
fontWeight={800}
|
||||||
label={`New`}
|
label={`New`}
|
||||||
maxWidth="50px"
|
maxWidth="50px"
|
||||||
onClick={this.onShowVersionHistory}
|
onClick={this.onBadgeClick}
|
||||||
padding="0 5px"
|
padding="0 5px"
|
||||||
data-id={id}
|
data-id={id}
|
||||||
/>
|
/>
|
||||||
@ -348,7 +391,7 @@ class FilesRowContent extends React.PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className='badges'>
|
<div className='badges'>
|
||||||
{ newItems && newItems > 0 &&
|
{ !!showNew &&
|
||||||
<Badge
|
<Badge
|
||||||
className='badge-version'
|
className='badge-version'
|
||||||
backgroundColor="#ED7309"
|
backgroundColor="#ED7309"
|
||||||
@ -358,7 +401,7 @@ class FilesRowContent extends React.PureComponent {
|
|||||||
fontWeight={800}
|
fontWeight={800}
|
||||||
label={newItems}
|
label={newItems}
|
||||||
maxWidth="50px"
|
maxWidth="50px"
|
||||||
onClick={this.onShowVersionHistory}
|
onClick={this.onBadgeClick}
|
||||||
padding="0 5px"
|
padding="0 5px"
|
||||||
data-id={id}
|
data-id={id}
|
||||||
/>
|
/>
|
||||||
@ -406,12 +449,13 @@ class FilesRowContent extends React.PureComponent {
|
|||||||
: `${t("TitleDocuments")}: ${filesCount} / ${t("TitleSubfolders")}: ${foldersCount}`}
|
: `${t("TitleDocuments")}: ${filesCount} / ${t("TitleSubfolders")}: ${foldersCount}`}
|
||||||
</Text>
|
</Text>
|
||||||
</SimpleFilesRowContent>
|
</SimpleFilesRowContent>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
const { filter, fileAction, selectedFolder, treeFolders } = state.files;
|
const { filter, fileAction, selectedFolder, treeFolders, folders } = state.files;
|
||||||
const { settings } = state.auth;
|
const { settings } = state.auth;
|
||||||
const indexOfTrash = 3;
|
const indexOfTrash = 3;
|
||||||
|
|
||||||
@ -420,10 +464,15 @@ function mapStateToProps(state) {
|
|||||||
fileAction,
|
fileAction,
|
||||||
parentFolder: selectedFolder.id,
|
parentFolder: selectedFolder.id,
|
||||||
isTrashFolder: treeFolders[indexOfTrash].id === selectedFolder.id,
|
isTrashFolder: treeFolders[indexOfTrash].id === selectedFolder.id,
|
||||||
settings
|
settings,
|
||||||
|
treeFolders,
|
||||||
|
rootFolderId: selectedFolder.pathParts[0],
|
||||||
|
newItems: selectedFolder.new,
|
||||||
|
selectedFolder,
|
||||||
|
folders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, { createFile, createFolder, updateFile, renameFolder, setFilter })(
|
export default connect(mapStateToProps, { createFile, createFolder, updateFile, renameFolder, setTreeFolders })(
|
||||||
withRouter(withTranslation()(FilesRowContent))
|
withRouter(withTranslation()(FilesRowContent))
|
||||||
);
|
);
|
@ -79,6 +79,7 @@ class SectionFilterContent extends React.Component {
|
|||||||
const sortBy = data.sortId;
|
const sortBy = data.sortId;
|
||||||
const sortOrder =
|
const sortOrder =
|
||||||
data.sortDirection === "desc" ? "descending" : "ascending";
|
data.sortDirection === "desc" ? "descending" : "ascending";
|
||||||
|
const viewAs = data.viewAs;
|
||||||
const authorType = getAuthorType(data.filterValues);
|
const authorType = getAuthorType(data.filterValues);
|
||||||
const withSubfolders = getSearchParams(data.filterValues);
|
const withSubfolders = getSearchParams(data.filterValues);
|
||||||
|
|
||||||
@ -95,6 +96,7 @@ class SectionFilterContent extends React.Component {
|
|||||||
newFilter.page = 0;
|
newFilter.page = 0;
|
||||||
newFilter.sortBy = sortBy;
|
newFilter.sortBy = sortBy;
|
||||||
newFilter.sortOrder = sortOrder;
|
newFilter.sortOrder = sortOrder;
|
||||||
|
newFilter.viewAs = viewAs;
|
||||||
newFilter.filterType = filterType;
|
newFilter.filterType = filterType;
|
||||||
newFilter.search = search;
|
newFilter.search = search;
|
||||||
newFilter.authorType = authorType;
|
newFilter.authorType = authorType;
|
||||||
@ -207,14 +209,21 @@ class SectionFilterContent extends React.Component {
|
|||||||
getSortData = () => {
|
getSortData = () => {
|
||||||
const { t } = this.props;
|
const { t } = this.props;
|
||||||
|
|
||||||
return [
|
const commonOptions = [
|
||||||
{ key: "lastModifiedDate", label: t("ByLastModifiedDate"), default: true },
|
{ key: "lastModifiedDate", label: t("ByLastModifiedDate"), default: true },
|
||||||
{ key: "creationDate", label: t("ByCreationDate"), default: true },
|
{ key: "creationDate", label: t("ByCreationDate"), default: true },
|
||||||
{ key: "title", label: t("ByTitle"), default: true },
|
{ key: "title", label: t("ByTitle"), default: true },
|
||||||
{ key: "type", label: t("ByType"), default: true },
|
{ key: "type", label: t("ByType"), default: true },
|
||||||
{ key: "size", label: t("BySize"), default: true },
|
{ key: "size", label: t("BySize"), default: true },
|
||||||
{ key: "author", label: t("ByAuthor"), default: true },
|
{ key: "author", label: t("ByAuthor"), default: true }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const viewSettings = [
|
||||||
|
{ key: "row", label: t("ViewList"), isSetting: true, default: true },
|
||||||
|
{ key: "tile", label: t("ViewTiles"), isSetting: true, default: true }
|
||||||
|
];
|
||||||
|
//TODO: Need use mobile detect for better result
|
||||||
|
return window.innerWidth < 460 ? [...commonOptions,...viewSettings] : commonOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
getSelectedFilterData = () => {
|
getSelectedFilterData = () => {
|
||||||
@ -222,7 +231,8 @@ class SectionFilterContent extends React.Component {
|
|||||||
const selectedFilterData = {
|
const selectedFilterData = {
|
||||||
filterValues: [],
|
filterValues: [],
|
||||||
sortDirection: filter.sortOrder === "ascending" ? "asc" : "desc",
|
sortDirection: filter.sortOrder === "ascending" ? "asc" : "desc",
|
||||||
sortId: filter.sortBy
|
sortId: filter.sortBy,
|
||||||
|
viewAs: filter.viewAs
|
||||||
};
|
};
|
||||||
|
|
||||||
selectedFilterData.inputValue = filter.search;
|
selectedFilterData.inputValue = filter.search;
|
||||||
@ -269,12 +279,12 @@ class SectionFilterContent extends React.Component {
|
|||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
return (!isEqual(this.props.filter, nextProps.filter) || this.props.selectedFolderId !== nextProps.selectedFolderId || this.state.isReady !== nextState.isReady);
|
return (!isEqual(this.props.filter, nextProps.filter) || this.props.selectedFolderId !== nextProps.selectedFolderId || this.state.isReady !== nextState.isReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const selectedFilterData = this.getSelectedFilterData();
|
const selectedFilterData = this.getSelectedFilterData();
|
||||||
const { t, i18n } = this.props;
|
const { t, i18n } = this.props;
|
||||||
const filterColumnCount = window.innerWidth < 500 ? {} : {filterColumnCount: 3}
|
const filterColumnCount = window.innerWidth < 500 ? {} : { filterColumnCount: 3 }
|
||||||
return (
|
return (
|
||||||
<FilterInput
|
<FilterInput
|
||||||
getFilterData={this.getData}
|
getFilterData={this.getData}
|
||||||
|
@ -82,5 +82,7 @@
|
|||||||
"TooltipElementMoveMessage": "Move {{element}}",
|
"TooltipElementMoveMessage": "Move {{element}}",
|
||||||
"TooltipElementsMoveMessage": "Move {{element}} elements",
|
"TooltipElementsMoveMessage": "Move {{element}} elements",
|
||||||
"TooltipElementCopyMessage": "Copy {{element}}",
|
"TooltipElementCopyMessage": "Copy {{element}}",
|
||||||
"TooltipElementsCopyMessage": "Copy {{element}} elements"
|
"TooltipElementsCopyMessage": "Copy {{element}} elements",
|
||||||
|
"ViewList": "List",
|
||||||
|
"ViewTiles": "Tiles"
|
||||||
}
|
}
|
@ -82,5 +82,7 @@
|
|||||||
"TooltipElementMoveMessage": "Переместить {{element}}",
|
"TooltipElementMoveMessage": "Переместить {{element}}",
|
||||||
"TooltipElementsMoveMessage": "Переместить {{element}} элемента(ов)",
|
"TooltipElementsMoveMessage": "Переместить {{element}} элемента(ов)",
|
||||||
"TooltipElementCopyMessage": "Скопировать {{element}}",
|
"TooltipElementCopyMessage": "Скопировать {{element}}",
|
||||||
"TooltipElementsCopyMessage": "Скопировать {{element}} элемента(ов)"
|
"TooltipElementsCopyMessage": "Скопировать {{element}} элемента(ов)",
|
||||||
|
"ViewList": "Список",
|
||||||
|
"ViewTiles": "Плитки"
|
||||||
}
|
}
|
@ -26,7 +26,7 @@ import {
|
|||||||
StyledFooter
|
StyledFooter
|
||||||
} from "../StyledPanels";
|
} from "../StyledPanels";
|
||||||
import { getFileIcon, getFolderIcon, canWebEdit, isImage, isSound, isVideo } from "../../../store/files/selectors";
|
import { getFileIcon, getFolderIcon, canWebEdit, isImage, isSound, isVideo } from "../../../store/files/selectors";
|
||||||
import { fetchFiles, setMediaViewerData } from '../../../store/files/actions';
|
import { fetchFiles, setMediaViewerData, setTreeFolders } from '../../../store/files/actions';
|
||||||
import store from "../../../store/store";
|
import store from "../../../store/store";
|
||||||
|
|
||||||
const { changeLanguage } = commonUtils;
|
const { changeLanguage } = commonUtils;
|
||||||
@ -36,6 +36,20 @@ class NewFilesPanelComponent extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
changeLanguage(i18n);
|
changeLanguage(i18n);
|
||||||
|
|
||||||
|
this.state = { files: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { folderId, onLoading } = this.props;
|
||||||
|
onLoading(true);
|
||||||
|
api.files
|
||||||
|
.getNewFiles(folderId[folderId.length - 1])
|
||||||
|
.then(files =>
|
||||||
|
this.setState({ files })
|
||||||
|
)
|
||||||
|
.catch((err) => toastr.error(err))
|
||||||
|
.finally(() => onLoading(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemIcon = (item, isEdit) => {
|
getItemIcon = (item, isEdit) => {
|
||||||
@ -57,16 +71,29 @@ class NewFilesPanelComponent extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMarkAsRead = () => {
|
onMarkAsRead = () => {
|
||||||
const { folderId, onClose, setNewFilesCount } = this.props;
|
const { folderId, onClose } = this.props;
|
||||||
|
const markAsReadFiles = true;
|
||||||
|
|
||||||
|
const folderIds = [];
|
||||||
|
const fileIds = [];
|
||||||
|
|
||||||
|
for(let item of this.state.files) {
|
||||||
|
if(item.fileExst) {
|
||||||
|
fileIds.push(item.id);
|
||||||
|
} else {
|
||||||
|
folderIds.push(item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
api.files
|
api.files
|
||||||
.markAsRead([folderId], [])
|
.markAsRead(folderIds, fileIds)
|
||||||
.then(() => setNewFilesCount(folderId, 0))
|
.then(() => this.setNewFilesCount(folderId, markAsReadFiles))
|
||||||
.catch(err => toastr.error(err))
|
.catch(err => toastr.error(err))
|
||||||
.finally(() => onClose());
|
.finally(() => onClose());
|
||||||
};
|
};
|
||||||
|
|
||||||
onNewFilesClick = item => {
|
onNewFilesClick = item => {
|
||||||
const { setNewFilesCount, onClose, /*onLoading,*/ folderId } = this.props;
|
const { onClose, /*onLoading,*/ folderId } = this.props;
|
||||||
const folderIds = [];
|
const folderIds = [];
|
||||||
const fileId = [];
|
const fileId = [];
|
||||||
const isFile = item.fileExst;
|
const isFile = item.fileExst;
|
||||||
@ -75,9 +102,10 @@ class NewFilesPanelComponent extends React.Component {
|
|||||||
|
|
||||||
//onLoading(true);
|
//onLoading(true);
|
||||||
|
|
||||||
|
//api.files.markAsRead([], [])
|
||||||
api.files.markAsRead(folderIds, fileId)
|
api.files.markAsRead(folderIds, fileId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setNewFilesCount(folderId);
|
this.setNewFilesCount(folderId, false, item);
|
||||||
this.onFilesClick(item);
|
this.onFilesClick(item);
|
||||||
})
|
})
|
||||||
.catch(err => toastr.error(err))
|
.catch(err => toastr.error(err))
|
||||||
@ -111,10 +139,54 @@ class NewFilesPanelComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setNewFilesCount = (folderPath, markAsReadAll, item) => {
|
||||||
|
const { treeFolders, setTreeFolders, folders, files, filter } = this.props;
|
||||||
|
const newFilter = filter.clone();
|
||||||
|
|
||||||
|
const data = treeFolders;
|
||||||
|
let dataItem;
|
||||||
|
|
||||||
|
const loop = (index, newData) => {
|
||||||
|
dataItem = newData.find(x => x.id === folderPath[index]);
|
||||||
|
if(index === folderPath.length - 1) {
|
||||||
|
const rootItem = data.find(x => x.id === folderPath[0]);
|
||||||
|
const newFilesCounter = dataItem.newItems ? dataItem.newItems : dataItem.new;
|
||||||
|
rootItem.newItems = markAsReadAll ? rootItem.newItems - newFilesCounter : rootItem.newItems - 1;
|
||||||
|
dataItem.newItems = markAsReadAll ? 0 : newFilesCounter - 1;
|
||||||
|
fetchFiles(this.props.selectedFolder.id, newFilter, store.dispatch);
|
||||||
|
return;
|
||||||
|
} else { loop(index + 1, dataItem.folders); }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(folderPath.length > 1) {
|
||||||
|
loop(0, data);
|
||||||
|
} else {
|
||||||
|
dataItem = data.find(x => x.id === folderPath[0]);
|
||||||
|
dataItem.newItems = markAsReadAll ? 0 : dataItem.newItems - 1;
|
||||||
|
|
||||||
|
if(item && item.fileExst) {
|
||||||
|
const fileItem = files.find(x => x.id === item.id && x.fileExst);
|
||||||
|
if(fileItem) {
|
||||||
|
fileItem.new = markAsReadAll ? 0 : fileItem.new - 1;
|
||||||
|
} else {
|
||||||
|
const filesFolder = folders.find(x => x.id === item.folderId);
|
||||||
|
filesFolder.new = markAsReadAll ? 0 : filesFolder.new - 1;
|
||||||
|
}
|
||||||
|
fetchFiles(this.props.selectedFolder.id, newFilter, store.dispatch);
|
||||||
|
} else if(item && !item.fileExst) {
|
||||||
|
const folderItem = folders.find(x => x.id === item.id && !x.fileExst);
|
||||||
|
folderItem.new = markAsReadAll ? 0 : folderItem.new - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTreeFolders(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
//console.log("NewFiles panel render");
|
//console.log("NewFiles panel render");
|
||||||
const { t, visible, onClose, files } = this.props;
|
const { t, visible, onClose } = this.props;
|
||||||
|
const { files } = this.state;
|
||||||
const zIndex = 310;
|
const zIndex = 310;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -192,8 +264,8 @@ const NewFilesPanel = (props) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
const { filter } = state.files
|
const { filter, files, folders, treeFolders, selectedFolder } = state.files
|
||||||
return { filter };
|
return { filter, files, folders, treeFolders, selectedFolder };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, { setMediaViewerData })(withRouter(NewFilesPanel));
|
export default connect(mapStateToProps, { setMediaViewerData, setTreeFolders })(withRouter(NewFilesPanel));
|
||||||
|
@ -5,6 +5,7 @@ export const FILTER_TYPE = "filterType";
|
|||||||
export const SEARCH = "search";
|
export const SEARCH = "search";
|
||||||
export const SORT_BY = "sortby";
|
export const SORT_BY = "sortby";
|
||||||
export const SORT_ORDER = "sortorder";
|
export const SORT_ORDER = "sortorder";
|
||||||
|
export const VIEW_AS = "viewas";
|
||||||
export const PAGE = "page";
|
export const PAGE = "page";
|
||||||
export const PAGE_COUNT = "pagecount";
|
export const PAGE_COUNT = "pagecount";
|
||||||
export const FOLDER = "folder";
|
export const FOLDER = "folder";
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
SEARCH,
|
SEARCH,
|
||||||
SORT_BY,
|
SORT_BY,
|
||||||
SORT_ORDER,
|
SORT_ORDER,
|
||||||
|
VIEW_AS,
|
||||||
PAGE,
|
PAGE,
|
||||||
PAGE_COUNT,
|
PAGE_COUNT,
|
||||||
AUTHOR_TYPE,
|
AUTHOR_TYPE,
|
||||||
@ -28,6 +29,7 @@ export function getFilterByLocation(location) {
|
|||||||
defaultFilter.withSubfolders;
|
defaultFilter.withSubfolders;
|
||||||
const search = urlFilter[SEARCH] || defaultFilter.search;
|
const search = urlFilter[SEARCH] || defaultFilter.search;
|
||||||
const sortBy = urlFilter[SORT_BY] || defaultFilter.sortBy;
|
const sortBy = urlFilter[SORT_BY] || defaultFilter.sortBy;
|
||||||
|
const viewAs = urlFilter[VIEW_AS] || defaultFilter.viewAs;
|
||||||
const sortOrder = urlFilter[SORT_ORDER] || defaultFilter.sortOrder;
|
const sortOrder = urlFilter[SORT_ORDER] || defaultFilter.sortOrder;
|
||||||
const page = (urlFilter[PAGE] && (+urlFilter[PAGE]-1)) || defaultFilter.page;
|
const page = (urlFilter[PAGE] && (+urlFilter[PAGE]-1)) || defaultFilter.page;
|
||||||
const pageCount =
|
const pageCount =
|
||||||
@ -41,6 +43,7 @@ export function getFilterByLocation(location) {
|
|||||||
defaultFilter.total,
|
defaultFilter.total,
|
||||||
sortBy,
|
sortBy,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
|
viewAs,
|
||||||
filterType,
|
filterType,
|
||||||
withSubfolders,
|
withSubfolders,
|
||||||
search,
|
search,
|
||||||
|
@ -188,7 +188,7 @@ export function fetchFiles(folderId, filter, dispatch) {
|
|||||||
dispatch(setFolders(data.folders));
|
dispatch(setFolders(data.folders));
|
||||||
dispatch(setFiles(data.files));
|
dispatch(setFiles(data.files));
|
||||||
//dispatch(setSelected("close")); //TODO: need close but it`s crash first select, need new logic
|
//dispatch(setSelected("close")); //TODO: need close but it`s crash first select, need new logic
|
||||||
return dispatch(setSelectedFolder({ folders: data.folders, ...data.current, pathParts: data.pathParts }));
|
return dispatch(setSelectedFolder({ folders: data.folders, ...data.current, pathParts: data.pathParts, ...{new: data.new} }));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,6 +360,7 @@ export function moveToFolder(destFolderId, folderIds, fileIds, conflictResolveTy
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*export function deleteGroup(id) {
|
/*export function deleteGroup(id) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const { people } = getState();
|
const { people } = getState();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "asc-web-common",
|
"name": "asc-web-common",
|
||||||
"version": "1.0.167",
|
"version": "1.0.170",
|
||||||
"description": "Ascensio System SIA common components and solutions library",
|
"description": "Ascensio System SIA common components and solutions library",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"files": [
|
"files": [
|
||||||
|
@ -5,6 +5,7 @@ const DEFAULT_PAGE_COUNT = 25;
|
|||||||
const DEFAULT_TOTAL = 0;
|
const DEFAULT_TOTAL = 0;
|
||||||
const DEFAULT_SORT_BY = "lastModifiedDate";
|
const DEFAULT_SORT_BY = "lastModifiedDate";
|
||||||
const DEFAULT_SORT_ORDER = "ascending";
|
const DEFAULT_SORT_ORDER = "ascending";
|
||||||
|
const DEFAULT_VIEW = "row";
|
||||||
const DEFAULT_FILTER_TYPE = null;
|
const DEFAULT_FILTER_TYPE = null;
|
||||||
const DEFAULT_SEARCH_TYPE = true; //withSubfolders
|
const DEFAULT_SEARCH_TYPE = true; //withSubfolders
|
||||||
const DEFAULT_SEARCH = null;
|
const DEFAULT_SEARCH = null;
|
||||||
@ -29,6 +30,7 @@ class FilesFilter {
|
|||||||
total = DEFAULT_TOTAL,
|
total = DEFAULT_TOTAL,
|
||||||
sortBy = DEFAULT_SORT_BY,
|
sortBy = DEFAULT_SORT_BY,
|
||||||
sortOrder = DEFAULT_SORT_ORDER,
|
sortOrder = DEFAULT_SORT_ORDER,
|
||||||
|
viewAs = DEFAULT_VIEW,
|
||||||
filterType = DEFAULT_FILTER_TYPE,
|
filterType = DEFAULT_FILTER_TYPE,
|
||||||
withSubfolders = DEFAULT_SEARCH_TYPE,
|
withSubfolders = DEFAULT_SEARCH_TYPE,
|
||||||
search = DEFAULT_SEARCH,
|
search = DEFAULT_SEARCH,
|
||||||
@ -41,6 +43,7 @@ class FilesFilter {
|
|||||||
this.pageCount = pageCount;
|
this.pageCount = pageCount;
|
||||||
this.sortBy = sortBy;
|
this.sortBy = sortBy;
|
||||||
this.sortOrder = sortOrder;
|
this.sortOrder = sortOrder;
|
||||||
|
this.viewAs = viewAs;
|
||||||
this.filterType = filterType;
|
this.filterType = filterType;
|
||||||
this.withSubfolders = withSubfolders;
|
this.withSubfolders = withSubfolders;
|
||||||
this.search = search;
|
this.search = search;
|
||||||
@ -106,6 +109,7 @@ class FilesFilter {
|
|||||||
this.total,
|
this.total,
|
||||||
this.sortBy,
|
this.sortBy,
|
||||||
this.sortOrder,
|
this.sortOrder,
|
||||||
|
this.viewAs,
|
||||||
this.filterType,
|
this.filterType,
|
||||||
this.withSubfolders,
|
this.withSubfolders,
|
||||||
this.search,
|
this.search,
|
||||||
@ -124,6 +128,7 @@ class FilesFilter {
|
|||||||
this.search === filter.search &&
|
this.search === filter.search &&
|
||||||
this.sortBy === filter.sortBy &&
|
this.sortBy === filter.sortBy &&
|
||||||
this.sortOrder === filter.sortOrder &&
|
this.sortOrder === filter.sortOrder &&
|
||||||
|
this.viewAs === filter.viewAs &&
|
||||||
this.page === filter.page &&
|
this.page === filter.page &&
|
||||||
this.selectedItem.key === filter.selectedItem.key &&
|
this.selectedItem.key === filter.selectedItem.key &&
|
||||||
this.folder === filter.folder &&
|
this.folder === filter.folder &&
|
||||||
|
@ -61,7 +61,8 @@ export function getFoldersTree() {
|
|||||||
title: folder.title,
|
title: folder.title,
|
||||||
access: folder.access,
|
access: folder.access,
|
||||||
foldersCount: folder.foldersCount,
|
foldersCount: folder.foldersCount,
|
||||||
rootFolderType: folder.rootFolderType
|
rootFolderType: folder.rootFolderType,
|
||||||
|
newItems: folder.new
|
||||||
}
|
}
|
||||||
}) : null,
|
}) : null,
|
||||||
pathParts: data.pathParts,
|
pathParts: data.pathParts,
|
||||||
|
@ -5,6 +5,7 @@ import isEqual from 'lodash/isEqual';
|
|||||||
import throttle from 'lodash/throttle';
|
import throttle from 'lodash/throttle';
|
||||||
import FilterBlock from './sub-components/FilterBlock';
|
import FilterBlock from './sub-components/FilterBlock';
|
||||||
import SortComboBox from './sub-components/SortComboBox';
|
import SortComboBox from './sub-components/SortComboBox';
|
||||||
|
import ViewSelector from './sub-components/ViewSelector';
|
||||||
import map from 'lodash/map';
|
import map from 'lodash/map';
|
||||||
import clone from 'lodash/clone';
|
import clone from 'lodash/clone';
|
||||||
import StyledFilterInput from './StyledFilterInput';
|
import StyledFilterInput from './StyledFilterInput';
|
||||||
@ -92,6 +93,7 @@ class FilterInput extends React.Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
sortDirection: props.selectedFilterData.sortDirection === "desc" ? true : false,
|
sortDirection: props.selectedFilterData.sortDirection === "desc" ? true : false,
|
||||||
|
viewAs: props.selectedFilterData.viewAs,
|
||||||
sortId: props.getSortData().findIndex(x => x.key === props.selectedFilterData.sortId) != -1 ? props.selectedFilterData.sortId : props.getSortData().length > 0 ? props.getSortData()[0].key : "",
|
sortId: props.getSortData().findIndex(x => x.key === props.selectedFilterData.sortId) != -1 ? props.selectedFilterData.sortId : props.getSortData().length > 0 ? props.getSortData()[0].key : "",
|
||||||
searchText: props.selectedFilterData.inputValue || props.value,
|
searchText: props.selectedFilterData.inputValue || props.value,
|
||||||
|
|
||||||
@ -120,6 +122,8 @@ class FilterInput extends React.Component {
|
|||||||
this.onDeleteFilterItem = this.onDeleteFilterItem.bind(this);
|
this.onDeleteFilterItem = this.onDeleteFilterItem.bind(this);
|
||||||
this.clearFilter = this.clearFilter.bind(this);
|
this.clearFilter = this.clearFilter.bind(this);
|
||||||
|
|
||||||
|
this.onClickViewSelector = this.onClickViewSelector.bind(this);
|
||||||
|
|
||||||
this.throttledResize = throttle(this.resize, 300);
|
this.throttledResize = throttle(this.resize, 300);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -230,9 +234,15 @@ class FilterInput extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
onChangeSortDirection(key) {
|
onChangeSortDirection(key) {
|
||||||
this.onFilter(this.state.filterValues, this.state.sortId, key ? "desc" : "asc");
|
this.onFilter(this.state.filterValues, this.state.sortId, key ? "desc" : "asc", this.state.viewAs);
|
||||||
this.setState({ sortDirection: !!key });
|
this.setState({ sortDirection: !!key });
|
||||||
}
|
}
|
||||||
|
onClickViewSelector(item) {
|
||||||
|
const itemId = (item.target && item.target.dataset.for) || item;
|
||||||
|
const viewAs = itemId.indexOf("row") === -1 ? "tile" : "row"
|
||||||
|
this.onFilter(this.state.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc", viewAs);
|
||||||
|
this.setState({ viewAs: viewAs });
|
||||||
|
}
|
||||||
getDefaultSelectedIndex() {
|
getDefaultSelectedIndex() {
|
||||||
const sortData = this.props.getSortData();
|
const sortData = this.props.getSortData();
|
||||||
if (sortData.length > 0) {
|
if (sortData.length > 0) {
|
||||||
@ -243,19 +253,19 @@ class FilterInput extends React.Component {
|
|||||||
}
|
}
|
||||||
onClickSortItem(key) {
|
onClickSortItem(key) {
|
||||||
this.setState({ sortId: key });
|
this.setState({ sortId: key });
|
||||||
this.onFilter(this.state.filterValues, key, this.state.sortDirection ? "desc" : "asc");
|
this.onFilter(this.state.filterValues, key, this.state.sortDirection ? "desc" : "asc", this.state.viewAs);
|
||||||
}
|
}
|
||||||
onSortDirectionClick() {
|
onSortDirectionClick() {
|
||||||
|
|
||||||
this.onFilter(this.state.filterValues, this.state.sortId, !this.state.sortDirection ? "desc" : "asc");
|
this.onFilter(this.state.filterValues, this.state.sortId, !this.state.sortDirection ? "desc" : "asc", this.state.viewAs);
|
||||||
this.setState({ sortDirection: !this.state.sortDirection });
|
this.setState({ sortDirection: !this.state.sortDirection });
|
||||||
}
|
}
|
||||||
onSearchChanged(value) {
|
onSearchChanged(value) {
|
||||||
this.setState({ searchText: value });
|
this.setState({ searchText: value });
|
||||||
this.onFilter(this.state.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc", value);
|
this.onFilter(this.state.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc", this.state.viewAs, value);
|
||||||
}
|
}
|
||||||
onSearch(result) {
|
onSearch(result) {
|
||||||
this.onFilter(result.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc");
|
this.onFilter(result.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc", this.state.viewAs);
|
||||||
}
|
}
|
||||||
getFilterData() {
|
getFilterData() {
|
||||||
const _this = this;
|
const _this = this;
|
||||||
@ -280,7 +290,7 @@ class FilterInput extends React.Component {
|
|||||||
openFilterItems: [],
|
openFilterItems: [],
|
||||||
hideFilterItems: []
|
hideFilterItems: []
|
||||||
});
|
});
|
||||||
this.onFilter([], this.state.sortId, this.state.sortDirection ? "desc" : "asc", '');
|
this.onFilter([], this.state.sortId, this.state.sortDirection ? "desc" : "asc", this.state.viewAs, '');
|
||||||
}
|
}
|
||||||
updateFilter(inputFilterItems) {
|
updateFilter(inputFilterItems) {
|
||||||
const currentFilterItems = inputFilterItems || cloneObjectsArray(this.state.filterValues);
|
const currentFilterItems = inputFilterItems || cloneObjectsArray(this.state.filterValues);
|
||||||
@ -344,9 +354,9 @@ class FilterInput extends React.Component {
|
|||||||
item.key = item.key.replace(item.group + "_", '');
|
item.key = item.key.replace(item.group + "_", '');
|
||||||
return item;
|
return item;
|
||||||
})
|
})
|
||||||
this.onFilter(filterValues.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc");
|
this.onFilter(filterValues.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc", this.state.viewAs);
|
||||||
}
|
}
|
||||||
onFilter(filterValues, sortId, sortDirection, searchText) {
|
onFilter(filterValues, sortId, sortDirection, viewAs, searchText) {
|
||||||
let cloneFilterValues = cloneObjectsArray(filterValues);
|
let cloneFilterValues = cloneObjectsArray(filterValues);
|
||||||
cloneFilterValues = cloneFilterValues.map(function (item) {
|
cloneFilterValues = cloneFilterValues.map(function (item) {
|
||||||
item.key = item.key.replace(item.group + "_", '');
|
item.key = item.key.replace(item.group + "_", '');
|
||||||
@ -356,7 +366,8 @@ class FilterInput extends React.Component {
|
|||||||
inputValue: searchText != undefined ? searchText : this.state.searchText,
|
inputValue: searchText != undefined ? searchText : this.state.searchText,
|
||||||
filterValues: cloneFilterValues.filter(item => item.key != '-1'),
|
filterValues: cloneFilterValues.filter(item => item.key != '-1'),
|
||||||
sortId: sortId,
|
sortId: sortId,
|
||||||
sortDirection: sortDirection
|
sortDirection: sortDirection,
|
||||||
|
viewAs: viewAs
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onChangeFilter(result) {
|
onChangeFilter(result) {
|
||||||
@ -364,7 +375,7 @@ class FilterInput extends React.Component {
|
|||||||
searchText: result.inputValue,
|
searchText: result.inputValue,
|
||||||
filterValues: result.filterValues,
|
filterValues: result.filterValues,
|
||||||
});
|
});
|
||||||
this.onFilter(result.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc", result.inputValue);
|
this.onFilter(result.filterValues, this.state.sortId, this.state.sortDirection ? "desc" : "asc", this.state.viewAs, result.inputValue);
|
||||||
}
|
}
|
||||||
onFilterRender() {
|
onFilterRender() {
|
||||||
if (this.isResizeUpdate) {
|
if (this.isResizeUpdate) {
|
||||||
@ -419,7 +430,7 @@ class FilterInput extends React.Component {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
this.onFilter(clone.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc");
|
this.onFilter(clone.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc", this.state.viewAs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -467,7 +478,7 @@ class FilterInput extends React.Component {
|
|||||||
item.key = item.key.replace(item.group + "_", '');
|
item.key = item.key.replace(item.group + "_", '');
|
||||||
return item;
|
return item;
|
||||||
})
|
})
|
||||||
this.onFilter(clone.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc");
|
this.onFilter(clone.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc", this.state.viewAs);
|
||||||
this.setState({
|
this.setState({
|
||||||
filterValues: currentFilterItems,
|
filterValues: currentFilterItems,
|
||||||
openFilterItems: currentFilterItems,
|
openFilterItems: currentFilterItems,
|
||||||
@ -503,7 +514,7 @@ class FilterInput extends React.Component {
|
|||||||
item.key = item.key.replace(item.group + "_", '');
|
item.key = item.key.replace(item.group + "_", '');
|
||||||
return item;
|
return item;
|
||||||
})
|
})
|
||||||
this.onFilter(clone.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc");
|
this.onFilter(clone.filter(item => item.key != '-1'), this.state.sortId, this.state.sortDirection ? "desc" : "asc", this.state.viewAs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -517,7 +528,7 @@ class FilterInput extends React.Component {
|
|||||||
/* eslint-enable react/prop-types */
|
/* eslint-enable react/prop-types */
|
||||||
|
|
||||||
const { searchText, filterValues, openFilterItems,
|
const { searchText, filterValues, openFilterItems,
|
||||||
hideFilterItems, sortId, sortDirection } = this.state;
|
hideFilterItems, sortId, sortDirection, viewAs } = this.state;
|
||||||
|
|
||||||
// console.log("filter input render, openFilterItems", openFilterItems, 'hideFilterItems', hideFilterItems);
|
// console.log("filter input render, openFilterItems", openFilterItems, 'hideFilterItems', hideFilterItems);
|
||||||
let iconSize = 33;
|
let iconSize = 33;
|
||||||
@ -574,6 +585,7 @@ class FilterInput extends React.Component {
|
|||||||
options={getSortData()}
|
options={getSortData()}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
onChangeSortId={this.onClickSortItem}
|
onChangeSortId={this.onClickSortItem}
|
||||||
|
onChangeView={this.onClickViewSelector}
|
||||||
onChangeSortDirection={this.onChangeSortDirection}
|
onChangeSortDirection={this.onChangeSortDirection}
|
||||||
selectedOption={getSortData().length > 0 ? getSortData().find(x => x.key === sortId) : {}}
|
selectedOption={getSortData().length > 0 ? getSortData().find(x => x.key === sortId) : {}}
|
||||||
onButtonClick={this.onSortDirectionClick}
|
onButtonClick={this.onSortDirectionClick}
|
||||||
@ -581,6 +593,11 @@ class FilterInput extends React.Component {
|
|||||||
directionAscLabel={directionAscLabel}
|
directionAscLabel={directionAscLabel}
|
||||||
directionDescLabel={directionDescLabel}
|
directionDescLabel={directionDescLabel}
|
||||||
/>
|
/>
|
||||||
|
<ViewSelector
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
onClickViewSelector={this.onClickViewSelector}
|
||||||
|
viewAs={viewAs}
|
||||||
|
/>
|
||||||
</StyledFilterInput>
|
</StyledFilterInput>
|
||||||
|
|
||||||
);
|
);
|
||||||
|
@ -43,7 +43,8 @@ class FilterStory extends React.Component {
|
|||||||
inputValue: "text",
|
inputValue: "text",
|
||||||
filterValues: [
|
filterValues: [
|
||||||
{key: "1", group: "filter-status"}
|
{key: "1", group: "filter-status"}
|
||||||
]
|
],
|
||||||
|
viewAs: "row"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.buttonClick = this.buttonClick.bind(this);
|
this.buttonClick = this.buttonClick.bind(this);
|
||||||
|
@ -17,7 +17,10 @@ const StyledFilterInput = styled.div`
|
|||||||
.styled-search-input {
|
.styled-search-input {
|
||||||
display: block;
|
display: block;
|
||||||
float: left;
|
float: left;
|
||||||
width: calc(100% - 140px);
|
width: calc(100% - 212px);
|
||||||
|
@media (max-width: 460px) {
|
||||||
|
width: calc(100% - 140px);
|
||||||
|
}
|
||||||
@media ${mobile} {
|
@media ${mobile} {
|
||||||
width: calc(100% - 58px);
|
width: calc(100% - 58px);
|
||||||
}
|
}
|
||||||
@ -121,8 +124,50 @@ const StyledFilterInput = styled.div`
|
|||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledViewSelector = styled.div`
|
||||||
|
display: flex;
|
||||||
|
float: left;
|
||||||
|
width: 64px;
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
@media (max-width: 460px) {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-selector-button{
|
||||||
|
border: 1px solid ${props => props.isDisabled ? '#ECEEF1' : '#D0D5DA'};
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 7px;
|
||||||
|
${props => props.isDisabled && 'background-color: #F8F9F9;' }
|
||||||
|
|
||||||
|
svg{
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active{
|
||||||
|
background-color:#A3A9AE;
|
||||||
|
border-color: #A3A9AE;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
${props => !props.isDisabled && 'background-color: #A3A9AE;' }
|
||||||
|
${props => !props.isDisabled && 'border-color: #A3A9AE;' }
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child{
|
||||||
|
border-right: none;
|
||||||
|
border-top-right-radius:0;
|
||||||
|
border-bottom-right-radius:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child{
|
||||||
|
border-left: none;
|
||||||
|
border-top-left-radius:0;
|
||||||
|
border-bottom-left-radius:0;
|
||||||
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const StyledFilterItem = styled.div`
|
export const StyledFilterItem = styled.div`
|
||||||
@ -228,4 +273,11 @@ export const StyledIconButton = styled.div`
|
|||||||
transform: ${state => !state.sortDirection ? 'scale(1, -1)' : 'scale(1)'};
|
transform: ${state => !state.sortDirection ? 'scale(1, -1)' : 'scale(1)'};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
export const StyledIconWrapper = styled.div`
|
||||||
|
display: inline-flex;
|
||||||
|
width: 32px;
|
||||||
|
height: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
export default StyledFilterInput;
|
export default StyledFilterInput;
|
@ -5,137 +5,168 @@ import PropTypes from 'prop-types';
|
|||||||
import { StyledIconButton } from '../StyledFilterInput';
|
import { StyledIconButton } from '../StyledFilterInput';
|
||||||
|
|
||||||
class SortComboBox extends React.Component {
|
class SortComboBox extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const { sortDirection } = props;
|
const { sortDirection } = props;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
sortDirection
|
sortDirection
|
||||||
}
|
|
||||||
|
|
||||||
this.combobox = React.createRef();
|
|
||||||
}
|
|
||||||
onButtonClick = () => {
|
|
||||||
const { onChangeSortDirection } = this.props;
|
|
||||||
const { sortDirection } = this.state;
|
|
||||||
typeof onChangeSortDirection === 'function' && onChangeSortDirection(+(sortDirection === 0 ? 1 : 0));
|
|
||||||
this.setState({
|
|
||||||
sortDirection: sortDirection === 0 ? 1 : 0
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeSortId = (e) => {
|
this.combobox = React.createRef();
|
||||||
const { onChangeSortId } = this.props;
|
}
|
||||||
typeof onChangeSortId === 'function' && onChangeSortId(e.target.value);
|
onButtonClick = () => {
|
||||||
}
|
const { onChangeSortDirection } = this.props;
|
||||||
onChangeSortDirection = (e) => {
|
const { sortDirection } = this.state;
|
||||||
const sortDirection = +e.target.value;
|
typeof onChangeSortDirection === 'function' && onChangeSortDirection(+(sortDirection === 0 ? 1 : 0));
|
||||||
const { onChangeSortDirection } = this.props;
|
this.setState({
|
||||||
this.setState({ sortDirection });
|
sortDirection: sortDirection === 0 ? 1 : 0
|
||||||
typeof onChangeSortDirection === 'function' && onChangeSortDirection(sortDirection);
|
});
|
||||||
}
|
}
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
|
||||||
//TODO
|
|
||||||
/*const comboboxText = this.combobox.current.ref.current.children[0].children[1];
|
|
||||||
if(comboboxText.scrollWidth > Math.round(comboboxText.getBoundingClientRect().width)){
|
|
||||||
comboboxText.style.opacity = "0";
|
|
||||||
}else{
|
|
||||||
comboboxText.style.opacity = "1";
|
|
||||||
}*/
|
|
||||||
const { sortDirection } = nextProps;
|
|
||||||
if (this.props.sortDirection !== sortDirection) {
|
|
||||||
this.setState({
|
|
||||||
sortDirection
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (!isEqual(this.props, nextProps) || !isEqual(this.state, nextState));
|
|
||||||
}
|
|
||||||
render() {
|
|
||||||
const { options, directionAscLabel, directionDescLabel, isDisabled,
|
|
||||||
selectedOption } = this.props;
|
|
||||||
const { sortDirection } = this.state;
|
|
||||||
let sortArray = options.map(function (item) {
|
|
||||||
item.value = item.key
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
let sortDirectionArray = [
|
|
||||||
{ value: '0', label: directionAscLabel },
|
|
||||||
{ value: '1', label: directionDescLabel }
|
|
||||||
];
|
|
||||||
|
|
||||||
const advancedOptions = (
|
onChangeSortId = (e) => {
|
||||||
<>
|
const { onChangeSortId } = this.props;
|
||||||
<DropDownItem noHover >
|
typeof onChangeSortId === 'function' && onChangeSortId(e.target.value);
|
||||||
<RadioButtonGroup
|
}
|
||||||
fontWeight={600}
|
|
||||||
isDisabled={isDisabled}
|
onChangeView = (e) => {
|
||||||
name={'direction'}
|
const { onChangeView } = this.props;
|
||||||
onClick={this.onChangeSortDirection}
|
typeof onChangeView === 'function' && onChangeView(e.target.value);
|
||||||
options={sortDirectionArray}
|
}
|
||||||
orientation='vertical'
|
|
||||||
selected={sortDirection.toString()}
|
onChangeSortDirection = (e) => {
|
||||||
spacing='0px'
|
const sortDirection = +e.target.value;
|
||||||
/>
|
const { onChangeSortDirection } = this.props;
|
||||||
</DropDownItem>
|
this.setState({ sortDirection });
|
||||||
<DropDownItem isSeparator />
|
typeof onChangeSortDirection === 'function' && onChangeSortDirection(sortDirection);
|
||||||
<DropDownItem noHover >
|
}
|
||||||
<RadioButtonGroup
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
fontWeight={600}
|
//TODO
|
||||||
isDisabled={isDisabled}
|
/*const comboboxText = this.combobox.current.ref.current.children[0].children[1];
|
||||||
name={'sort'}
|
if(comboboxText.scrollWidth > Math.round(comboboxText.getBoundingClientRect().width)){
|
||||||
onClick={this.onChangeSortId}
|
comboboxText.style.opacity = "0";
|
||||||
options={sortArray}
|
}else{
|
||||||
orientation='vertical'
|
comboboxText.style.opacity = "1";
|
||||||
selected={selectedOption.key}
|
}*/
|
||||||
spacing='0px'
|
const { sortDirection } = nextProps;
|
||||||
/>
|
if (this.props.sortDirection !== sortDirection) {
|
||||||
</DropDownItem>
|
this.setState({
|
||||||
</>
|
sortDirection
|
||||||
);
|
});
|
||||||
return (
|
return true;
|
||||||
<ComboBox
|
}
|
||||||
advancedOptions={advancedOptions}
|
return (!isEqual(this.props, nextProps) || !isEqual(this.state, nextState));
|
||||||
className='styled-sort-combobox'
|
}
|
||||||
directionX="right"
|
render() {
|
||||||
|
const { options, directionAscLabel, directionDescLabel, isDisabled,
|
||||||
|
selectedOption } = this.props;
|
||||||
|
const { sortDirection } = this.state;
|
||||||
|
|
||||||
|
let settingsArray = options.filter(item => {
|
||||||
|
item.value = item.key
|
||||||
|
return item.isSetting === true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let sortArray = options.filter(item => {
|
||||||
|
item.value = item.key
|
||||||
|
return item.isSetting !== true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let sortDirectionArray = [
|
||||||
|
{ value: '0', label: directionAscLabel },
|
||||||
|
{ value: '1', label: directionDescLabel }
|
||||||
|
];
|
||||||
|
|
||||||
|
const advancedOptions = (
|
||||||
|
<>
|
||||||
|
<DropDownItem noHover >
|
||||||
|
<RadioButtonGroup
|
||||||
|
fontWeight={600}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
name={'direction'}
|
||||||
|
onClick={this.onChangeSortDirection}
|
||||||
|
options={sortDirectionArray}
|
||||||
|
orientation='vertical'
|
||||||
|
selected={sortDirection.toString()}
|
||||||
|
spacing='0px'
|
||||||
|
/>
|
||||||
|
</DropDownItem>
|
||||||
|
<DropDownItem isSeparator />
|
||||||
|
<DropDownItem noHover >
|
||||||
|
<RadioButtonGroup
|
||||||
|
fontWeight={600}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
name={'sort'}
|
||||||
|
onClick={this.onChangeSortId}
|
||||||
|
options={sortArray}
|
||||||
|
orientation='vertical'
|
||||||
|
selected={selectedOption.key}
|
||||||
|
spacing='0px'
|
||||||
|
/>
|
||||||
|
</DropDownItem>
|
||||||
|
{settingsArray.length !== 0 &&
|
||||||
|
<>
|
||||||
|
<DropDownItem isSeparator />
|
||||||
|
<DropDownItem noHover >
|
||||||
|
<RadioButtonGroup
|
||||||
|
fontWeight={600}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
options={[]}
|
name={'view'}
|
||||||
ref={this.combobox}
|
onClick={this.onChangeView}
|
||||||
scaled={true}
|
options={settingsArray}
|
||||||
selectedOption={selectedOption}
|
orientation='vertical'
|
||||||
size="content"
|
selected={selectedOption.key}
|
||||||
>
|
spacing='0px'
|
||||||
<StyledIconButton sortDirection={!!sortDirection}>
|
/>
|
||||||
<IconButton
|
</DropDownItem>
|
||||||
clickColor={"#333"}
|
</>
|
||||||
color={"#A3A9AE"}
|
}
|
||||||
hoverColor={"#333"}
|
</>
|
||||||
iconName={'ZASortingIcon'}
|
);
|
||||||
isDisabled={isDisabled}
|
return (
|
||||||
isFill={true}
|
<ComboBox
|
||||||
onClick={this.onButtonClick}
|
advancedOptions={advancedOptions}
|
||||||
size={10}
|
className='styled-sort-combobox'
|
||||||
/>
|
directionX="right"
|
||||||
</StyledIconButton>
|
isDisabled={isDisabled}
|
||||||
</ComboBox>
|
options={[]}
|
||||||
);
|
ref={this.combobox}
|
||||||
}
|
scaled={true}
|
||||||
|
selectedOption={selectedOption}
|
||||||
|
size="content"
|
||||||
|
>
|
||||||
|
<StyledIconButton sortDirection={!!sortDirection}>
|
||||||
|
<IconButton
|
||||||
|
clickColor={"#333"}
|
||||||
|
color={"#A3A9AE"}
|
||||||
|
hoverColor={"#333"}
|
||||||
|
iconName={'ZASortingIcon'}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isFill={true}
|
||||||
|
onClick={this.onButtonClick}
|
||||||
|
size={10}
|
||||||
|
/>
|
||||||
|
</StyledIconButton>
|
||||||
|
</ComboBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SortComboBox.propTypes = {
|
SortComboBox.propTypes = {
|
||||||
directionAscLabel: PropTypes.string,
|
directionAscLabel: PropTypes.string,
|
||||||
directionDescLabel: PropTypes.string,
|
directionDescLabel: PropTypes.string,
|
||||||
isDisabled: PropTypes.bool,
|
isDisabled: PropTypes.bool,
|
||||||
onButtonClick: PropTypes.func,
|
onButtonClick: PropTypes.func,
|
||||||
onChangeSortDirection: PropTypes.func,
|
onChangeSortDirection: PropTypes.func,
|
||||||
onChangeSortId: PropTypes.func,
|
onChangeSortId: PropTypes.func,
|
||||||
sortDirection: PropTypes.number,
|
onChangeView: PropTypes.func,
|
||||||
|
sortDirection: PropTypes.number,
|
||||||
}
|
}
|
||||||
|
|
||||||
SortComboBox.defaultProps = {
|
SortComboBox.defaultProps = {
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
sortDirection: 0
|
sortDirection: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { IconButton } from 'asc-web-components';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { StyledViewSelector } from '../StyledFilterInput';
|
||||||
|
|
||||||
|
|
||||||
|
class ViewSelector extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
viewAs: props.viewAs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(){
|
||||||
|
const { isDisabled, viewAs} = this.props;
|
||||||
|
|
||||||
|
return(
|
||||||
|
<StyledViewSelector isDisabled={isDisabled}>
|
||||||
|
<IconButton
|
||||||
|
className={`view-selector-button ${viewAs === "row" ? "active" : ""}`}
|
||||||
|
color={viewAs === "row" ? "#ffffff" : "#A3A9AE"}
|
||||||
|
hoverColor={"#ffffff"}
|
||||||
|
clickColor={"#ffffff"}
|
||||||
|
iconName={'FilterViewSelectorRowIcon'}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isFill={true}
|
||||||
|
onClick={(item) => this.props.onClickViewSelector(item)}
|
||||||
|
size={16}
|
||||||
|
id="rowSelectorButton"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
className={`view-selector-button ${viewAs === "tile" ? "active" : ""}`}
|
||||||
|
color={viewAs === "tile" ? "#ffffff" : "#A3A9AE"}
|
||||||
|
hoverColor={"#ffffff"}
|
||||||
|
clickColor={"#ffffff"}
|
||||||
|
iconName={'FilterViewSelectorTileIcon'}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isFill={true}
|
||||||
|
onClick={(item) => this.props.onClickViewSelector(item)}
|
||||||
|
size={16}
|
||||||
|
id="tileSelectorButton"
|
||||||
|
/>
|
||||||
|
</StyledViewSelector>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ViewSelector.propTypes = {
|
||||||
|
isDisabled: PropTypes.bool,
|
||||||
|
viewAs: PropTypes.string,
|
||||||
|
onClickViewSelector: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewSelector.defaultProps = {
|
||||||
|
isDisabled: false
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ViewSelector;
|
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 15C0 15.5523 0.447715 16 1 16H15C15.5523 16 16 15.5523 16 15C16 14.4477 15.5523 14 15 14H1C0.447715 14 0 14.4477 0 15ZM0 8C0 8.55228 0.447715 9 1 9H15C15.5523 9 16 8.55228 16 8C16 7.44771 15.5523 7 15 7H1C0.447715 7 0 7.44771 0 8ZM1 2C0.447715 2 0 1.55229 0 1C0 0.447715 0.447715 0 1 0H15C15.5523 0 16 0.447715 16 1C16 1.55229 15.5523 2 15 2H1Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 516 B |
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 0C0.447715 0 0 0.447715 0 1V6C0 6.55228 0.447715 7 1 7H6C6.55228 7 7 6.55228 7 6V1C7 0.447715 6.55228 0 6 0H1ZM1 9C0.447715 9 0 9.44771 0 10V15C0 15.5523 0.447715 16 1 16H6C6.55228 16 7 15.5523 7 15V10C7 9.44772 6.55228 9 6 9H1ZM9 1C9 0.447715 9.44772 0 10 0H15C15.5523 0 16 0.447715 16 1V6C16 6.55228 15.5523 7 15 7H10C9.44771 7 9 6.55228 9 6V1ZM10 9C9.44772 9 9 9.44771 9 10V15C9 15.5523 9.44771 16 10 16H15C15.5523 16 16 15.5523 16 15V10C16 9.44772 15.5523 9 15 9H10Z" fill="#A3A9AE"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 644 B |
@ -133,6 +133,8 @@ import OrigCrossSidebarIcon from './cross.sidebar.react.svg';
|
|||||||
import OrigCheckboxIcon from './checkbox.react.svg';
|
import OrigCheckboxIcon from './checkbox.react.svg';
|
||||||
import OrigCheckboxCheckedIcon from './checkbox.checked.react.svg';
|
import OrigCheckboxCheckedIcon from './checkbox.checked.react.svg';
|
||||||
import OrigCheckboxIndeterminateIcon from './checkbox.indeterminate.react.svg';
|
import OrigCheckboxIndeterminateIcon from './checkbox.indeterminate.react.svg';
|
||||||
|
import OrigFilterViewSelectorRowIcon from './filter.view.selector.row.react.svg';
|
||||||
|
import OrigFilterViewSelectorTileIcon from './filter.view.selector.tile.react.svg';
|
||||||
|
|
||||||
import OrigEyeIcon from './eye.react.svg';
|
import OrigEyeIcon from './eye.react.svg';
|
||||||
import OrigEyeOffIcon from './eye.off.react.svg';
|
import OrigEyeOffIcon from './eye.off.react.svg';
|
||||||
@ -800,4 +802,12 @@ export const ShareLinkedInIcon = createStyledIcon(
|
|||||||
export const KeyIcon = createStyledIcon(
|
export const KeyIcon = createStyledIcon(
|
||||||
OrigKeyIcon,
|
OrigKeyIcon,
|
||||||
'KeyIcon'
|
'KeyIcon'
|
||||||
|
);
|
||||||
|
export const FilterViewSelectorRowIcon = createStyledIcon(
|
||||||
|
OrigFilterViewSelectorRowIcon,
|
||||||
|
'FilterViewSelectorRowIcon'
|
||||||
|
);
|
||||||
|
export const FilterViewSelectorTileIcon = createStyledIcon(
|
||||||
|
OrigFilterViewSelectorTileIcon,
|
||||||
|
'FilterViewSelectorTileIcon'
|
||||||
);
|
);
|
@ -20,6 +20,14 @@
|
|||||||
<Compile Remove="WebZones\IRenderCustomNavigation.cs" />
|
<Compile Remove="WebZones\IRenderCustomNavigation.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="PublicResources\webstudio_patterns.xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="PublicResources\webstudio_patterns.xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\common\ASC.Common\ASC.Common.csproj" />
|
<ProjectReference Include="..\..\common\ASC.Common\ASC.Common.csproj" />
|
||||||
<ProjectReference Include="..\..\common\ASC.Core.Common\ASC.Core.Common.csproj" />
|
<ProjectReference Include="..\..\common\ASC.Core.Common\ASC.Core.Common.csproj" />
|
||||||
|
@ -28,7 +28,7 @@ using ASC.Notify.Model;
|
|||||||
|
|
||||||
namespace ASC.Web.Studio.Core.Notify
|
namespace ASC.Web.Studio.Core.Notify
|
||||||
{
|
{
|
||||||
static class Actions
|
public static class Actions
|
||||||
{
|
{
|
||||||
public static readonly INotifyAction AdminNotify = new NotifyAction("admin_notify", "admin notifications");
|
public static readonly INotifyAction AdminNotify = new NotifyAction("admin_notify", "admin notifications");
|
||||||
public static readonly INotifyAction PeriodicNotify = new NotifyAction("periodic_notify", "periodic notifications");
|
public static readonly INotifyAction PeriodicNotify = new NotifyAction("periodic_notify", "periodic notifications");
|
||||||
@ -49,8 +49,8 @@ namespace ASC.Web.Studio.Core.Notify
|
|||||||
public static readonly INotifyAction RestoreCompleted = new NotifyAction("restore_completed", "restore_completed");
|
public static readonly INotifyAction RestoreCompleted = new NotifyAction("restore_completed", "restore_completed");
|
||||||
public static readonly INotifyAction PortalDeactivate = new NotifyAction("portal_deactivate", "portal deactivate");
|
public static readonly INotifyAction PortalDeactivate = new NotifyAction("portal_deactivate", "portal deactivate");
|
||||||
public static readonly INotifyAction PortalDelete = new NotifyAction("portal_delete", "portal delete");
|
public static readonly INotifyAction PortalDelete = new NotifyAction("portal_delete", "portal delete");
|
||||||
public static readonly INotifyAction PortalDeleteSuccessV10 = new NotifyAction("portal_delete_success_v10");
|
public static readonly INotifyAction PortalDeleteSuccessV10 = new NotifyAction("portal_delete_success_v10");
|
||||||
|
|
||||||
public static readonly INotifyAction ProfileDelete = new NotifyAction("profile_delete", "profile_delete");
|
public static readonly INotifyAction ProfileDelete = new NotifyAction("profile_delete", "profile_delete");
|
||||||
public static readonly INotifyAction ProfileHasDeletedItself = new NotifyAction("profile_has_deleted_itself", "profile_has_deleted_itself");
|
public static readonly INotifyAction ProfileHasDeletedItself = new NotifyAction("profile_has_deleted_itself", "profile_has_deleted_itself");
|
||||||
public static readonly INotifyAction ReassignsCompleted = new NotifyAction("reassigns_completed", "reassigns_completed");
|
public static readonly INotifyAction ReassignsCompleted = new NotifyAction("reassigns_completed", "reassigns_completed");
|
||||||
|
@ -58,7 +58,7 @@ namespace ASC.Web.Studio.Core.Notify
|
|||||||
{
|
{
|
||||||
private readonly StudioNotifyServiceHelper client;
|
private readonly StudioNotifyServiceHelper client;
|
||||||
|
|
||||||
private static string EMailSenderName { get { return ASC.Core.Configuration.Constants.NotifyEMailSenderSysName; } }
|
public static string EMailSenderName { get { return ASC.Core.Configuration.Constants.NotifyEMailSenderSysName; } }
|
||||||
|
|
||||||
private UserManager UserManager { get; }
|
private UserManager UserManager { get; }
|
||||||
private StudioNotifyHelper StudioNotifyHelper { get; }
|
private StudioNotifyHelper StudioNotifyHelper { get; }
|
||||||
@ -653,49 +653,6 @@ namespace ASC.Web.Studio.Core.Notify
|
|||||||
tagValues.ToArray());
|
tagValues.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Backup & Restore
|
|
||||||
|
|
||||||
public void SendMsgBackupCompleted(Guid userId, string link)
|
|
||||||
{
|
|
||||||
client.SendNoticeToAsync(
|
|
||||||
Actions.BackupCreated,
|
|
||||||
new[] { StudioNotifyHelper.ToRecipient(userId) },
|
|
||||||
new[] { EMailSenderName },
|
|
||||||
new TagValue(Tags.OwnerName, UserManager.GetUsers(userId).DisplayUserName(DisplayUserSettingsHelper)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendMsgRestoreStarted(Tenant tenant, bool notifyAllUsers)
|
|
||||||
{
|
|
||||||
var owner = UserManager.GetUsers(tenant.OwnerId);
|
|
||||||
var users =
|
|
||||||
notifyAllUsers
|
|
||||||
? StudioNotifyHelper.RecipientFromEmail(UserManager.GetUsers(EmployeeStatus.Active).Where(r => r.ActivationStatus == EmployeeActivationStatus.Activated).Select(u => u.Email).ToList(), false)
|
|
||||||
: owner.ActivationStatus == EmployeeActivationStatus.Activated ? StudioNotifyHelper.RecipientFromEmail(owner.Email, false) : new IDirectRecipient[0];
|
|
||||||
|
|
||||||
client.SendNoticeToAsync(
|
|
||||||
Actions.RestoreStarted,
|
|
||||||
users,
|
|
||||||
new[] { EMailSenderName });
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendMsgRestoreCompleted(Tenant tenant, bool notifyAllUsers)
|
|
||||||
{
|
|
||||||
var owner = UserManager.GetUsers(tenant.OwnerId);
|
|
||||||
|
|
||||||
var users =
|
|
||||||
notifyAllUsers
|
|
||||||
? UserManager.GetUsers(EmployeeStatus.Active).Select(u => StudioNotifyHelper.ToRecipient(u.ID)).ToArray()
|
|
||||||
: new[] { StudioNotifyHelper.ToRecipient(owner.ID) };
|
|
||||||
|
|
||||||
client.SendNoticeToAsync(
|
|
||||||
Actions.RestoreCompleted,
|
|
||||||
users,
|
|
||||||
new[] { EMailSenderName },
|
|
||||||
new TagValue(Tags.OwnerName, owner.DisplayUserName(DisplayUserSettingsHelper)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Portal Deactivation & Deletion
|
#region Portal Deactivation & Deletion
|
||||||
|
|
||||||
public void SendMsgPortalDeactivation(Tenant t, string deactivateUrl, string activateUrl)
|
public void SendMsgPortalDeactivation(Tenant t, string deactivateUrl, string activateUrl)
|
||||||
@ -861,39 +818,6 @@ namespace ASC.Web.Studio.Core.Notify
|
|||||||
|
|
||||||
#region Migration Portal
|
#region Migration Portal
|
||||||
|
|
||||||
public void MigrationPortalStart(Tenant tenant, string region, bool notify)
|
|
||||||
{
|
|
||||||
MigrationNotify(tenant, Actions.MigrationPortalStart, region, string.Empty, notify);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MigrationPortalSuccess(Tenant tenant, string region, string url, bool notify)
|
|
||||||
{
|
|
||||||
MigrationNotify(tenant, Actions.MigrationPortalSuccess, region, url, notify);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MigrationPortalError(Tenant tenant, string region, string url, bool notify)
|
|
||||||
{
|
|
||||||
MigrationNotify(tenant, !string.IsNullOrEmpty(region) ? Actions.MigrationPortalError : Actions.MigrationPortalServerFailure, region, url, notify);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MigrationNotify(Tenant tenant, INotifyAction action, string region, string url, bool notify)
|
|
||||||
{
|
|
||||||
var users = UserManager.GetUsers()
|
|
||||||
.Where(u => notify ? u.ActivationStatus.HasFlag(EmployeeActivationStatus.Activated) : u.IsOwner(tenant))
|
|
||||||
.Select(u => StudioNotifyHelper.ToRecipient(u.ID))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
if (users.Any())
|
|
||||||
{
|
|
||||||
client.SendNoticeToAsync(
|
|
||||||
action,
|
|
||||||
users,
|
|
||||||
new[] { EMailSenderName },
|
|
||||||
new TagValue(Tags.RegionName, TransferResourceHelper.GetRegionDescription(region)),
|
|
||||||
new TagValue(Tags.PortalUrl, url));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PortalRenameNotify(Tenant tenant, string oldVirtualRootPath)
|
public void PortalRenameNotify(Tenant tenant, string oldVirtualRootPath)
|
||||||
{
|
{
|
||||||
var users = UserManager.GetUsers()
|
var users = UserManager.GetUsers()
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
namespace ASC.Web.Studio.Core.Notify
|
namespace ASC.Web.Studio.Core.Notify
|
||||||
{
|
{
|
||||||
static class Tags
|
public static class Tags
|
||||||
{
|
{
|
||||||
public const string UserName = "UserName";
|
public const string UserName = "UserName";
|
||||||
public const string UserLastName = "UserLastName";
|
public const string UserLastName = "UserLastName";
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user