diff --git a/common/ASC.Common/Threading/DistributedTask.cs b/common/ASC.Common/Threading/DistributedTask.cs index 0a5a05cc52..e837967a88 100644 --- a/common/ASC.Common/Threading/DistributedTask.cs +++ b/common/ASC.Common/Threading/DistributedTask.cs @@ -98,13 +98,24 @@ namespace ASC.Common.Threading public T GetProperty(string name) { - if (!DistributedTaskCache.Props.Any(r => r.Key == name)) return default; - - var val = DistributedTaskCache.Props.SingleOrDefault(r => r.Key == name); + var val = DistributedTaskCache.Props.FirstOrDefault(r => r.Key == name); if (val == null) return default; + + var resType = typeof(T); + object result = val.Value; + + if(resType == typeof(Guid)) + { + result = Guid.Parse(val.Value.Trim('"')); + } + else if(resType.IsEnum) + { + Enum.TryParse(resType, val.Value, out var e); + result = e; + } - return JsonSerializer.Deserialize(val.Value); + return (T)Convert.ChangeType(result, resType); } public void SetProperty(string name, object value) diff --git a/common/ASC.Core.Common/Data/DbQuotaService.cs b/common/ASC.Core.Common/Data/DbQuotaService.cs index 7f971d9c41..24d4dd911e 100644 --- a/common/ASC.Core.Common/Data/DbQuotaService.cs +++ b/common/ASC.Core.Common/Data/DbQuotaService.cs @@ -164,6 +164,7 @@ namespace ASC.Core.Data var counter = CoreDbContext.QuotaRows .Where(r => r.Path == row.Path && r.Tenant == row.Tenant) .Select(r => r.Counter) + .Take(1) .FirstOrDefault(); var dbQuotaRow = new DbQuotaRow diff --git a/common/ASC.Data.Storage/DataStoreCache.cs b/common/ASC.Data.Storage/DataStoreCache.cs deleted file mode 100644 index 8374184a94..0000000000 --- a/common/ASC.Data.Storage/DataStoreCache.cs +++ /dev/null @@ -1,63 +0,0 @@ -/* - * - * (c) Copyright Ascensio System Limited 2010-2018 - * - * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). - * In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that - * Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights. - * - * THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR - * FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html - * - * You can contact Ascensio System SIA by email at sales@onlyoffice.com - * - * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display - * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. - * - * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains - * relevant author attributions when distributing the software. If the display of the logo in its graphic - * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" - * in every copy of the program you distribute. - * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. - * -*/ - - -using System; - -using ASC.Common.Caching; - -namespace ASC.Data.Storage -{ - static class DataStoreCache - { - private static readonly ICache Cache = AscCache.Memory; - - - public static void Put(IDataStore store, string tenantId, string module) - { - Cache.Insert(DataStoreCacheItemExtenstion.MakeCacheKey(tenantId, module), store, DateTime.MaxValue); - } - - public static IDataStore Get(string tenantId, string module) - { - return Cache.Get(DataStoreCacheItemExtenstion.MakeCacheKey(tenantId, module)); - } - - public static void Remove(string tenantId, string module) - { - Cache.Remove(DataStoreCacheItemExtenstion.MakeCacheKey(tenantId, module)); - } - - - } - - public static class DataStoreCacheItemExtenstion - { - internal static string MakeCacheKey(string tenantId, string module) - { - return string.Format("{0}:\\{1}", tenantId, module); - } - } -} \ No newline at end of file diff --git a/common/ASC.Data.Storage/DiscStorage/DiscDataStore.cs b/common/ASC.Data.Storage/DiscStorage/DiscDataStore.cs index c156c7fefa..09b5ea53bd 100644 --- a/common/ASC.Data.Storage/DiscStorage/DiscDataStore.cs +++ b/common/ASC.Data.Storage/DiscStorage/DiscDataStore.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using ASC.Common; using ASC.Common.Logging; using ASC.Core; using ASC.Data.Storage.Configuration; @@ -40,6 +41,7 @@ using Microsoft.Extensions.Options; namespace ASC.Data.Storage.DiscStorage { + [Scope] public class DiscDataStore : BaseStorage { private readonly Dictionary _mappedPaths = new Dictionary(); diff --git a/common/ASC.Data.Storage/GoogleCloud/GoogleCloudStorage.cs b/common/ASC.Data.Storage/GoogleCloud/GoogleCloudStorage.cs index ba9f28df25..3d897643ff 100644 --- a/common/ASC.Data.Storage/GoogleCloud/GoogleCloudStorage.cs +++ b/common/ASC.Data.Storage/GoogleCloud/GoogleCloudStorage.cs @@ -37,6 +37,7 @@ using System.Text; using System.Threading; using System.Web; +using ASC.Common; using ASC.Common.Logging; using ASC.Core; using ASC.Data.Storage.Configuration; @@ -55,6 +56,7 @@ using MimeMapping = ASC.Common.Web.MimeMapping; namespace ASC.Data.Storage.GoogleCloud { + [Scope] public class GoogleCloudStorage : BaseStorage { private string _subDir = string.Empty; @@ -241,7 +243,7 @@ namespace ASC.Data.Storage.GoogleCloud { var contentDisposition = string.Format("attachment; filename={0};", HttpUtility.UrlPathEncode(attachmentFileName)); - if (attachmentFileName.Any(c => (int)c >= 0 && (int)c <= 127)) + if (attachmentFileName.Any(c => c >= 0 && c <= 127)) { contentDisposition = string.Format("attachment; filename*=utf-8''{0};", HttpUtility.UrlPathEncode(attachmentFileName)); @@ -786,7 +788,7 @@ namespace ASC.Data.Storage.GoogleCloud continue; } - if ((int)status != 308) + if (status != 308) throw (ex); break; diff --git a/common/ASC.Data.Storage/RackspaceCloud/RackspaceCloudStorage.cs b/common/ASC.Data.Storage/RackspaceCloud/RackspaceCloudStorage.cs index 1eb07f089a..1d1ddffe6e 100644 --- a/common/ASC.Data.Storage/RackspaceCloud/RackspaceCloudStorage.cs +++ b/common/ASC.Data.Storage/RackspaceCloud/RackspaceCloudStorage.cs @@ -30,6 +30,7 @@ using System.IO; using System.Linq; using System.Web; +using ASC.Common; using ASC.Common.Logging; using ASC.Core; using ASC.Data.Storage.Configuration; @@ -45,6 +46,7 @@ using MimeMapping = ASC.Common.Web.MimeMapping; namespace ASC.Data.Storage.RackspaceCloud { + [Scope] public class RackspaceCloudStorage : BaseStorage { private string _region; @@ -248,7 +250,7 @@ namespace ASC.Data.Storage.RackspaceCloud { var contentDisposition = string.Format("attachment; filename={0};", HttpUtility.UrlPathEncode(attachmentFileName)); - if (attachmentFileName.Any(c => (int)c >= 0 && (int)c <= 127)) + if (attachmentFileName.Any(c => c >= 0 && c <= 127)) { contentDisposition = string.Format("attachment; filename*=utf-8''{0};", HttpUtility.UrlPathEncode(attachmentFileName)); diff --git a/common/ASC.Data.Storage/S3/S3Storage.cs b/common/ASC.Data.Storage/S3/S3Storage.cs index 536827e0a1..851909947c 100644 --- a/common/ASC.Data.Storage/S3/S3Storage.cs +++ b/common/ASC.Data.Storage/S3/S3Storage.cs @@ -41,6 +41,7 @@ using Amazon.S3.Model; using Amazon.S3.Transfer; using Amazon.Util; +using ASC.Common; using ASC.Common.Logging; using ASC.Core; using ASC.Data.Storage.Configuration; @@ -53,6 +54,7 @@ using MimeMapping = ASC.Common.Web.MimeMapping; namespace ASC.Data.Storage.S3 { + [Scope] public class S3Storage : BaseStorage { private readonly List _domains = new List(); @@ -190,7 +192,7 @@ namespace ASC.Data.Storage.S3 { var contentDisposition = string.Format("attachment; filename={0};", HttpUtility.UrlPathEncode(attachmentFileName)); - if (attachmentFileName.Any(c => (int)c >= 0 && (int)c <= 127)) + if (attachmentFileName.Any(c => c >= 0 && c <= 127)) { contentDisposition = string.Format("attachment; filename*=utf-8''{0};", HttpUtility.UrlPathEncode(attachmentFileName)); diff --git a/common/ASC.Data.Storage/StorageFactory.cs b/common/ASC.Data.Storage/StorageFactory.cs index 9d1d8b8e5e..d62c923fe0 100644 --- a/common/ASC.Data.Storage/StorageFactory.cs +++ b/common/ASC.Data.Storage/StorageFactory.cs @@ -29,50 +29,20 @@ using System.Collections.Generic; using System.Linq; using ASC.Common; -using ASC.Common.Caching; -using ASC.Common.Logging; using ASC.Core; using ASC.Core.Common.Configuration; using ASC.Core.Common.Settings; using ASC.Data.Storage.Configuration; using ASC.Data.Storage.DiscStorage; -using ASC.Data.Storage.Encryption; -using ASC.Security.Cryptography; +using ASC.Data.Storage.GoogleCloud; +using ASC.Data.Storage.RackspaceCloud; +using ASC.Data.Storage.S3; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; namespace ASC.Data.Storage { - [Singletone] - public class StorageFactoryListener - { - private volatile bool Subscribed; - private readonly object locker; - private ICacheNotify Cache { get; } - - public StorageFactoryListener(ICacheNotify cache) - { - Cache = cache; - locker = new object(); - } - - public void Subscribe() - { - if (Subscribed) return; - - lock (locker) - { - if (Subscribed) return; - - Subscribed = true; - Cache.Subscribe((r) => DataStoreCache.Remove(r.TenantId, r.Module), CacheNotifyAction.Remove); - } - } - } - [Singletone(Additional = typeof(StorageConfigExtension))] public class StorageFactoryConfig { @@ -174,7 +144,7 @@ namespace ASC.Data.Storage } } - [Scope] + [Scope(Additional = typeof(StorageFactoryExtension))] public class StorageFactory { private const string DefaultTenantName = "default"; @@ -184,55 +154,22 @@ namespace ASC.Data.Storage private StorageSettingsHelper StorageSettingsHelper { get; } private TenantManager TenantManager { get; } private CoreBaseSettings CoreBaseSettings { get; } - private PathUtils PathUtils { get; } - private EmailValidationKeyProvider EmailValidationKeyProvider { get; } - private IOptionsMonitor Options { get; } - private IHttpContextAccessor HttpContextAccessor { get; } - private EncryptionSettingsHelper EncryptionSettingsHelper { get; } - private EncryptionFactory EncryptionFactory { get; } + private IServiceProvider ServiceProvider { get; } public StorageFactory( - StorageFactoryListener storageFactoryListener, + IServiceProvider serviceProvider, StorageFactoryConfig storageFactoryConfig, SettingsManager settingsManager, StorageSettingsHelper storageSettingsHelper, TenantManager tenantManager, - CoreBaseSettings coreBaseSettings, - PathUtils pathUtils, - EmailValidationKeyProvider emailValidationKeyProvider, - IOptionsMonitor options, - EncryptionSettingsHelper encryptionSettingsHelper, - EncryptionFactory encryptionFactory) : - this(storageFactoryListener, storageFactoryConfig, settingsManager, storageSettingsHelper, tenantManager, coreBaseSettings, pathUtils, emailValidationKeyProvider, options, null, encryptionSettingsHelper, encryptionFactory) + CoreBaseSettings coreBaseSettings) { - } - - public StorageFactory( - StorageFactoryListener storageFactoryListener, - StorageFactoryConfig storageFactoryConfig, - SettingsManager settingsManager, - StorageSettingsHelper storageSettingsHelper, - TenantManager tenantManager, - CoreBaseSettings coreBaseSettings, - PathUtils pathUtils, - EmailValidationKeyProvider emailValidationKeyProvider, - IOptionsMonitor options, - IHttpContextAccessor httpContextAccessor, - EncryptionSettingsHelper encryptionSettingsHelper, - EncryptionFactory encryptionFactory) - { - storageFactoryListener.Subscribe(); + ServiceProvider = serviceProvider; StorageFactoryConfig = storageFactoryConfig; SettingsManager = settingsManager; StorageSettingsHelper = storageSettingsHelper; TenantManager = tenantManager; CoreBaseSettings = coreBaseSettings; - PathUtils = pathUtils; - EmailValidationKeyProvider = emailValidationKeyProvider; - Options = options; - HttpContextAccessor = httpContextAccessor; - EncryptionSettingsHelper = encryptionSettingsHelper; - EncryptionFactory = encryptionFactory; } public IDataStore GetStorage(string tenant, string module) @@ -261,10 +198,6 @@ namespace ASC.Data.Storage //Make tennant path tenant = TenantPath.CreatePath(tenant); - //remove cache - //var store = DataStoreCache.Get(tenant, module);//TODO - //if (store == null) - //{ var section = StorageFactoryConfig.Section; if (section == null) { @@ -273,7 +206,6 @@ namespace ASC.Data.Storage var settings = SettingsManager.LoadForTenant(tenantId); - //} return GetDataStore(tenant, module, StorageSettingsHelper.DataStoreConsumer(settings), controller); } @@ -294,16 +226,6 @@ namespace ASC.Data.Storage return GetDataStore(tenant, module, consumer, new TenantQuotaController(tenantId, TenantManager)); } - private IDataStore GetStoreAndCache(string tenant, string module, DataStoreConsumer consumer, IQuotaController controller) - { - var store = GetDataStore(tenant, module, consumer, controller); - if (store != null) - { - DataStoreCache.Put(store, tenant, module); - } - return store; - } - private IDataStore GetDataStore(string tenant, string module, DataStoreConsumer consumer, IQuotaController controller) { var storage = StorageFactoryConfig.Section; @@ -330,10 +252,22 @@ namespace ASC.Data.Storage props = handler.Property.ToDictionary(r => r.Name, r => r.Value); } - return ((IDataStore)Activator.CreateInstance(instanceType, TenantManager, PathUtils, EmailValidationKeyProvider, HttpContextAccessor, Options, EncryptionSettingsHelper, EncryptionFactory)) + ; + return ((IDataStore)ActivatorUtilities.CreateInstance(ServiceProvider, instanceType)) .Configure(tenant, handler, moduleElement, props) .SetQuotaController(moduleElement.Count ? controller : null /*don't count quota if specified on module*/); } } + + public class StorageFactoryExtension + { + public static void Register(DIHelper services) + { + services.TryAdd(); + services.TryAdd(); + services.TryAdd(); + services.TryAdd(); + } + } } \ No newline at end of file diff --git a/config/appsettings.json b/config/appsettings.json index a6d30423e1..c4bca9374b 100644 --- a/config/appsettings.json +++ b/config/appsettings.json @@ -62,7 +62,7 @@ "header": "" }, "url": { - "public": "http://192.168.0.142/", + "public": "http://localhost:8085/", "internal": "", "portal": "" } diff --git a/products/ASC.Files/Client/package.json b/products/ASC.Files/Client/package.json index 85d8a1bbea..041b457941 100644 --- a/products/ASC.Files/Client/package.json +++ b/products/ASC.Files/Client/package.json @@ -9,6 +9,7 @@ "asc-web-components": "file:../../../packages/asc-web-components", "connected-react-router": "6.6.1", "copy-to-clipboard": "^3.2.0", + "fast-deep-equal": "^3.1.3", "history": "4.10.1", "i18next": "19.0.3", "i18next-browser-languagedetector": "4.0.1", diff --git a/products/ASC.Files/Client/public/index.html b/products/ASC.Files/Client/public/index.html index 31d5f4914c..d34eaf8bbe 100644 --- a/products/ASC.Files/Client/public/index.html +++ b/products/ASC.Files/Client/public/index.html @@ -239,16 +239,5 @@ To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> - diff --git a/products/ASC.Files/Client/src/App.js b/products/ASC.Files/Client/src/App.js index b0b658cfe2..82196667ea 100644 --- a/products/ASC.Files/Client/src/App.js +++ b/products/ASC.Files/Client/src/App.js @@ -1,6 +1,6 @@ import React, { Suspense } from "react"; import { connect } from "react-redux"; -import { Router, Switch, Redirect } from "react-router-dom"; +import { Router, Switch, Redirect, Route } from "react-router-dom"; import Home from "./components/pages/Home"; import DocEditor from "./components/pages/DocEditor"; import Settings from "./components/pages/Settings"; @@ -10,7 +10,6 @@ import config from "../package.json"; import { store as commonStore, - constants, history, PrivateRoute, PublicRoute, @@ -32,8 +31,8 @@ const { setCurrentProductId, setCurrentProductHomePage, getPortalCultures, + getIsAuthenticated, } = commonStore.auth.actions; -const { AUTH_KEY } = constants; class App extends React.Component { constructor(props) { @@ -43,8 +42,6 @@ class App extends React.Component { } componentDidMount() { - utils.removeTempContent(); - const { setModuleInfo, getUser, @@ -53,80 +50,83 @@ class App extends React.Component { getPortalCultures, fetchTreeFolders, setIsLoaded, + getIsAuthenticated, } = this.props; setModuleInfo(); + getIsAuthenticated().then((isAuthenticated) => { + if (!isAuthenticated) { + utils.updateTempContent(); + return setIsLoaded(); + } else { + utils.updateTempContent(isAuthenticated); + } - const token = localStorage.getItem(AUTH_KEY); + const requests = this.isEditor + ? [getUser()] + : [ + getUser(), + getPortalSettings(), + getModules(), + getPortalCultures(), + fetchTreeFolders(), + ]; - if (!token) { - return setIsLoaded(); - } - - const requests = this.isEditor - ? [getUser()] - : [ - getUser(), - getPortalSettings(), - getModules(), - getPortalCultures(), - fetchTreeFolders(), - ]; - - Promise.all(requests) - .catch((e) => { - toastr.error(e); - }) - .finally(() => { - setIsLoaded(); - }); + Promise.all(requests) + .catch((e) => { + toastr.error(e); + }) + .finally(() => { + utils.updateTempContent(); + setIsLoaded(); + }); + }); } render() { const { homepage } = this.props; return navigator.onLine ? ( - - - {!this.isEditor && } -
- - - - - - - - - - - - - - -
-
-
+ + + {!this.isEditor && } +
+ + + + + + + + + + + + + +
+
+
) : ( ); @@ -143,6 +143,7 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { + getIsAuthenticated: () => getIsAuthenticated(dispatch), setModuleInfo: () => { dispatch(setCurrentProductHomePage(config.homepage)); dispatch(setCurrentProductId("e67be73d-f9ae-4ce1-8fec-1880cb518cb4")); diff --git a/products/ASC.Files/Client/src/components/Article/Body/TreeFolders.js b/products/ASC.Files/Client/src/components/Article/Body/TreeFolders.js index 24528ffc26..284060a826 100644 --- a/products/ASC.Files/Client/src/components/Article/Body/TreeFolders.js +++ b/products/ASC.Files/Client/src/components/Article/Body/TreeFolders.js @@ -1,7 +1,7 @@ import React from "react"; import { TreeMenu, TreeNode, Icons } from "asc-web-components"; import styled from "styled-components"; -import isEqual from "lodash/isEqual"; +import equal from "fast-deep-equal/react"; import { api, constants, toastr, store as initStore } from "asc-web-common"; import { connect } from "react-redux"; import { @@ -70,7 +70,7 @@ class TreeFolders extends React.Component { this.setState({ expandedKeys }); } - if (!isEqual(prevProps.data, data)) { + if (!equal(prevProps.data, data)) { //!utils.array.isArrayEqual(prevProps.data, data)) { this.setState({ treeData: data }); } diff --git a/products/ASC.Files/Client/src/components/Article/Body/index.js b/products/ASC.Files/Client/src/components/Article/Body/index.js index 7160b833b9..ce0add7bdb 100644 --- a/products/ASC.Files/Client/src/components/Article/Body/index.js +++ b/products/ASC.Files/Client/src/components/Article/Body/index.js @@ -107,7 +107,7 @@ class ArticleBodyContent extends React.Component { const { showNewFilesPanel, expandedKeys, newFolderId } = this.state; //console.log("Article Body render", this.props, this.state.expandedKeys); - console.log("Article Body render"); + //console.log("Article Body render"); return ( <> {showNewFilesPanel && ( diff --git a/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/index.js b/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/index.js index 38632298fd..9e2f3356ef 100644 --- a/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/index.js +++ b/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/index.js @@ -8,7 +8,7 @@ import { utils } from "asc-web-common"; import { setTreeFolders, setDialogVisible, - onConvert, + convertUploadedFiles, } from "../../../store/files/actions"; import { createI18N } from "../../../helpers/i18n"; const i18n = createI18N({ @@ -50,7 +50,7 @@ class ConvertDialogComponent extends React.Component { return false; } - onConvert = () => this.props.onConvert(this.props.t); + onConvert = () => this.props.convertUploadedFiles(this.props.t); onClose = () => this.props.setDialogVisible(this.props.t); render() { @@ -66,7 +66,7 @@ class ConvertDialogComponent extends React.Component { convert alert image
{t("ConversionMessage")} @@ -118,12 +118,8 @@ const ConvertDialog = (props) => ( ); -const mapStateToProps = (state) => { - return {}; -}; - -export default connect(mapStateToProps, { +export default connect(null, { setTreeFolders, setDialogVisible, - onConvert, + convertUploadedFiles, })(withRouter(ConvertDialog)); diff --git a/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/locales/en/translation.json b/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/locales/en/translation.json index 1b57aad8d4..cfca170171 100644 --- a/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/locales/en/translation.json +++ b/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/locales/en/translation.json @@ -5,5 +5,6 @@ "HideMessage": "Do not show this message again", "ContinueButton": "Continue", "CloseButton": "Close", - "UploadingLabel": "Uploading files: {{file}} of {{totalFiles}}" + "UploadingLabel": "Uploading files: {{file}} of {{totalFiles}}", + "ConvertingLabel": "Converting files: {{file}} of {{totalFiles}}" } diff --git a/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/locales/ru/translation.json b/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/locales/ru/translation.json index 999e876b6f..82cc5a968d 100644 --- a/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/locales/ru/translation.json +++ b/products/ASC.Files/Client/src/components/dialogs/ConvertDialog/locales/ru/translation.json @@ -5,5 +5,6 @@ "HideMessage": "Больше не показывать это сообщение", "ContinueButton": "Продолжить", "CloseButton": "Закрыть", - "UploadingLabel": "Загружено файлов: {{file}} из {{totalFiles}}" + "UploadingLabel": "Загружено файлов: {{file}} из {{totalFiles}}", + "ConvertingLabel": "Сконвертировано файлов: {{file}} из {{totalFiles}}" } diff --git a/products/ASC.Files/Client/src/components/dialogs/DeleteDialog/index.js b/products/ASC.Files/Client/src/components/dialogs/DeleteDialog/index.js index 27ea5c5d6c..e4ce01fb27 100644 --- a/products/ASC.Files/Client/src/components/dialogs/DeleteDialog/index.js +++ b/products/ASC.Files/Client/src/components/dialogs/DeleteDialog/index.js @@ -14,10 +14,11 @@ import { api, utils, toastr } from "asc-web-common"; import { fetchFiles, setTreeFolders, - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, setUpdateTree, } from "../../../store/files/actions"; +import { TIMEOUT } from "../../../helpers/constants"; import { loopTreeFolders, getSelectedFolderId, @@ -66,8 +67,8 @@ class DeleteDialogComponent extends React.Component { treeFolders, setTreeFolders, isRecycleBinFolder, - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, t, fetchFiles, setUpdateTree, @@ -78,19 +79,23 @@ class DeleteDialogComponent extends React.Component { .then((res) => { const currentProcess = res.find((x) => x.id === id); if (currentProcess && currentProcess.progress !== 100) { - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "trash", percent: currentProcess.progress, label: t("DeleteOperation"), visible: true, + alert: false, }); setTimeout(() => this.loopDeleteOperation(id), 1000); } else { - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "trash", percent: 100, label: t("DeleteOperation"), visible: true, + alert: false, }); - setTimeout(() => clearProgressData(), 5000); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); fetchFiles(currentFolderId, filter).then((data) => { if (!isRecycleBinFolder && !!this.state.foldersList.length) { const path = data.selectedFolder.pathParts.slice(0); @@ -106,8 +111,12 @@ class DeleteDialogComponent extends React.Component { } }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); }; @@ -116,8 +125,8 @@ class DeleteDialogComponent extends React.Component { isRecycleBinFolder, onClose, t, - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, } = this.props; const { selection } = this.state; @@ -139,10 +148,12 @@ class DeleteDialogComponent extends React.Component { onClose(); if (folderIds.length || fileIds.length) { - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "trash", visible: true, label: t("DeleteOperation"), percent: 0, + alert: false, }); files @@ -152,8 +163,12 @@ class DeleteDialogComponent extends React.Component { this.loopDeleteOperation(id); }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); } }; @@ -289,8 +304,8 @@ const mapStateToProps = (state) => { export default connect(mapStateToProps, { setTreeFolders, - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, setUpdateTree, fetchFiles, })(withRouter(DeleteDialog)); diff --git a/products/ASC.Files/Client/src/components/dialogs/DownloadDialog/index.js b/products/ASC.Files/Client/src/components/dialogs/DownloadDialog/index.js index c4fa4d36fc..21ed484dfe 100644 --- a/products/ASC.Files/Client/src/components/dialogs/DownloadDialog/index.js +++ b/products/ASC.Files/Client/src/components/dialogs/DownloadDialog/index.js @@ -22,9 +22,10 @@ import { getSelection, } from "../../../store/files/selectors"; import { - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, } from "../../../store/files/actions"; +import { TIMEOUT } from "../../../helpers/constants"; import DownloadContent from "./DownloadContent"; import { createI18N } from "../../../helpers/i18n"; const i18n = createI18N({ @@ -178,8 +179,8 @@ class DownloadDialogComponent extends React.Component { onDownloadProgress, onClose, t, - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, } = this.props; const downloadItems = this.getDownloadItems(); @@ -187,10 +188,12 @@ class DownloadDialogComponent extends React.Component { const folderIds = downloadItems[1]; if (fileConvertIds.length || folderIds.length) { - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "file", visible: true, percent: 0, label: t("ArchivingData"), + alert: false, }); api.files .downloadFormatFiles(fileConvertIds, folderIds) @@ -199,8 +202,12 @@ class DownloadDialogComponent extends React.Component { onDownloadProgress(false); }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); } }; @@ -629,6 +636,6 @@ const mapStateToProps = (state) => { }; export default connect(mapStateToProps, { - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, })(withRouter(DownloadDialog)); diff --git a/products/ASC.Files/Client/src/components/dialogs/EmptyTrashDialog/index.js b/products/ASC.Files/Client/src/components/dialogs/EmptyTrashDialog/index.js index de0fd5e2eb..cf771dd2d2 100644 --- a/products/ASC.Files/Client/src/components/dialogs/EmptyTrashDialog/index.js +++ b/products/ASC.Files/Client/src/components/dialogs/EmptyTrashDialog/index.js @@ -7,9 +7,10 @@ import { withTranslation } from "react-i18next"; import { api, utils, toastr } from "asc-web-common"; import { fetchFiles, - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, } from "../../../store/files/actions"; +import { TIMEOUT } from "../../../helpers/constants"; import { getSelectedFolderId, getFilter, @@ -32,9 +33,9 @@ const EmptyTrashDialogComponent = (props) => { t, filter, currentFolderId, - setProgressBarData, + setSecondaryProgressBarData, isLoading, - clearProgressData, + clearSecondaryProgressData, fetchFiles, } = props; @@ -51,51 +52,65 @@ const EmptyTrashDialogComponent = (props) => { const currentProcess = res.find((x) => x.id === id); if (currentProcess && currentProcess.progress !== 100) { const newProgressData = { + icon: "trash", visible: true, percent: currentProcess.progress, label: t("DeleteOperation"), + alert: false, }; - setProgressBarData(newProgressData); + setSecondaryProgressBarData(newProgressData); setTimeout(() => loopEmptyTrash(id), 1000); } else { fetchFiles(currentFolderId, filter) .then(() => { - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "trash", visible: true, percent: 100, label: t("DeleteOperation"), + alert: false, }); - setTimeout(() => clearProgressData(), 5000); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); toastr.success(successMessage); }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); } }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); }, [ t, currentFolderId, filter, - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, fetchFiles, ] ); const onEmptyTrash = useCallback(() => { const newProgressData = { + icon: "trash", visible: true, percent: 0, label: t("DeleteOperation"), + alert: false, }; - setProgressBarData(newProgressData); + setSecondaryProgressBarData(newProgressData); onClose(); files .emptyTrash() @@ -104,10 +119,20 @@ const EmptyTrashDialogComponent = (props) => { loopEmptyTrash(id); }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); - }, [onClose, loopEmptyTrash, setProgressBarData, t, clearProgressData]); + }, [ + onClose, + loopEmptyTrash, + setSecondaryProgressBarData, + t, + clearSecondaryProgressData, + ]); return ( @@ -157,7 +182,7 @@ const mapStateToProps = (state) => { }; export default connect(mapStateToProps, { - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, fetchFiles, })(withRouter(EmptyTrashDialog)); diff --git a/products/ASC.Files/Client/src/components/pages/DocEditor/index.js b/products/ASC.Files/Client/src/components/pages/DocEditor/index.js index 322af39d71..7827b4e6b6 100644 --- a/products/ASC.Files/Client/src/components/pages/DocEditor/index.js +++ b/products/ASC.Files/Client/src/components/pages/DocEditor/index.js @@ -1,31 +1,24 @@ -import React, { useEffect } from "react"; +import React from "react"; import { withRouter } from "react-router"; import { /*RequestLoader,*/ Box } from "asc-web-components"; import { utils, api, toastr } from "asc-web-common"; -import { withTranslation, I18nextProvider } from "react-i18next"; -import { createI18N } from "../../../helpers/i18n"; -const i18n = createI18N({ - page: "DocEditor", - localesPath: "pages/DocEditor", -}); - -const { changeLanguage, getObjectByLocation, showLoader } = utils; -const { files } = api; +const { getObjectByLocation, showLoader } = utils; class PureEditor extends React.Component { async componentDidMount() { const urlParams = getObjectByLocation(window.location); const fileId = urlParams.fileId || null; + const doc = urlParams.doc || null; - console.log("PureEditor componentDidMount", fileId); + console.log("PureEditor componentDidMount", fileId, doc); const vh = window.innerHeight * 0.01; document.documentElement.style.setProperty("--vh", `${vh}px`); showLoader(); - let docApiUrl = await files.getDocServiceUrl(); + let docApiUrl = await api.files.getDocServiceUrl(); const script = document.createElement("script"); script.setAttribute("type", "text/javascript"); @@ -34,8 +27,8 @@ class PureEditor extends React.Component { script.onload = function () { console.log("PureEditor script.onload", fileId, window.DocsAPI); - files - .openEdit(fileId) + api.files + .openEdit(fileId, doc) .then((config) => { if (window.innerWidth < 720) { config.type = "mobile"; @@ -67,17 +60,4 @@ class PureEditor extends React.Component { } } -const EditorContainer = withTranslation()(PureEditor); - -const DocEditor = (props) => { - useEffect(() => { - changeLanguage(i18n); - }, []); - return ( - - - - ); -}; - -export default withRouter(DocEditor); +export default withRouter(PureEditor); diff --git a/products/ASC.Files/Client/src/components/pages/DocEditor/locales/en/translation.json b/products/ASC.Files/Client/src/components/pages/DocEditor/locales/en/translation.json deleted file mode 100644 index 752bdf5646..0000000000 --- a/products/ASC.Files/Client/src/components/pages/DocEditor/locales/en/translation.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "NewDocument": "New document", - "NewSpreadsheet": "New spreadsheet", - "NewPresentation": "New presentation", - "NewFolder": "New folder", - "UploadToFolder": "Upload to folder", - "SharingSettings": "Sharing settings", - "LinkForPortalUsers": "Link for portal users", - "MoveTo": "Move to", - "Copy": "Copy", - "Download": "Download", - "Rename": "Rename", - "Delete": "Delete", - "Type": "Type", - "Author": "Author", - "Search": "Search", - "Folders": "Folders", - "Document": "Document", - "Documents": "Documents", - "Spreadsheet": "Spreadsheet", - "Presentation": "Presentation", - "Presentations": "Presentations", - "Spreadsheets": "Spreadsheets", - "Images": "Images", - "Media": "Media", - "Archives": "Archives", - "AllFiles": "All files", - "NoSubfolders": "No subfolders", - "LoadingProcessing": "Loading...", - "LoadingDescription": "Please wait...", - "ByLastModifiedDate": "Last modified date", - "ByCreationDate": "Creation date", - "ByTitle": "Title", - "ByType": "Type", - "BySize": "Size", - "ByAuthor": "Author", - "DirectionAscLabel": "A-Z", - "DirectionDescLabel": "Z-A", - "CountPerPage": "{{count}} per page", - "PageOfTotalPage": "{{page}} of {{totalPage}}", - "PreviousPage": "Previous", - "NextPage": "Next", - "DefaultOptionLabel": "Me", - "LblSelect": "Select", - "AuthorMe": "Me", - "TitleCreated": "Created", - "TitleUploaded": "Uploaded", - "TitleModified": "Updated", - "TitleRemoved": "Removed", - "TitleSubfolders": "Flds", - "TitleDocuments": "Dcs", - "Share": "Share", - "DownloadAs": "Download as", - "More": "More", - "CloseButton": "Close", - "All": "All", - "Files": "Files", - "EmptyRecycleBin": "Empty Recycle Bin", - "Folder": "Folder", - "ClearButton": "Reset filter", - "SubheadingEmptyText": "No files to be displayed in this section", - "MyEmptyContainerDescription": "The documents and image files you create or upload to the portal are kept here in 'My Documents' section. You can open and edit them using the ONLYOFFICE™ portal editor, share them with friends or colleagues, organize into folders. Drag-and-drop the files from your computer here to upload them to your portal even more easily.", - "SharedEmptyContainerDescription": "The 'Shared with Me' section is used to show the files which your friends or colleagues gave you access to. In case you haven't seen the latest changes in the documents they are marked 'new'. You can remove the files from the list clicking the appropriate button.", - "CommonEmptyContainerDescription": "The 'Common Documents' section shows all the documents shared by portal administrator for common access. Only portal administrator can create folders in this section, but with the access granted the portal users can also upload their files here. Drag-and-drop the files from your computer here to upload them to your portal even more easily.", - "TrashEmptyContainerDescription": "The 'Recycle Bin' section is where all the deleted files are moved. You can either restore them in case they are deleted by mistake or delete them permanently. Please note, that when you delete the files from the 'Recycle Bin' they cannot be restored any longer.", - "GoToMyButton": "Go to My Documents", - "BackToParentFolderButton": "Back to parent folder", - "EmptyFolderHeader": "No files in this folder", - "EmptyFilterSubheadingText": "No files to be displayed for this filter here", - "EmptyFilterDescriptionText": "No files or folders matching your filter can be displayed in this section. Please select other filter options or clear filter to view all the files in this section. You can also look for the file you need in other sections.", - "Filter": "Filter" -} diff --git a/products/ASC.Files/Client/src/components/pages/DocEditor/locales/ru/translation.json b/products/ASC.Files/Client/src/components/pages/DocEditor/locales/ru/translation.json deleted file mode 100644 index d3fc39a153..0000000000 --- a/products/ASC.Files/Client/src/components/pages/DocEditor/locales/ru/translation.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "NewDocument": "Новый документ", - "NewSpreadsheet": "Новая таблица", - "NewPresentation": "Новая презентация", - "NewFolder": "Новая папка", - "UploadToFolder": "Загрузить в папку", - "SharingSettings": "Настройки доступа", - "LinkForPortalUsers": "Ссылка для пользователей портала", - "MoveTo": "Переместить", - "Copy": "Копировать", - "Download": "Скачать", - "Rename": "Переименовать", - "Delete": "Удалить", - "Type": "Тип", - "Author": "Автор", - "Search": "Поиск", - "Folders": "Папки", - "Document": "Документ", - "Documents": "Документы", - "Spreadsheet": "Таблица", - "Presentation": "Презентация", - "Presentations": "Презентации", - "Spreadsheets": "Таблицы", - "Images": "Изображения", - "Media": "Медиа", - "Archives": "Архивы", - "AllFiles": "Все файлы", - "NoSubfolders": "Без подпапок", - "LoadingProcessing": "Загрузка...", - "LoadingDescription": "Пожалуйста, подождите...", - "ByLastModifiedDate": "Дата последнего изменения", - "ByCreationDate": "Дата создания", - "ByTitle": "Название", - "ByType": "Тип", - "BySize": "Размер", - "ByAuthor": "Автор", - "DirectionAscLabel": "А-Я", - "DirectionDescLabel": "Я-А", - "CountPerPage": "{{count}} на странице", - "PageOfTotalPage": "{{page}} из {{totalPage}}", - "PreviousPage": "Предыдущая", - "NextPage": "Следующая", - "DefaultOptionLabel": "Я", - "LblSelect": "Выберите", - "AuthorMe": "Я", - "TitleCreated": "Создана", - "TitleUploaded": "Загружен", - "TitleModified": "Обновлён", - "TitleRemoved": "Удалён", - "TitleSubfolders": "Flds", - "TitleDocuments": "Dcs", - "Share": "Доступ", - "DownloadAs": "Скачать как", - "More": "Больше", - "CloseButton": "Закрыть", - "All": "Все", - "Files": "Файлы", - "EmptyRecycleBin": "Очистить корзину", - "Folder": "Папка", - "ClearButton": "Сбросить фильтр", - "SubheadingEmptyText": "Нет файлов для отображения в этом разделе", - "MyEmptyContainerDescription": "Документы и файлы изображений, которые вы создаете или загружаете на портал, хранятся здесь, в разделе «Мои документы». Вы можете открывать и редактировать их с помощью редактора портала ONLYOFFICE ™, делиться ими с друзьями или коллегами, организовывать в папки. Перетащите файлы со своего компьютера сюда, чтобы загрузить их на свой портал еще проще.", - "SharedEmptyContainerDescription": "Раздел «Доступно для меня» используется для отображения файлов, к которым ваши друзья или коллеги предоставили вам доступ. Если вы не видели последние изменения в документах, они помечаются как «новые». Вы можете удалить файлы из списка, нажав соответствующую кнопку.", - "CommonEmptyContainerDescription": "В разделе «Общие документы» отображаются все документы, которыми администратор портала предоставил общий доступ. Только администраторы портала могут создавать папки в этом разделе, но с предоставленным доступом пользователи портала также могут загружать свои файлы здесь. Перетащите файлы со своего компьютера сюда, чтобы загрузить их на свой портал еще проще.", - "TrashEmptyContainerDescription": "В разделе «Корзина» находятся все удаленные файлы. Вы можете восстановить их, если они были удалены по ошибке, или удалить их навсегда. Обратите внимание, что когда вы удаляете файлы из корзины, они больше не могут быть восстановлены.", - "GoToMyButton": "Перейти к моим документам", - "BackToParentFolderButton": "Вернуться в папку на уровень выше", - "EmptyFolderHeader": "В этой папке нет файлов", - "EmptyFilterSubheadingText": "Здесь нет файлов, соответствующих этому фильтру", - "EmptyFilterDescriptionText": "В этом разделе нет файлов или папок, соответствующих фильтру. Пожалуйста, выберите другие параметры или очистите фильтр, чтобы показать все файлы в этом разделе. Вы можете также поискать нужный файл в других разделах.", - "Filter": "Фильтр" -} diff --git a/products/ASC.Files/Client/src/components/pages/Home/Section/Body/FilesRowContent.js b/products/ASC.Files/Client/src/components/pages/Home/Section/Body/FilesRowContent.js index 7902e72ef1..87cfdf9d40 100644 --- a/products/ASC.Files/Client/src/components/pages/Home/Section/Body/FilesRowContent.js +++ b/products/ASC.Files/Client/src/components/pages/Home/Section/Body/FilesRowContent.js @@ -13,18 +13,19 @@ import { } from "asc-web-components"; import { constants, api, toastr, store as initStore } from "asc-web-common"; import { - clearProgressData, + clearSecondaryProgressData, createFile, createFolder, fetchFiles, renameFolder, setIsLoading, setNewRowItems, - setProgressBarData, + setSecondaryProgressBarData, setTreeFolders, setUpdateTree, updateFile, } from "../../../../../store/files/actions"; +import { TIMEOUT } from "../../../../../helpers/constants"; import { canConvert, canWebEdit, @@ -357,33 +358,48 @@ class FilesRowContent extends React.PureComponent { selectedFolder, filter, setIsLoading, - setProgressBarData, + setSecondaryProgressBarData, t, - clearProgressData, + clearSecondaryProgressData, fetchFiles, } = this.props; - api.files.getConvertFile(fileId).then((res) => { + api.files.getFileConversationProgress(fileId).then((res) => { if (res && res[0] && res[0].progress !== 100) { - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "file", visible: true, percent: res[0].progress, label: t("Convert"), + alert: false, }); setTimeout(() => this.getConvertProgress(fileId), 1000); } else { if (res[0].error) { + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); toastr.error(res[0].error); - clearProgressData(); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); } else { - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "file", visible: true, percent: 100, label: t("Convert"), + alert: false, }); - setTimeout(() => clearProgressData(), 5000); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); const newFilter = filter.clone(); fetchFiles(selectedFolder.id, newFilter) - .catch((err) => toastr.error(err)) + .catch((err) => { + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); + }) .finally(() => setIsLoading(false)); } } @@ -391,8 +407,14 @@ class FilesRowContent extends React.PureComponent { }; onConvert = () => { - const { item, t, setProgressBarData } = this.props; - setProgressBarData({ visible: true, percent: 0, label: t("Convert") }); + const { item, t, setSecondaryProgressBarData } = this.props; + setSecondaryProgressBarData({ + icon: "file", + visible: true, + percent: 0, + label: t("Convert"), + alert: false, + }); this.setState({ showConvertDialog: false }, () => api.files.convertFile(item.id).then((convertRes) => { if (convertRes && convertRes[0] && convertRes[0].progress !== 100) { @@ -509,7 +531,7 @@ class FilesRowContent extends React.PureComponent { > {fileExst} - {canConvert && !isTrashFolder && ( + {/* TODO: Uncomment after fix conversation {canConvert && !isTrashFolder && ( - )} + )} */} {canWebEdit && !isTrashFolder && ( { - const { t, setProgressBarData, clearProgressData } = this.props; - setProgressBarData({ + const { + t, + setSecondaryProgressBarData, + clearSecondaryProgressData, + } = this.props; + setSecondaryProgressBarData({ + icon: "trash", visible: true, percent: 0, label: t("DeleteOperation"), + alert: false, }); api.files .deleteFile(fileId) @@ -396,8 +404,12 @@ class SectionBodyContent extends React.Component { this.loopDeleteProgress(id, currentFolderId, false); }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); }; @@ -408,24 +420,28 @@ class SectionBodyContent extends React.Component { setTreeFolders, isRecycleBin, t, - setProgressBarData, + setSecondaryProgressBarData, fetchFiles, setUpdateTree, } = this.props; api.files.getProgress().then((res) => { const deleteProgress = res.find((x) => x.id === id); if (deleteProgress && deleteProgress.progress !== 100) { - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "trash", visible: true, percent: deleteProgress.progress, label: t("DeleteOperation"), + alert: false, }); setTimeout(() => this.loopDeleteProgress(id, folderId, isFolder), 1000); } else { - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "trash", visible: true, percent: 100, label: t("DeleteOperation"), + alert: false, }); fetchFiles(folderId, filter) .then((data) => { @@ -443,20 +459,34 @@ class SectionBodyContent extends React.Component { : toastr.success(`File moved to recycle bin`); }) .catch((err) => { - toastr.error(err); - this.props.clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => this.props.clearSecondaryProgressData(), TIMEOUT); }) .finally(() => - setTimeout(() => this.props.clearProgressData(), 5000) + setTimeout(() => this.props.clearSecondaryProgressData(), TIMEOUT) ); } }); }; onDeleteFolder = (folderId, currentFolderId) => { - const { t, setProgressBarData, clearProgressData } = this.props; + const { + t, + setSecondaryProgressBarData, + clearSecondaryProgressData, + } = this.props; const progressLabel = t("DeleteOperation"); - setProgressBarData({ visible: true, percent: 0, label: progressLabel }); + setSecondaryProgressBarData({ + icon: "trash", + visible: true, + percent: 0, + label: progressLabel, + alert: false, + }); api.files .deleteFolder(folderId, currentFolderId) .then((res) => { @@ -464,13 +494,17 @@ class SectionBodyContent extends React.Component { this.loopDeleteProgress(id, currentFolderId, true); }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); }; onClickShare = () => - this.setState({ showSharingPanel: !this.state.showSharingPanel }); + this.props.setSharingPanelVisible(!this.props.sharingPanelVisible); onClickLinkForPortal = () => { const { settings, selection } = this.props; @@ -566,7 +600,12 @@ class SectionBodyContent extends React.Component { onCopyAction = () => this.setState({ showCopyPanel: !this.state.showCopyPanel }); onDuplicate = () => { - const { selection, selectedFolderId, setProgressBarData, t } = this.props; + const { + selection, + selectedFolderId, + setSecondaryProgressBarData, + t, + } = this.props; const folderIds = []; const fileIds = []; selection[0].fileExst @@ -575,10 +614,12 @@ class SectionBodyContent extends React.Component { const conflictResolveType = 0; //Skip = 0, Overwrite = 1, Duplicate = 2 const deleteAfter = false; - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "duplicate", visible: true, percent: 0, label: t("CopyOperation"), + alert: false, }); this.copyTo( selectedFolderId, @@ -775,7 +816,7 @@ class SectionBodyContent extends React.Component { if (currentProps.sectionWidth !== nextProps.sectionWidth) { return true; } - if (!isEqual(currentProps.data, nextProps.data)) { + if (!equal(currentProps.data, nextProps.data)) { return true; } if (currentProps.viewAs !== nextProps.viewAs) { @@ -1325,17 +1366,19 @@ class SectionBodyContent extends React.Component { isShare, isCommon, isAdmin, - setProgressBarData, + setSecondaryProgressBarData, } = this.props; const folderIds = []; const fileIds = []; const conflictResolveType = 0; //Skip = 0, Overwrite = 1, Duplicate = 2 const deleteAfter = true; - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "move", visible: true, percent: 0, label: t("MoveToOperation"), + alert: false, }); for (let item of selection) { if (item.fileExst) { @@ -1391,7 +1434,7 @@ class SectionBodyContent extends React.Component { conflictResolveType, deleteAfter ) => { - const { loopFilesOperations, clearProgressData } = this.props; + const { loopFilesOperations, clearSecondaryProgressData } = this.props; api.files .copyToFolder( @@ -1406,8 +1449,12 @@ class SectionBodyContent extends React.Component { loopFilesOperations(id, destFolderId, true); }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); }; @@ -1418,7 +1465,7 @@ class SectionBodyContent extends React.Component { conflictResolveType, deleteAfter ) => { - const { loopFilesOperations, clearProgressData } = this.props; + const { loopFilesOperations, clearSecondaryProgressData } = this.props; api.files .moveToFolder( @@ -1433,8 +1480,12 @@ class SectionBodyContent extends React.Component { loopFilesOperations(id, destFolderId, false); }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); }; @@ -1516,7 +1567,7 @@ class SectionBodyContent extends React.Component { }; render() { - console.log("Files Home SectionBodyContent render", this.props); + //console.log("Files Home SectionBodyContent render", this.props); const { viewer, @@ -1545,12 +1596,7 @@ class SectionBodyContent extends React.Component { } = this.props; console.log("Files Home SectionBodyContent render", this.props); - const { - editingId, - showSharingPanel, - showMoveToPanel, - showCopyPanel, - } = this.state; + const { editingId, showMoveToPanel, showCopyPanel } = this.state; const operationsPanelProps = { setIsLoading, @@ -1707,7 +1753,11 @@ class SectionBodyContent extends React.Component { ) : ( {(context) => ( - + {items.map((item) => { const { checked, isFolder, value, contextOptions } = item; const sectionWidth = context.sectionWidth; @@ -1810,12 +1860,6 @@ class SectionBodyContent extends React.Component { extsImagePreviewed={mediaViewerImageFormats} //TODO /> )} - {showSharingPanel && ( - - )} ); } @@ -1865,6 +1909,7 @@ const mapStateToProps = (state) => { viewer: getCurrentUser(state), tooltipValue: getTooltipLabel(state), iconOfDraggedFile: getIconOfDraggedFile(state)(state), + sharingPanelVisible: getSharePanelVisible(state), }; }; @@ -1878,16 +1923,17 @@ export default connect(mapStateToProps, { setDragging, setDragItem, setMediaViewerData, - setProgressBarData, + setSecondaryProgressBarData, setSelection, setSelected, setUpdateTree, setIsLoading, - clearProgressData, + clearSecondaryProgressData, markItemAsFavorite, removeItemFromFavorite, fetchFavoritesFolder, getFileInfo, addFileToRecentlyViewed, loopFilesOperations, + setSharingPanelVisible, })(withRouter(withTranslation()(SectionBodyContent))); diff --git a/products/ASC.Files/Client/src/components/pages/Home/Section/Filter/index.js b/products/ASC.Files/Client/src/components/pages/Home/Section/Filter/index.js index 7f7ceee278..fb4c01c056 100644 --- a/products/ASC.Files/Client/src/components/pages/Home/Section/Filter/index.js +++ b/products/ASC.Files/Client/src/components/pages/Home/Section/Filter/index.js @@ -17,7 +17,7 @@ import result from "lodash/result"; import { withTranslation } from "react-i18next"; import { withRouter } from "react-router"; import { constants, FilterInput, store, Loaders, utils } from "asc-web-common"; -import isEqual from "lodash/isEqual"; +import equal from "fast-deep-equal/react"; import { isMobileOnly } from "react-device-detect"; const { withLayoutSize } = utils; @@ -285,7 +285,7 @@ class SectionFilterContent extends React.Component { shouldComponentUpdate(nextProps, nextState) { return ( - !isEqual(this.props.filter, nextProps.filter) || + !equal(this.props.filter, nextProps.filter) || this.props.selectedFolderId !== nextProps.selectedFolderId || this.state.isReady !== nextState.isReady || this.props.viewAs !== nextProps.viewAs || @@ -295,7 +295,7 @@ class SectionFilterContent extends React.Component { } render() { - console.log("Filter render"); + //console.log("Filter render"); const selectedFilterData = this.getSelectedFilterData(); const { t, language, firstLoad, sectionWidth } = this.props; const filterColumnCount = diff --git a/products/ASC.Files/Client/src/components/pages/Home/Section/Header/index.js b/products/ASC.Files/Client/src/components/pages/Home/Section/Header/index.js index d78f0268b3..f9fe940b4a 100644 --- a/products/ASC.Files/Client/src/components/pages/Home/Section/Header/index.js +++ b/products/ASC.Files/Client/src/components/pages/Home/Section/Header/index.js @@ -22,17 +22,19 @@ import { import { fetchFiles, setAction, - setProgressBarData, - clearProgressData, + setSecondaryProgressBarData, + clearSecondaryProgressData, setIsLoading, setSelected, + setSharingPanelVisible, } from "../../../../../store/files/actions"; +import { TIMEOUT } from "../../../../../helpers/constants"; import { EmptyTrashDialog, DeleteDialog, DownloadDialog, } from "../../../../dialogs"; -import { SharingPanel, OperationsPanel } from "../../../../panels"; +import { OperationsPanel } from "../../../../panels"; import { isCanBeDeleted, getIsRecycleBinFolder, @@ -48,6 +50,8 @@ import { getHeaderChecked, getOnlyFoldersSelected, getAccessedSelected, + getSelectionLength, + getSharePanelVisible, } from "../../../../../store/files/selectors"; const { isAdmin } = store.auth.selectors; @@ -56,21 +60,27 @@ const { tablet, desktop } = utils.device; const { Consumer } = utils.context; const StyledContainer = styled.div` - @media ${desktop} { - ${(props) => - props.isHeaderVisible && - css` - width: calc(100% + 76px); - `} - } - .header-container { position: relative; - display: flex; + display: grid; + grid-template-columns: ${(props) => + props.isRootFolder + ? "auto auto 1fr" + : props.canCreate + ? "auto auto auto auto 1fr" + : "auto auto auto 1fr"}; + align-items: center; max-width: calc(100vw - 32px); @media ${tablet} { + grid-template-columns: ${(props) => + props.isRootFolder + ? "1fr auto" + : props.canCreate + ? "auto 1fr auto auto" + : "auto 1fr auto"}; + .headline-header { margin-left: -1px; } @@ -159,7 +169,6 @@ class SectionHeaderContent extends React.Component { super(props); this.state = { - showSharingPanel: false, showDeleteDialog: false, showDownloadDialog: false, showEmptyTrashDialog: false, @@ -242,25 +251,36 @@ class SectionHeaderContent extends React.Component { .getProgress() .then((res) => { if (!url) { - this.props.setProgressBarData({ + this.props.setSecondaryProgressBarData({ + icon: "file", visible: true, percent: res[0].progress, label: this.props.t("ArchivingData"), + alert: false, }); setTimeout(() => this.loop(res[0].url), 1000); } else { - setTimeout(() => this.props.clearProgressData(), 5000); + setTimeout(() => this.props.clearSecondaryProgressData(), TIMEOUT); return window.open(url, "_blank"); } }) .catch((err) => { - toastr.error(err); - this.props.clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => this.props.clearSecondaryProgressData(), TIMEOUT); }); }; downloadAction = () => { - const { t, selection, setProgressBarData, clearProgressData } = this.props; + const { + t, + selection, + setSecondaryProgressBarData, + clearSecondaryProgressData, + } = this.props; const fileIds = []; const folderIds = []; const items = []; @@ -275,10 +295,12 @@ class SectionHeaderContent extends React.Component { } } - setProgressBarData({ + setSecondaryProgressBarData({ + icon: "file", visible: true, percent: 0, label: t("ArchivingData"), + alert: false, }); api.files @@ -287,8 +309,12 @@ class SectionHeaderContent extends React.Component { this.loop(res[0].url); }) .catch((err) => { - toastr.error(err); - clearProgressData(); + setSecondaryProgressBarData({ + visible: true, + alert: true, + }); + //toastr.error(err); + setTimeout(() => clearSecondaryProgressData(), TIMEOUT); }); }; @@ -298,7 +324,7 @@ class SectionHeaderContent extends React.Component { renameAction = () => toastr.info("renameAction click"); onOpenSharingPanel = () => - this.setState({ showSharingPanel: !this.state.showSharingPanel }); + this.props.setSharingPanelVisible(!this.props.sharingPanelVisible); onDeleteAction = () => this.setState({ showDeleteDialog: !this.state.showDeleteDialog }); @@ -501,7 +527,6 @@ class SectionHeaderContent extends React.Component { const { showDeleteDialog, - showSharingPanel, showEmptyTrashDialog, showDownloadDialog, showMoveToPanel, @@ -514,8 +539,9 @@ class SectionHeaderContent extends React.Component { {(context) => ( {isHeaderVisible ? (
@@ -617,13 +643,6 @@ class SectionHeaderContent extends React.Component { /> )} - {showSharingPanel && ( - - )} - {showMoveToPanel && ( { - const selection = getSelection(state); - return { isRootFolder: getIsRootFolder(state), isAdmin: isAdmin(state), isRecycleBin: getIsRecycleBinFolder(state), parentId: getSelectedFolderParentId(state), - selection, + selection: getSelection(state), title: getSelectedFolderTitle(state), filter: getFilter(state), deleteDialogVisible: isCanBeDeleted(state), @@ -673,15 +690,17 @@ const mapStateToProps = (state) => { isHeaderChecked: getHeaderChecked(state), isAccessedSelected: getAccessedSelected(state), isOnlyFoldersSelected: getOnlyFoldersSelected(state), - isItemsSelected: selection.length, + isItemsSelected: getSelectionLength(state), + sharingPanelVisible: getSharePanelVisible(state), }; }; export default connect(mapStateToProps, { setAction, - setProgressBarData, + setSecondaryProgressBarData, setIsLoading, - clearProgressData, + clearSecondaryProgressData, fetchFiles, setSelected, + setSharingPanelVisible, })(withTranslation()(withRouter(SectionHeaderContent))); diff --git a/products/ASC.Files/Client/src/components/pages/Home/index.js b/products/ASC.Files/Client/src/components/pages/Home/index.js index a7ab810962..e92143d5ef 100644 --- a/products/ASC.Files/Client/src/components/pages/Home/index.js +++ b/products/ASC.Files/Client/src/components/pages/Home/index.js @@ -31,17 +31,20 @@ import { getSelectedFolderId, getFileActionId, getFilter, - getProgressData, + getPrimaryProgressData, + getSecondaryProgressData, getTreeFolders, getViewAs, getIsLoading, getIsRecycleBinFolder, getDragging, getHeaderVisible, + getSharePanelVisible, getFirstLoad, } from "../../../store/files/selectors"; import { ConvertDialog } from "../../dialogs"; +import { SharingPanel } from "../../panels"; import { createI18N } from "../../../helpers/i18n"; import { getFilterByLocation } from "../../../helpers/converters"; const i18n = createI18N({ @@ -50,7 +53,7 @@ const i18n = createI18N({ }); const { changeLanguage } = utils; const { FilesFilter } = api; -const { getSettingsHomepage, getIsLoaded } = store.auth.selectors; +const { getSettingsHomepage } = store.auth.selectors; const { setHeaderVisible } = store.auth.actions; class PureHome extends React.Component { componentDidMount() { @@ -140,7 +143,7 @@ class PureHome extends React.Component { if (filter) { const folderId = filter.folder; - console.log("filter", filter); + //console.log("filter", filter); return fetchFiles(folderId, filter); } @@ -181,14 +184,16 @@ class PureHome extends React.Component { } render() { - console.log("Home render"); + //console.log("Home render"); const { - progressData, + primaryProgressData, + secondaryProgressData, viewAs, convertDialogVisible, + sharingPanelVisible, fileActionId, isRecycleBin, - isLoaded, + firstLoad, isHeaderVisible, } = this.props; @@ -197,6 +202,8 @@ class PureHome extends React.Component { {convertDialogVisible && ( )} + + {sharingPanelVisible && } @@ -273,13 +288,15 @@ function mapStateToProps(state) { fileActionId: getFileActionId(state), filter: getFilter(state), isRecycleBin: getIsRecycleBinFolder(state), - progressData: getProgressData(state), + primaryProgressData: getPrimaryProgressData(state), + secondaryProgressData: getSecondaryProgressData(state), treeFolders: getTreeFolders(state), viewAs: getViewAs(state), isLoading: getIsLoading(state), homepage: getSettingsHomepage(state), dragging: getDragging(state), - isLoaded: getIsLoaded(state), + firstLoad: getFirstLoad(state), + sharingPanelVisible: getSharePanelVisible(state), firstLoad: getFirstLoad(state), isHeaderVisible: getHeaderVisible(state), }; diff --git a/products/ASC.Files/Client/src/components/pages/VersionHistory/Section/Header/index.js b/products/ASC.Files/Client/src/components/pages/VersionHistory/Section/Header/index.js index 77cd0cdacf..0a07fb4a82 100644 --- a/products/ASC.Files/Client/src/components/pages/VersionHistory/Section/Header/index.js +++ b/products/ASC.Files/Client/src/components/pages/VersionHistory/Section/Header/index.js @@ -10,7 +10,8 @@ const { tablet, desktop } = utils.device; const { getSettings } = store.auth.selectors; const StyledContainer = styled.div` - display: flex; + display: grid; + grid-template-columns: auto 1fr auto auto; align-items: center; .arrow-button { @@ -24,14 +25,6 @@ const StyledContainer = styled.div` } } - @media ${desktop} { - ${(props) => - props.isHeaderVisible && - css` - width: calc(100% + 76px); - `} - } - .group-button-menu-container { margin: 0 -16px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); @@ -85,7 +78,7 @@ const SectionHeaderContent = (props) => { }; return ( - + - {t("Size")}: -
- - 600 x 800 px - - - 400 x 600 px - - - {t("Auto")} - -
-
-
- {t("Width")}: - +
+ {t("Size")}: +
+ + 600 x 800 px + + + 400 x 600 px + + + {t("Auto")} +
-
- {t("Height")}: - +
+
+ {t("Width")}: + +
+
+ {t("Height")}: + +
+
+
+ + {t("EmbedCode")}: + + +