Merge branch 'develop' into feature/integration-system
This commit is contained in:
commit
81a62b4b2a
38
build/scripts/minify-common-locales.js
Normal file
38
build/scripts/minify-common-locales.js
Normal file
@ -0,0 +1,38 @@
|
||||
const { join } = require("path");
|
||||
const { readdirSync, readFileSync, writeFileSync } = require("fs");
|
||||
const minifyJson = require("../../packages/asc-web-common/utils/minifyJson.js");
|
||||
|
||||
const localesDir = join(
|
||||
__dirname,
|
||||
"../../build",
|
||||
"deploy",
|
||||
"public",
|
||||
"locales"
|
||||
);
|
||||
|
||||
const getFileList = (dirName) => {
|
||||
let files = [];
|
||||
const items = readdirSync(dirName, { withFileTypes: true });
|
||||
|
||||
for (const item of items) {
|
||||
if (item.isDirectory()) {
|
||||
files = [...files, ...getFileList(`${dirName}/${item.name}`)];
|
||||
} else {
|
||||
files.push(`${dirName}/${item.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
const files = getFileList(localesDir);
|
||||
|
||||
files.forEach((filePath) => {
|
||||
try {
|
||||
let content = readFileSync(filePath);
|
||||
writeFileSync(filePath, minifyJson(content, filePath));
|
||||
//console.log(`File '${filePath}' minified`);
|
||||
} catch (e) {
|
||||
console.error("Unable to minify file ", filePath, e);
|
||||
}
|
||||
});
|
@ -24,6 +24,7 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
global using System.Collections.Concurrent;
|
||||
global using System.ComponentModel;
|
||||
global using System.Globalization;
|
||||
global using System.Linq.Expressions;
|
||||
@ -69,8 +70,8 @@ global using ASC.EventBus;
|
||||
global using ASC.EventBus.Abstractions;
|
||||
global using ASC.EventBus.RabbitMQ;
|
||||
global using ASC.IPSecurity;
|
||||
global using ASC.MessagingSystem.Data;
|
||||
global using ASC.MessagingSystem.Core;
|
||||
global using ASC.MessagingSystem.Data;
|
||||
global using ASC.MessagingSystem.Models;
|
||||
global using ASC.Security.Cryptography;
|
||||
global using ASC.Web.Api.Routing;
|
||||
@ -83,6 +84,8 @@ global using ASC.Webhooks.Core;
|
||||
global using Autofac;
|
||||
global using Autofac.Extensions.DependencyInjection;
|
||||
|
||||
global using AutoMapper;
|
||||
|
||||
global using Confluent.Kafka;
|
||||
|
||||
global using HealthChecks.UI.Client;
|
||||
@ -123,8 +126,6 @@ global using NLog.Extensions.Logging;
|
||||
|
||||
global using RabbitMQ.Client;
|
||||
|
||||
global using AutoMapper;
|
||||
|
||||
global using StackExchange.Redis.Extensions.Core.Configuration;
|
||||
global using StackExchange.Redis.Extensions.Newtonsoft;
|
||||
|
||||
|
@ -43,7 +43,7 @@ public class PaymentFilter : IResourceFilter
|
||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||
{
|
||||
if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor
|
||||
&& !controllerActionDescriptor.EndpointMetadata.OfType<AllowNotPaymentAttribute>().Any())
|
||||
&& controllerActionDescriptor.EndpointMetadata.OfType<AllowNotPaymentAttribute>().Any())
|
||||
{
|
||||
_logger.DebugPaymentIsNotRequired();
|
||||
|
||||
|
@ -55,6 +55,7 @@ public class EmployeeDtoHelper
|
||||
private readonly ApiContext _httpContext;
|
||||
private readonly DisplayUserSettingsHelper _displayUserSettingsHelper;
|
||||
private readonly CommonLinkUtility _commonLinkUtility;
|
||||
private readonly ConcurrentDictionary<Guid, EmployeeDto> _concurrentDictionary;
|
||||
|
||||
public EmployeeDtoHelper(
|
||||
ApiContext httpContext,
|
||||
@ -67,12 +68,13 @@ public class EmployeeDtoHelper
|
||||
_userManager = userManager;
|
||||
_httpContext = httpContext;
|
||||
_displayUserSettingsHelper = displayUserSettingsHelper;
|
||||
_commonLinkUtility = commonLinkUtility;
|
||||
_commonLinkUtility = commonLinkUtility;
|
||||
_concurrentDictionary = new ConcurrentDictionary<Guid, EmployeeDto>();
|
||||
}
|
||||
|
||||
public EmployeeDto Get(UserInfo userInfo)
|
||||
{
|
||||
return Init(new EmployeeDto(), userInfo);
|
||||
return _concurrentDictionary.GetOrAdd(userInfo.Id, (id) => Init(new EmployeeDto(), userInfo));
|
||||
}
|
||||
|
||||
public EmployeeDto Get(Guid userId)
|
||||
|
@ -61,7 +61,7 @@ public class EmailValidationKeyModelHelper
|
||||
request.TryGetValue("type", out var type);
|
||||
|
||||
ConfirmType? cType = null;
|
||||
if (Enum.TryParse<ConfirmType>(type, out var confirmType))
|
||||
if (ConfirmTypeExtensions.TryParse(type, out var confirmType))
|
||||
{
|
||||
cType = confirmType;
|
||||
}
|
||||
@ -69,7 +69,7 @@ public class EmailValidationKeyModelHelper
|
||||
request.TryGetValue("key", out var key);
|
||||
|
||||
request.TryGetValue("emplType", out var emplType);
|
||||
Enum.TryParse<EmployeeType>(emplType, out var employeeType);
|
||||
EmployeeTypeExtensions.TryParse(emplType, out var employeeType);
|
||||
|
||||
request.TryGetValue("email", out var _email);
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Primitives" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="6.0.0" />
|
||||
<PackageReference Include="EtaEmre.NetEscapades.EnumGenerators" Version="1.0.0-beta07" />
|
||||
<!-- <PackageReference Include="Microsoft.CodeQuality.Analyzers" Version="2.9.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
@ -36,7 +36,7 @@ global using System.Runtime.CompilerServices;
|
||||
global using System.Runtime.Loader;
|
||||
global using System.Runtime.Serialization;
|
||||
global using System.Security.Cryptography;
|
||||
global using System.Security.Principal;
|
||||
global using System.Security.Principal;
|
||||
global using System.ServiceModel;
|
||||
global using System.Text;
|
||||
global using System.Text.RegularExpressions;
|
||||
@ -92,6 +92,8 @@ global using Microsoft.Extensions.Options;
|
||||
global using Microsoft.Extensions.Primitives;
|
||||
global using Microsoft.Net.Http.Headers;
|
||||
|
||||
global using NetEscapades.EnumGenerators;
|
||||
|
||||
global using Newtonsoft.Json;
|
||||
global using Newtonsoft.Json.Serialization;
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
namespace ASC.Common.Security.Authorizing;
|
||||
|
||||
[EnumExtensions]
|
||||
public enum AceType
|
||||
{
|
||||
Allow,
|
||||
|
@ -70,7 +70,7 @@ public class AzRecord : IMapFrom<Acl>
|
||||
|
||||
result.Object = cache.ObjectId;
|
||||
|
||||
if (Enum.TryParse<AceType>(cache.Reaction, out var reaction))
|
||||
if (AceTypeExtensions.TryParse(cache.Reaction, out var reaction))
|
||||
{
|
||||
result.AceType = reaction;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ namespace ASC.Core.Users;
|
||||
|
||||
[Flags]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
[EnumExtensions]
|
||||
public enum EmployeeType
|
||||
{
|
||||
All = 0,
|
||||
|
@ -73,7 +73,7 @@ public class UserGroupRef : IMapFrom<UserGroup>
|
||||
GroupId = new Guid(cache.GroupId)
|
||||
};
|
||||
|
||||
if (Enum.TryParse<UserGroupRefType>(cache.RefType, out var refType))
|
||||
if (UserGroupRefTypeExtensions.TryParse(cache.RefType, out var refType))
|
||||
{
|
||||
result.RefType = refType;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
namespace ASC.Core;
|
||||
|
||||
[EnumExtensions]
|
||||
public enum UserGroupRefType
|
||||
{
|
||||
Contains,
|
||||
|
@ -34,7 +34,7 @@ global using System.Diagnostics;
|
||||
global using System.Globalization;
|
||||
global using System.Linq;
|
||||
global using System.Linq.Expressions;
|
||||
global using System.Net;
|
||||
global using System.Net;
|
||||
global using System.Net.Http.Headers;
|
||||
global using System.Reflection;
|
||||
global using System.Resources;
|
||||
@ -148,6 +148,8 @@ global using Microsoft.Extensions.Options;
|
||||
|
||||
global using MimeKit;
|
||||
|
||||
global using NetEscapades.EnumGenerators;
|
||||
|
||||
global using Newtonsoft.Json;
|
||||
|
||||
global using NVelocity;
|
||||
|
@ -25,7 +25,8 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
namespace ASC.MessagingSystem.Core;
|
||||
|
||||
|
||||
[EnumExtensions]
|
||||
public enum MessageAction
|
||||
{
|
||||
None = -1,
|
||||
@ -462,20 +463,20 @@ public enum MessageAction
|
||||
|
||||
FolderMarkedAsRead = 5065,
|
||||
|
||||
RoomCreated = 5066,
|
||||
RoomRenamed = 5067,
|
||||
RoomArchived = 5068,
|
||||
RoomUnarchived = 5069,
|
||||
RoomDeleted = 5070,
|
||||
RoomUpdateAccess = 5071,
|
||||
RoomCreated = 5070,
|
||||
RoomRenamed = 5071,
|
||||
RoomArchived = 5072,
|
||||
RoomUnarchived = 5073,
|
||||
RoomDeleted = 5074,
|
||||
RoomUpdateAccess = 5075,
|
||||
|
||||
TagCreated = 5072,
|
||||
TagsDeleted = 5073,
|
||||
AddedRoomTags = 5074,
|
||||
DeletedRoomTags = 5075,
|
||||
TagCreated = 5076,
|
||||
TagsDeleted = 5077,
|
||||
AddedRoomTags = 5078,
|
||||
DeletedRoomTags = 5079,
|
||||
|
||||
RoomLogoCreated = 5076,
|
||||
RoomLogoDeleted = 5077,
|
||||
RoomLogoCreated = 5080,
|
||||
RoomLogoDeleted = 5081,
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -413,10 +413,10 @@ public class NotifyEngine : INotifyEngine, IDisposable
|
||||
|
||||
request.CurrentMessage = noticeMessage;
|
||||
var preventresponse = CheckPreventInterceptors(request, InterceptorPlace.MessageSend, serviceScope, channel.SenderName);
|
||||
if (preventresponse != null)
|
||||
{
|
||||
return preventresponse;
|
||||
}
|
||||
if (preventresponse != null)
|
||||
{
|
||||
return preventresponse;
|
||||
}
|
||||
|
||||
channel.SendAsync(noticeMessage);
|
||||
|
||||
|
@ -35,6 +35,7 @@ namespace ASC.Web.Studio.Utility;
|
||||
// portal-remove - confirm portal deletation - Tenant.SetStatus(TenantStatus.RemovePending)
|
||||
// DnsChange - change Portal Address and/or Custom domain name
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
[EnumExtensions]
|
||||
public enum ConfirmType
|
||||
{
|
||||
EmpInvite,
|
||||
|
@ -37,7 +37,7 @@ global using System.Security.Cryptography.X509Certificates;
|
||||
global using System.Text;
|
||||
global using System.Text.Json.Serialization;
|
||||
global using System.Web;
|
||||
global using System.Xml.XPath;
|
||||
global using System.Xml.XPath;
|
||||
|
||||
global using ASC.Common;
|
||||
global using ASC.Common.Caching;
|
||||
|
@ -905,6 +905,7 @@
|
||||
"авторизацията",
|
||||
"Азърбайджан",
|
||||
"Азърбайджански",
|
||||
"Вер",
|
||||
"Двуфакторно",
|
||||
"Двуфакторното",
|
||||
"др",
|
||||
@ -1155,6 +1156,7 @@
|
||||
"Thumbnails",
|
||||
"usw",
|
||||
"Verbindungs-URL",
|
||||
"Ver",
|
||||
"White",
|
||||
"XLSX-Format",
|
||||
"ZIP-Datei",
|
||||
@ -2121,6 +2123,7 @@
|
||||
"Store",
|
||||
"sull",
|
||||
"texto",
|
||||
"Ver",
|
||||
"Azərbaycan",
|
||||
"Azərbaycan",
|
||||
"Latın",
|
||||
|
@ -16,6 +16,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="27.2.1" />
|
||||
<PackageReference Include="EtaEmre.NetEscapades.EnumGenerators" Version="1.0.0-beta07" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -57,4 +57,6 @@ global using CsvHelper.Configuration;
|
||||
|
||||
global using Microsoft.Extensions.Logging;
|
||||
|
||||
global using NetEscapades.EnumGenerators;
|
||||
|
||||
global using Newtonsoft.Json;
|
||||
|
@ -1,26 +1,26 @@
|
||||
namespace ASC.AuditTrail.Types
|
||||
namespace ASC.AuditTrail.Types;
|
||||
|
||||
[EnumExtensions]
|
||||
public enum ActionType
|
||||
{
|
||||
public enum ActionType
|
||||
{
|
||||
None,
|
||||
Create,
|
||||
Update,
|
||||
Delete,
|
||||
Link,
|
||||
Unlink,
|
||||
Attach,
|
||||
Detach,
|
||||
Send,
|
||||
Import,
|
||||
Export,
|
||||
UpdateAccess,
|
||||
Download,
|
||||
Upload,
|
||||
Copy,
|
||||
Move,
|
||||
Reassigns,
|
||||
Follow,
|
||||
Unfollow,
|
||||
Logout
|
||||
}
|
||||
}
|
||||
None,
|
||||
Create,
|
||||
Update,
|
||||
Delete,
|
||||
Link,
|
||||
Unlink,
|
||||
Attach,
|
||||
Detach,
|
||||
Send,
|
||||
Import,
|
||||
Export,
|
||||
UpdateAccess,
|
||||
Download,
|
||||
Upload,
|
||||
Copy,
|
||||
Move,
|
||||
Reassigns,
|
||||
Follow,
|
||||
Unfollow,
|
||||
Logout
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
namespace ASC.AuditTrail.Types
|
||||
namespace ASC.AuditTrail.Types;
|
||||
|
||||
[EnumExtensions]
|
||||
public enum EntryType
|
||||
{
|
||||
public enum EntryType
|
||||
{
|
||||
None,
|
||||
File,
|
||||
Folder,
|
||||
Project,
|
||||
Contact,
|
||||
Milestone,
|
||||
Task,
|
||||
Comment,
|
||||
SubTask,
|
||||
Message,
|
||||
TimeSpend,
|
||||
ReportTemplate,
|
||||
Template,
|
||||
Relationship,
|
||||
CRMTask,
|
||||
Opportunity,
|
||||
Invoice,
|
||||
Case,
|
||||
ListItem,
|
||||
InvoiceItem,
|
||||
InvoiceTax,
|
||||
FieldDescription,
|
||||
OpportunityMilestone,
|
||||
User,
|
||||
Group
|
||||
}
|
||||
None,
|
||||
File,
|
||||
Folder,
|
||||
Project,
|
||||
Contact,
|
||||
Milestone,
|
||||
Task,
|
||||
Comment,
|
||||
SubTask,
|
||||
Message,
|
||||
TimeSpend,
|
||||
ReportTemplate,
|
||||
Template,
|
||||
Relationship,
|
||||
CRMTask,
|
||||
Opportunity,
|
||||
Invoice,
|
||||
Case,
|
||||
ListItem,
|
||||
InvoiceItem,
|
||||
InvoiceTax,
|
||||
FieldDescription,
|
||||
OpportunityMilestone,
|
||||
User,
|
||||
Group
|
||||
}
|
||||
|
@ -1,33 +1,33 @@
|
||||
namespace ASC.AuditTrail.Types
|
||||
namespace ASC.AuditTrail.Types;
|
||||
|
||||
[EnumExtensions]
|
||||
public enum ModuleType
|
||||
{
|
||||
public enum ModuleType
|
||||
{
|
||||
None,
|
||||
Files,
|
||||
Folders,
|
||||
DocumentsSettings,
|
||||
Companies,
|
||||
Persons,
|
||||
Contacts,
|
||||
CrmTasks,
|
||||
Opportunities,
|
||||
Invoices,
|
||||
Cases,
|
||||
CommonCrmSettings,
|
||||
ContactsSettings,
|
||||
ContactTypes,
|
||||
InvoiceSettings,
|
||||
OtherCrmSettings,
|
||||
Users,
|
||||
Groups,
|
||||
Projects,
|
||||
Milestones,
|
||||
Tasks,
|
||||
Discussions,
|
||||
TimeTracking,
|
||||
Reports,
|
||||
ProjectsSettings,
|
||||
General,
|
||||
Products
|
||||
}
|
||||
None,
|
||||
Files,
|
||||
Folders,
|
||||
DocumentsSettings,
|
||||
Companies,
|
||||
Persons,
|
||||
Contacts,
|
||||
CrmTasks,
|
||||
Opportunities,
|
||||
Invoices,
|
||||
Cases,
|
||||
CommonCrmSettings,
|
||||
ContactsSettings,
|
||||
ContactTypes,
|
||||
InvoiceSettings,
|
||||
OtherCrmSettings,
|
||||
Users,
|
||||
Groups,
|
||||
Projects,
|
||||
Milestones,
|
||||
Tasks,
|
||||
Discussions,
|
||||
TimeTracking,
|
||||
Reports,
|
||||
ProjectsSettings,
|
||||
General,
|
||||
Products
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
namespace ASC.AuditTrail.Types
|
||||
namespace ASC.AuditTrail.Types;
|
||||
|
||||
[EnumExtensions]
|
||||
public enum ProductType
|
||||
{
|
||||
public enum ProductType
|
||||
{
|
||||
None,
|
||||
CRM,
|
||||
Documents,
|
||||
Login,
|
||||
Others,
|
||||
People,
|
||||
Projects,
|
||||
Settings
|
||||
}
|
||||
None,
|
||||
CRM,
|
||||
Documents,
|
||||
Login,
|
||||
Others,
|
||||
People,
|
||||
Projects,
|
||||
Settings
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
namespace ASC.ElasticSearch;
|
||||
|
||||
[EnumExtensions]
|
||||
public enum Analyzer
|
||||
{
|
||||
standard,
|
||||
@ -34,6 +35,7 @@ public enum Analyzer
|
||||
}
|
||||
|
||||
[Flags]
|
||||
[EnumExtensions]
|
||||
public enum CharFilter
|
||||
{
|
||||
io,
|
||||
|
@ -153,13 +153,13 @@ public class BaseIndexer<T> where T : class, ISearchItem
|
||||
{
|
||||
IPromise<IAnalyzers> analyzers(AnalyzersDescriptor b)
|
||||
{
|
||||
foreach (var c in Enum.GetNames(typeof(Analyzer)))
|
||||
foreach (var c in AnalyzerExtensions.GetNames())
|
||||
{
|
||||
var c1 = c;
|
||||
b.Custom(c1 + "custom", ca => ca.Tokenizer(c1).Filters(nameof(Filter.lowercase)).CharFilters(nameof(CharFilter.io)));
|
||||
}
|
||||
|
||||
foreach (var c in Enum.GetNames(typeof(CharFilter)))
|
||||
foreach (var c in CharFilterExtensions.GetNames())
|
||||
{
|
||||
if (c == nameof(CharFilter.io))
|
||||
{
|
||||
|
@ -56,6 +56,8 @@ global using Microsoft.Extensions.Logging;
|
||||
|
||||
global using Nest;
|
||||
|
||||
global using NetEscapades.EnumGenerators;
|
||||
|
||||
global using Newtonsoft.Json;
|
||||
|
||||
global using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||
|
@ -1,4 +1,3 @@
|
||||
{
|
||||
"kafka": {
|
||||
}
|
||||
"kafka": {}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "appserver",
|
||||
"version": "1.1.1",
|
||||
"version": "1.2.0",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"packages/asc-web-components",
|
||||
@ -20,8 +20,8 @@
|
||||
"build:test.translation:personal": "lerna run build:test.translation:personal --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc --ignore @appserver/debug-info",
|
||||
"bump": "lerna version --no-push --no-git-tag-version",
|
||||
"clean": "lerna run clean --parallel",
|
||||
"deploy": "shx rm -rf build/deploy/products && shx rm -rf build/deploy/public && shx rm -rf build/deploy/studio && lerna run deploy --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc && shx cp -r public build/deploy",
|
||||
"deploy:personal": "shx rm -rf build/deploy/products && shx rm -rf build/deploy/public && shx rm -rf build/deploy/studio && lerna run deploy --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor} && shx cp -r public build/deploy",
|
||||
"deploy": "shx rm -rf build/deploy/products && shx rm -rf build/deploy/public && shx rm -rf build/deploy/studio && lerna run deploy --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc && shx cp -r public build/deploy && node build/scripts/minify-common-locales.js",
|
||||
"deploy:personal": "shx rm -rf build/deploy/products && shx rm -rf build/deploy/public && shx rm -rf build/deploy/studio && lerna run deploy --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor} && shx cp -r public build/deploy && node build/scripts/minify-common-locales.js",
|
||||
"serve": "lerna run serve --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc",
|
||||
"start": "lerna run start --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc",
|
||||
"start:personal": "lerna run start:personal --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor}",
|
||||
|
@ -73,24 +73,22 @@ const FilterInput = React.memo(
|
||||
onFilter={onFilter}
|
||||
headerLabel={headerLabel}
|
||||
/>
|
||||
{(isMobile ||
|
||||
isTabletUtils() ||
|
||||
isMobileUtils() ||
|
||||
viewAs === "row") && (
|
||||
<SortButton
|
||||
t={t}
|
||||
selectedFilterData={selectedFilterData}
|
||||
getSortData={getSortData}
|
||||
onChangeViewAs={onChangeViewAs}
|
||||
viewAs={viewAs === "table" ? "row" : viewAs}
|
||||
viewSettings={viewSettings}
|
||||
onSort={onSort}
|
||||
viewSelectorVisible={
|
||||
viewSelectorVisible &&
|
||||
(isMobile || isMobileUtils() || isTabletUtils())
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{(isMobile || isTabletUtils() || isMobileUtils() || viewAs === "row") &&
|
||||
!isRecentFolder && (
|
||||
<SortButton
|
||||
t={t}
|
||||
selectedFilterData={selectedFilterData}
|
||||
getSortData={getSortData}
|
||||
onChangeViewAs={onChangeViewAs}
|
||||
viewAs={viewAs === "table" ? "row" : viewAs}
|
||||
viewSettings={viewSettings}
|
||||
onSort={onSort}
|
||||
viewSelectorVisible={
|
||||
viewSelectorVisible &&
|
||||
(isMobile || isMobileUtils() || isTabletUtils())
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{((viewSettings &&
|
||||
!isMobile &&
|
||||
viewSelectorVisible &&
|
||||
|
@ -20,7 +20,6 @@ import {
|
||||
import { withTranslation } from "react-i18next";
|
||||
import Scrollbar from "@appserver/components/scrollbar";
|
||||
|
||||
//TODO: fix translate
|
||||
const FilterBlock = ({
|
||||
t,
|
||||
selectedFilterData,
|
||||
@ -38,6 +37,7 @@ const FilterBlock = ({
|
||||
|
||||
const [filterData, setFilterData] = React.useState([]);
|
||||
const [filterValues, setFilterValues] = React.useState([]);
|
||||
const [clearFilter, setClearFilter] = React.useState(false);
|
||||
|
||||
const changeShowSelector = (isAuthor, group) => {
|
||||
setShowSelector((val) => {
|
||||
@ -83,9 +83,11 @@ const FilterBlock = ({
|
||||
setFilterData(items);
|
||||
};
|
||||
|
||||
const clearFilter = () => {
|
||||
const onClearFilter = () => {
|
||||
changeSelectedItems([]);
|
||||
setFilterValues([]);
|
||||
setClearFilter(true);
|
||||
selectedFilterData.filterValues.length > 0 && onFilter && onFilter([]);
|
||||
};
|
||||
|
||||
const changeFilterValue = (group, key, isSelected, label) => {
|
||||
@ -96,6 +98,16 @@ const FilterBlock = ({
|
||||
|
||||
setFilterValues(value);
|
||||
changeSelectedItems(value);
|
||||
|
||||
const idx = selectedFilterData.filterValues.findIndex(
|
||||
(item) => item.group === group
|
||||
);
|
||||
|
||||
if (idx > -1) {
|
||||
setClearFilter(true);
|
||||
onFilter(value);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -121,41 +133,47 @@ const FilterBlock = ({
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
const data = getFilterData();
|
||||
if (!clearFilter) {
|
||||
const data = getFilterData();
|
||||
|
||||
const items = data.filter((item) => item.isHeader === true);
|
||||
const items = data.filter((item) => item.isHeader === true);
|
||||
|
||||
items.forEach((item) => {
|
||||
const groupItem = data.filter(
|
||||
(val) => val.group === item.group && val.isHeader !== true
|
||||
);
|
||||
items.forEach((item) => {
|
||||
const groupItem = data.filter(
|
||||
(val) => val.group === item.group && val.isHeader !== true
|
||||
);
|
||||
|
||||
groupItem.forEach((item) => (item.isSelected = false));
|
||||
groupItem.forEach((item) => (item.isSelected = false));
|
||||
|
||||
item.groupItem = groupItem;
|
||||
});
|
||||
|
||||
if (selectedFilterData.filterValues) {
|
||||
selectedFilterData.filterValues.forEach((value) => {
|
||||
items.forEach((item) => {
|
||||
if (item.group === value.group) {
|
||||
item.groupItem.forEach((groupItem) => {
|
||||
if (groupItem.key === value.key || groupItem.isSelector) {
|
||||
groupItem.isSelected = true;
|
||||
if (groupItem.isSelector) {
|
||||
groupItem.selectedLabel = value.label;
|
||||
groupItem.selectedKey = value.key;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
item.groupItem = groupItem;
|
||||
});
|
||||
}
|
||||
|
||||
setFilterData(items);
|
||||
setFilterValues(selectedFilterData.filterValues);
|
||||
}, [selectedFilterData, getFilterData]);
|
||||
if (selectedFilterData.filterValues) {
|
||||
selectedFilterData.filterValues.forEach((value) => {
|
||||
items.forEach((item) => {
|
||||
if (item.group === value.group) {
|
||||
item.groupItem.forEach((groupItem) => {
|
||||
if (groupItem.key === value.key || groupItem.isSelector) {
|
||||
groupItem.isSelected = true;
|
||||
if (groupItem.isSelector) {
|
||||
groupItem.selectedLabel = value.label;
|
||||
groupItem.selectedKey = value.key;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const newFilterValues = selectedFilterData.filterValues.map((value) => ({
|
||||
...value,
|
||||
}));
|
||||
|
||||
setFilterData(items);
|
||||
setFilterValues(newFilterValues);
|
||||
}
|
||||
}, [selectedFilterData, getFilterData, clearFilter]);
|
||||
|
||||
const onFilterAction = () => {
|
||||
onFilter && onFilter(filterValues);
|
||||
@ -175,6 +193,39 @@ const FilterBlock = ({
|
||||
changeFilterValue(showSelector.group, items[0].key, false, items[0].label);
|
||||
};
|
||||
|
||||
const isEqualFilter = () => {
|
||||
const selectedFilterValues = selectedFilterData.filterValues;
|
||||
|
||||
let isEqual = true;
|
||||
|
||||
if (
|
||||
filterValues.length === 0 ||
|
||||
selectedFilterValues.length > filterValues.length
|
||||
)
|
||||
return !isEqual;
|
||||
|
||||
if (
|
||||
(selectedFilterValues.length === 0 && filterValues.length > 0) ||
|
||||
selectedFilterValues.length !== filterValues.length
|
||||
) {
|
||||
isEqual = false;
|
||||
|
||||
return !isEqual;
|
||||
}
|
||||
|
||||
filterValues.forEach((value) => {
|
||||
const oldValue = selectedFilterValues.find(
|
||||
(item) => item.group === value.group
|
||||
);
|
||||
|
||||
isEqual = isEqual && oldValue?.key === value.key;
|
||||
});
|
||||
|
||||
return !isEqual;
|
||||
};
|
||||
|
||||
const showFooter = isEqualFilter();
|
||||
|
||||
return (
|
||||
<>
|
||||
{showSelector.show ? (
|
||||
@ -208,13 +259,13 @@ const FilterBlock = ({
|
||||
</StyledFilterBlock>
|
||||
</>
|
||||
) : (
|
||||
<StyledFilterBlock>
|
||||
<StyledFilterBlock showFooter={showFooter}>
|
||||
<StyledFilterBlockHeader>
|
||||
<Heading size="medium">{contextMenuHeader}</Heading>
|
||||
<IconButton
|
||||
iconName="/static/images/clear.react.svg"
|
||||
isFill={true}
|
||||
onClick={clearFilter}
|
||||
onClick={onClearFilter}
|
||||
size={17}
|
||||
/>
|
||||
</StyledFilterBlockHeader>
|
||||
@ -237,15 +288,17 @@ const FilterBlock = ({
|
||||
})}
|
||||
</Scrollbar>
|
||||
</div>
|
||||
<StyledFilterBlockFooter>
|
||||
<Button
|
||||
size="normal"
|
||||
primary={true}
|
||||
label={t("AddFilter")}
|
||||
scale={true}
|
||||
onClick={onFilterAction}
|
||||
/>
|
||||
</StyledFilterBlockFooter>
|
||||
{showFooter && (
|
||||
<StyledFilterBlockFooter>
|
||||
<Button
|
||||
size="normal"
|
||||
primary={true}
|
||||
label={t("AddFilter")}
|
||||
scale={true}
|
||||
onClick={onFilterAction}
|
||||
/>
|
||||
</StyledFilterBlockFooter>
|
||||
)}
|
||||
|
||||
<StyledControlContainer onClick={hideFilterBlock}>
|
||||
<StyledCrossIcon />
|
||||
|
@ -50,7 +50,7 @@ const StyledFilterBlock = styled.div`
|
||||
}
|
||||
|
||||
.filter-body {
|
||||
height: calc(100% - 125px);
|
||||
height: ${(props) => (props.showFooter ? "calc(100% - 125px)" : "100%")};
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -1,15 +1,20 @@
|
||||
import Base from "@appserver/components/themes/base";
|
||||
import styled, { keyframes, css } from "styled-components";
|
||||
import { desktop, tablet } from "@appserver/components/utils/device";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
|
||||
const StyledFloatingButtonWrapper = styled.div`
|
||||
@media ${desktop} {
|
||||
position: absolute;
|
||||
z-index: 300;
|
||||
width: 100px;
|
||||
height: 70px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
${isDesktop &&
|
||||
css`
|
||||
width: 100px;
|
||||
height: 70px;
|
||||
`}
|
||||
}
|
||||
|
||||
.layout-progress-bar_close-icon {
|
||||
|
@ -7,6 +7,7 @@ import { isMobile } from "react-device-detect";
|
||||
import { tablet } from "@appserver/components/utils/device";
|
||||
import { Base } from "@appserver/components/themes";
|
||||
import ToggleInfoPanelButton from "./toggle-infopanel-btn";
|
||||
import PlusButton from "./plus-btn";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
margin-left: 20px;
|
||||
@ -112,17 +113,9 @@ const ControlButtons = ({
|
||||
{!isRootFolder && canCreate ? (
|
||||
<>
|
||||
{!isMobile && (
|
||||
<ContextMenuButton
|
||||
zIndex={402}
|
||||
<PlusButton
|
||||
className="add-button"
|
||||
directionX="right"
|
||||
iconName="images/plus.svg"
|
||||
size={15}
|
||||
isFill
|
||||
getData={getContextOptionsPlus}
|
||||
isDisabled={false}
|
||||
usePortal={false}
|
||||
dropDownClassName="add-drop-down"
|
||||
/>
|
||||
)}
|
||||
{!personal && (
|
||||
@ -148,17 +141,9 @@ const ControlButtons = ({
|
||||
) : canCreate ? (
|
||||
<>
|
||||
{!isMobile && (
|
||||
<ContextMenuButton
|
||||
zIndex={402}
|
||||
<PlusButton
|
||||
className="add-button"
|
||||
directionX="right"
|
||||
iconName="images/plus.svg"
|
||||
size={15}
|
||||
isFill
|
||||
getData={getContextOptionsPlus}
|
||||
isDisabled={false}
|
||||
usePortal={false}
|
||||
dropDownClassName="add-drop-down"
|
||||
/>
|
||||
)}
|
||||
{!isDesktop && (
|
||||
@ -172,7 +157,7 @@ const ControlButtons = ({
|
||||
) : isRecycleBinFolder && !isEmptyFilesList ? (
|
||||
<>
|
||||
<IconButton
|
||||
iconName="images/clear.active.react.svg"
|
||||
iconName="images/clear.trash.react.svg"
|
||||
size={15}
|
||||
isFill={true}
|
||||
onClick={clearTrash}
|
||||
|
@ -0,0 +1,53 @@
|
||||
import React, { useState, useRef } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import IconButton from "@appserver/components/icon-button";
|
||||
import ContextMenu from "@appserver/components/context-menu";
|
||||
|
||||
const PlusButton = (props) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const ref = useRef(null);
|
||||
const menuRef = useRef(null);
|
||||
|
||||
const { className, getData } = props;
|
||||
|
||||
const toggle = (e, isOpen) => {
|
||||
isOpen ? menuRef.current.show(e) : menuRef.current.hide(e);
|
||||
setIsOpen(isOpen);
|
||||
};
|
||||
|
||||
const onClick = (e) => {
|
||||
toggle(e, !isOpen);
|
||||
};
|
||||
|
||||
const onHide = () => {
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const model = getData();
|
||||
|
||||
return (
|
||||
<div ref={ref} className={className}>
|
||||
<IconButton
|
||||
onClick={onClick}
|
||||
iconName="images/plus.svg"
|
||||
size={15}
|
||||
isFill
|
||||
/>
|
||||
<ContextMenu
|
||||
model={model}
|
||||
containerRef={ref}
|
||||
ref={menuRef}
|
||||
onHide={onHide}
|
||||
scaled={false}
|
||||
leftOffset={150}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
PlusButton.propTypes = {
|
||||
className: PropTypes.string,
|
||||
getData: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default PlusButton;
|
@ -1,6 +1,6 @@
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import Backend from "@appserver/common/utils/i18next-http-backend";
|
||||
import { LANGUAGE } from "../../constants";
|
||||
import { loadLanguagePath } from "../../utils";
|
||||
|
||||
|
@ -17,7 +17,11 @@ import {
|
||||
|
||||
const paddingStyles = css`
|
||||
padding: ${(props) =>
|
||||
props.settingsStudio ? "0 7px 16px 24px" : "19px 3px 16px 20px"};
|
||||
props.settingsStudio
|
||||
? "0 7px 16px 24px"
|
||||
: props.viewAs === "row"
|
||||
? "19px 3px 16px 16px"
|
||||
: "19px 3px 16px 20px"};
|
||||
|
||||
@media ${tablet} {
|
||||
padding: ${(props) =>
|
||||
|
@ -93,10 +93,6 @@ module.exports = {
|
||||
singleton: true,
|
||||
requiredVersion: deps["react-i18next"],
|
||||
},
|
||||
"i18next-http-backend": {
|
||||
singleton: true,
|
||||
requiredVersion: deps["i18next-http-backend"],
|
||||
},
|
||||
"prop-types": {
|
||||
singleton: true,
|
||||
requiredVersion: deps["prop-types"],
|
||||
|
@ -12,10 +12,10 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.15.4",
|
||||
"axios": "^0.21.4",
|
||||
"cross-fetch": "3.1.5",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"global": "^4.4.0",
|
||||
"i18next": "^20.6.1",
|
||||
"i18next-http-backend": "^1.3.1",
|
||||
"mobx": "^6.3.3",
|
||||
"mobx-react": "^7.2.0",
|
||||
"moment": "^2.29.1",
|
||||
|
@ -5,7 +5,7 @@ import { Workbox } from "workbox-window";
|
||||
import SnackBar from "@appserver/components/snackbar";
|
||||
import i18n from "i18next";
|
||||
import { useTranslation, initReactI18next } from "react-i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import Backend from "@appserver/common/utils/i18next-http-backend";
|
||||
import { LANGUAGE } from "../constants";
|
||||
import { loadLanguagePath } from "../utils";
|
||||
|
||||
|
@ -0,0 +1,2 @@
|
||||
import backend from './lib/index.js'
|
||||
export default backend
|
@ -0,0 +1,15 @@
|
||||
var fetchApi
|
||||
if (typeof fetch === 'function') {
|
||||
if (typeof global !== 'undefined' && global.fetch) {
|
||||
fetchApi = global.fetch
|
||||
} else if (typeof window !== 'undefined' && window.fetch) {
|
||||
fetchApi = window.fetch
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof require !== 'undefined' && (typeof window === 'undefined' || typeof window.document === 'undefined')) {
|
||||
var f = fetchApi || require('cross-fetch')
|
||||
if (f.default) f = f.default
|
||||
exports.default = f
|
||||
module.exports = exports.default
|
||||
}
|
241
packages/asc-web-common/utils/i18next-http-backend/lib/index.js
Normal file
241
packages/asc-web-common/utils/i18next-http-backend/lib/index.js
Normal file
@ -0,0 +1,241 @@
|
||||
import { defaults, makePromise } from "./utils.js";
|
||||
import request from "./request.js";
|
||||
|
||||
const getDefaults = () => {
|
||||
return {
|
||||
loadPath: "/locales/{{lng}}/{{ns}}.json",
|
||||
addPath: "/locales/add/{{lng}}/{{ns}}",
|
||||
allowMultiLoading: false,
|
||||
parse: (data) => JSON.parse(data),
|
||||
stringify: JSON.stringify,
|
||||
parsePayload: (namespace, key, fallbackValue) => ({
|
||||
[key]: fallbackValue || "",
|
||||
}),
|
||||
request,
|
||||
reloadInterval: typeof window !== "undefined" ? false : 60 * 60 * 1000,
|
||||
customHeaders: {},
|
||||
queryStringParams: {},
|
||||
crossDomain: false, // used for XmlHttpRequest
|
||||
withCredentials: false, // used for XmlHttpRequest
|
||||
overrideMimeType: false, // used for XmlHttpRequest
|
||||
requestOptions: {
|
||||
// used for fetch
|
||||
mode: "cors",
|
||||
credentials: "same-origin",
|
||||
cache: "default",
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
class Backend {
|
||||
constructor(services, options = {}, allOptions = {}) {
|
||||
this.services = services;
|
||||
this.options = options;
|
||||
this.allOptions = allOptions;
|
||||
this.type = "backend";
|
||||
this.init(services, options, allOptions);
|
||||
}
|
||||
|
||||
init(services, options = {}, allOptions = {}) {
|
||||
this.services = services;
|
||||
this.options = defaults(options, this.options || {}, getDefaults());
|
||||
this.allOptions = allOptions;
|
||||
if (this.services && this.options.reloadInterval) {
|
||||
setInterval(() => this.reload(), this.options.reloadInterval);
|
||||
}
|
||||
}
|
||||
|
||||
readMulti(languages, namespaces, callback) {
|
||||
this._readAny(languages, languages, namespaces, namespaces, callback);
|
||||
}
|
||||
|
||||
read(language, namespace, callback) {
|
||||
this._readAny([language], language, [namespace], namespace, callback);
|
||||
}
|
||||
|
||||
_readAny(
|
||||
languages,
|
||||
loadUrlLanguages,
|
||||
namespaces,
|
||||
loadUrlNamespaces,
|
||||
callback
|
||||
) {
|
||||
let loadPath = this.options.loadPath;
|
||||
if (typeof this.options.loadPath === "function") {
|
||||
loadPath = this.options.loadPath(languages, namespaces);
|
||||
}
|
||||
|
||||
loadPath = makePromise(loadPath);
|
||||
|
||||
loadPath.then((resolvedLoadPath) => {
|
||||
if (!resolvedLoadPath) return callback(null, {});
|
||||
const url = this.services.interpolator.interpolate(resolvedLoadPath, {
|
||||
lng: languages.join("+"),
|
||||
ns: namespaces.join("+"),
|
||||
});
|
||||
this.loadUrl(url, callback, loadUrlLanguages, loadUrlNamespaces);
|
||||
});
|
||||
}
|
||||
|
||||
loadUrl(url, callback, languages, namespaces) {
|
||||
//console.log("loadUrl", url, languages, namespaces);
|
||||
|
||||
if (!window.i18n) {
|
||||
window.i18n = {
|
||||
inLoad: [],
|
||||
loaded: {},
|
||||
};
|
||||
}
|
||||
|
||||
var index = window.i18n.inLoad.findIndex((item) => item.url == url);
|
||||
|
||||
if (index > -1) {
|
||||
//console.log("skip already in load url", url);
|
||||
window.i18n.inLoad[index].callbacks.push(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.i18n.loaded[url]) {
|
||||
return callback(null, window.i18n.loaded[url].data);
|
||||
}
|
||||
|
||||
if (namespaces == "translation") {
|
||||
//console.log("skip defaultNS");
|
||||
return callback(
|
||||
`failed loading ${url}; status code: 404`,
|
||||
false /* retry */
|
||||
);
|
||||
}
|
||||
|
||||
window.i18n.inLoad.push({ url, callbacks: [callback] });
|
||||
|
||||
this.options.request(this.options, url, undefined, (err, res) => {
|
||||
if (res && ((res.status >= 500 && res.status < 600) || !res.status))
|
||||
return this.sendCallbacks(
|
||||
url,
|
||||
namespaces,
|
||||
`failed loading ${url}; status code: ${res.status}`,
|
||||
true /* retry */
|
||||
);
|
||||
if (res && res.status >= 400 && res.status < 500)
|
||||
return this.sendCallbacks(
|
||||
url,
|
||||
namespaces,
|
||||
`failed loading ${url}; status code: ${res.status}`,
|
||||
false /* no retry */
|
||||
);
|
||||
if (
|
||||
!res &&
|
||||
err &&
|
||||
err.message &&
|
||||
err.message.indexOf("Failed to fetch") > -1
|
||||
)
|
||||
return this.sendCallbacks(
|
||||
url,
|
||||
namespaces,
|
||||
`failed loading ${url}: ${err.message}`,
|
||||
true /* retry */
|
||||
);
|
||||
if (err) return this.sendCallbacks(url, namespaces, err, false);
|
||||
|
||||
let ret, parseErr;
|
||||
try {
|
||||
if (typeof res.data === "string") {
|
||||
ret = this.options.parse(res.data, languages, namespaces);
|
||||
} else {
|
||||
// fallback, which omits calling the parse function
|
||||
ret = res.data;
|
||||
}
|
||||
} catch (e) {
|
||||
parseErr = `failed parsing ${url} to json`;
|
||||
}
|
||||
if (parseErr) return this.sendCallbacks(url, namespaces, parseErr, false);
|
||||
this.sendCallbacks(url, namespaces, null, ret);
|
||||
});
|
||||
}
|
||||
|
||||
sendCallbacks(url, namespaces, error, data) {
|
||||
var index = window.i18n.inLoad.findIndex((item) => item.url == url);
|
||||
if (index == -1) return;
|
||||
|
||||
window.i18n.inLoad[index].callbacks.forEach((cb) => cb(error, data));
|
||||
|
||||
window.i18n.inLoad.splice(index, 1);
|
||||
|
||||
if (!error) {
|
||||
window.i18n.loaded[url] = {
|
||||
namespaces,
|
||||
data,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
create(languages, namespace, key, fallbackValue, callback) {
|
||||
// If there is a falsey addPath, then abort -- this has been disabled.
|
||||
if (!this.options.addPath) return;
|
||||
if (typeof languages === "string") languages = [languages];
|
||||
const payload = this.options.parsePayload(namespace, key, fallbackValue);
|
||||
let finished = 0;
|
||||
const dataArray = [];
|
||||
const resArray = [];
|
||||
languages.forEach((lng) => {
|
||||
let addPath = this.options.addPath;
|
||||
if (typeof this.options.addPath === "function") {
|
||||
addPath = this.options.addPath(lng, namespace);
|
||||
}
|
||||
const url = this.services.interpolator.interpolate(addPath, {
|
||||
lng: lng,
|
||||
ns: namespace,
|
||||
});
|
||||
|
||||
this.options.request(this.options, url, payload, (data, res) => {
|
||||
// TODO: if res.status === 4xx do log
|
||||
finished += 1;
|
||||
dataArray.push(data);
|
||||
resArray.push(res);
|
||||
if (finished === languages.length) {
|
||||
if (callback) callback(dataArray, resArray);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
reload() {
|
||||
const { backendConnector, languageUtils, logger } = this.services;
|
||||
const currentLanguage = backendConnector.language;
|
||||
if (currentLanguage && currentLanguage.toLowerCase() === "cimode") return; // avoid loading resources for cimode
|
||||
|
||||
const toLoad = [];
|
||||
const append = (lng) => {
|
||||
const lngs = languageUtils.toResolveHierarchy(lng);
|
||||
lngs.forEach((l) => {
|
||||
if (toLoad.indexOf(l) < 0) toLoad.push(l);
|
||||
});
|
||||
};
|
||||
|
||||
append(currentLanguage);
|
||||
|
||||
if (this.allOptions.preload)
|
||||
this.allOptions.preload.forEach((l) => append(l));
|
||||
|
||||
toLoad.forEach((lng) => {
|
||||
this.allOptions.ns.forEach((ns) => {
|
||||
backendConnector.read(lng, ns, "read", null, null, (err, data) => {
|
||||
if (err)
|
||||
logger.warn(
|
||||
`loading namespace ${ns} for language ${lng} failed`,
|
||||
err
|
||||
);
|
||||
if (!err && data)
|
||||
logger.log(`loaded namespace ${ns} for language ${lng}`, data);
|
||||
|
||||
backendConnector.loaded(`${lng}|${ns}`, err, data);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Backend.type = "backend";
|
||||
|
||||
export default Backend;
|
@ -0,0 +1,127 @@
|
||||
import { defaults, hasXMLHttpRequest } from './utils.js'
|
||||
import * as fetchNode from './getFetch.cjs'
|
||||
|
||||
let fetchApi
|
||||
if (typeof fetch === 'function') {
|
||||
if (typeof global !== 'undefined' && global.fetch) {
|
||||
fetchApi = global.fetch
|
||||
} else if (typeof window !== 'undefined' && window.fetch) {
|
||||
fetchApi = window.fetch
|
||||
}
|
||||
}
|
||||
let XmlHttpRequestApi
|
||||
if (hasXMLHttpRequest()) {
|
||||
if (typeof global !== 'undefined' && global.XMLHttpRequest) {
|
||||
XmlHttpRequestApi = global.XMLHttpRequest
|
||||
} else if (typeof window !== 'undefined' && window.XMLHttpRequest) {
|
||||
XmlHttpRequestApi = window.XMLHttpRequest
|
||||
}
|
||||
}
|
||||
let ActiveXObjectApi
|
||||
if (typeof ActiveXObject === 'function') {
|
||||
if (typeof global !== 'undefined' && global.ActiveXObject) {
|
||||
ActiveXObjectApi = global.ActiveXObject
|
||||
} else if (typeof window !== 'undefined' && window.ActiveXObject) {
|
||||
ActiveXObjectApi = window.ActiveXObject
|
||||
}
|
||||
}
|
||||
if (!fetchApi && fetchNode && !XmlHttpRequestApi && !ActiveXObjectApi) fetchApi = fetchNode.default || fetchNode // because of strange export
|
||||
if (typeof fetchApi !== 'function') fetchApi = undefined
|
||||
|
||||
const addQueryString = (url, params) => {
|
||||
if (params && typeof params === 'object') {
|
||||
let queryString = ''
|
||||
// Must encode data
|
||||
for (const paramName in params) {
|
||||
queryString += '&' + encodeURIComponent(paramName) + '=' + encodeURIComponent(params[paramName])
|
||||
}
|
||||
if (!queryString) return url
|
||||
url = url + (url.indexOf('?') !== -1 ? '&' : '?') + queryString.slice(1)
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
// fetch api stuff
|
||||
const requestWithFetch = (options, url, payload, callback) => {
|
||||
if (options.queryStringParams) {
|
||||
url = addQueryString(url, options.queryStringParams)
|
||||
}
|
||||
const headers = defaults({}, typeof options.customHeaders === 'function' ? options.customHeaders() : options.customHeaders)
|
||||
if (payload) headers['Content-Type'] = 'application/json'
|
||||
fetchApi(url, defaults({
|
||||
method: payload ? 'POST' : 'GET',
|
||||
body: payload ? options.stringify(payload) : undefined,
|
||||
headers
|
||||
}, typeof options.requestOptions === 'function' ? options.requestOptions(payload) : options.requestOptions)).then((response) => {
|
||||
if (!response.ok) return callback(response.statusText || 'Error', { status: response.status })
|
||||
response.text().then((data) => {
|
||||
callback(null, { status: response.status, data })
|
||||
}).catch(callback)
|
||||
}).catch(callback)
|
||||
}
|
||||
|
||||
// xml http request stuff
|
||||
const requestWithXmlHttpRequest = (options, url, payload, callback) => {
|
||||
if (payload && typeof payload === 'object') {
|
||||
// if (!cache) payload._t = Date.now()
|
||||
// URL encoded form payload must be in querystring format
|
||||
payload = addQueryString('', payload).slice(1)
|
||||
}
|
||||
|
||||
if (options.queryStringParams) {
|
||||
url = addQueryString(url, options.queryStringParams)
|
||||
}
|
||||
|
||||
try {
|
||||
let x
|
||||
if (XmlHttpRequestApi) {
|
||||
x = new XmlHttpRequestApi()
|
||||
} else {
|
||||
x = new ActiveXObjectApi('MSXML2.XMLHTTP.3.0')
|
||||
}
|
||||
x.open(payload ? 'POST' : 'GET', url, 1)
|
||||
if (!options.crossDomain) {
|
||||
x.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
|
||||
}
|
||||
x.withCredentials = !!options.withCredentials
|
||||
if (payload) {
|
||||
x.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
|
||||
}
|
||||
if (x.overrideMimeType) {
|
||||
x.overrideMimeType('application/json')
|
||||
}
|
||||
let h = options.customHeaders
|
||||
h = typeof h === 'function' ? h() : h
|
||||
if (h) {
|
||||
for (const i in h) {
|
||||
x.setRequestHeader(i, h[i])
|
||||
}
|
||||
}
|
||||
x.onreadystatechange = () => {
|
||||
x.readyState > 3 && callback(x.status >= 400 ? x.statusText : null, { status: x.status, data: x.responseText })
|
||||
}
|
||||
x.send(payload)
|
||||
} catch (e) {
|
||||
console && console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
const request = (options, url, payload, callback) => {
|
||||
if (typeof payload === 'function') {
|
||||
callback = payload
|
||||
payload = undefined
|
||||
}
|
||||
callback = callback || (() => {})
|
||||
|
||||
if (fetchApi) {
|
||||
// use fetch api
|
||||
return requestWithFetch(options, url, payload, callback)
|
||||
}
|
||||
|
||||
if (hasXMLHttpRequest() || typeof ActiveXObject === 'function') {
|
||||
// use xml http request
|
||||
return requestWithXmlHttpRequest(options, url, payload, callback)
|
||||
}
|
||||
}
|
||||
|
||||
export default request
|
@ -0,0 +1,44 @@
|
||||
const arr = []
|
||||
const each = arr.forEach
|
||||
const slice = arr.slice
|
||||
|
||||
export function defaults (obj) {
|
||||
each.call(slice.call(arguments, 1), (source) => {
|
||||
if (source) {
|
||||
for (const prop in source) {
|
||||
if (obj[prop] === undefined) obj[prop] = source[prop]
|
||||
}
|
||||
}
|
||||
})
|
||||
return obj
|
||||
}
|
||||
|
||||
export function hasXMLHttpRequest () {
|
||||
return (typeof XMLHttpRequest === 'function' || typeof XMLHttpRequest === 'object')
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given `maybePromise` is a Promise.
|
||||
*
|
||||
* @param {*} maybePromise
|
||||
*
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function isPromise (maybePromise) {
|
||||
return !!maybePromise && typeof maybePromise.then === 'function'
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert any value to a Promise than will resolve to this value.
|
||||
*
|
||||
* @param {*} maybePromise
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function makePromise (maybePromise) {
|
||||
if (isPromise(maybePromise)) {
|
||||
return maybePromise
|
||||
}
|
||||
|
||||
return Promise.resolve(maybePromise)
|
||||
}
|
17
packages/asc-web-common/utils/minifyJson.js
Normal file
17
packages/asc-web-common/utils/minifyJson.js
Normal file
@ -0,0 +1,17 @@
|
||||
const minifyJson = (content, path) => {
|
||||
try {
|
||||
var isBuffer = Buffer.isBuffer(content);
|
||||
//console.log("is buffer", isBuffer);
|
||||
if (isBuffer) {
|
||||
content = content.toString().trim();
|
||||
//console.log("content string", content);
|
||||
}
|
||||
const json = JSON.parse(content);
|
||||
return JSON.stringify(json);
|
||||
} catch (e) {
|
||||
console.error("Unable to minimize ", path, e);
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = minifyJson;
|
@ -20,6 +20,8 @@ const AccessRightSelect = ({
|
||||
onSelect,
|
||||
advancedOptions,
|
||||
selectedOption,
|
||||
isExternalLink,
|
||||
isPersonal,
|
||||
...props
|
||||
}) => {
|
||||
const [currentItem, setCurrentItem] = useState(selectedOption);
|
||||
@ -97,6 +99,8 @@ const AccessRightSelect = ({
|
||||
label: currentItem?.title,
|
||||
}}
|
||||
size="content"
|
||||
isExternalLink={isExternalLink}
|
||||
isPersonal={isPersonal}
|
||||
/>
|
||||
</StyledAccessRightWrapper>
|
||||
);
|
||||
@ -111,6 +115,8 @@ AccessRightSelect.propTypes = {
|
||||
advancedOptions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
/** The option that is selected by default */
|
||||
selectedOption: PropTypes.object,
|
||||
isExternalLink: PropTypes.bool,
|
||||
isPersonal: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default React.memo(AccessRightSelect);
|
||||
|
@ -97,7 +97,7 @@ const CatalogItem = (props) => {
|
||||
{!iconBadge ? (
|
||||
<Badge className="catalog-item__badge" label={labelBadge} />
|
||||
) : (
|
||||
<ReactSVG src={iconBadge} />
|
||||
<ReactSVG className="catalog-icon__badge" src={iconBadge} />
|
||||
)}
|
||||
</StyledCatalogItemBadgeWrapper>
|
||||
)}
|
||||
|
@ -310,7 +310,22 @@ const StyledCatalogItemContainer = styled.div`
|
||||
`}
|
||||
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
|
||||
.catalog-icon__badge {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.catalog-icon__badge:target {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
:hover {
|
||||
.catalog-icon__badge {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
StyledCatalogItemContainer.defaultProps = { theme: Base };
|
||||
|
||||
export {
|
||||
|
@ -104,6 +104,9 @@ class ComboBox extends React.Component {
|
||||
fixedDirection,
|
||||
withBlur,
|
||||
fillIcon,
|
||||
isExternalLink,
|
||||
isPersonal,
|
||||
offsetLeft,
|
||||
} = this.props;
|
||||
const { isOpen, selectedOption } = this.state;
|
||||
|
||||
@ -169,6 +172,9 @@ class ComboBox extends React.Component {
|
||||
isDefaultMode={isDefaultMode}
|
||||
fixedDirection={fixedDirection}
|
||||
withBlur={withBlur}
|
||||
isExternalLink={isExternalLink}
|
||||
isPersonal={isPersonal}
|
||||
offsetLeft={offsetLeft}
|
||||
>
|
||||
{advancedOptions
|
||||
? advancedOptions
|
||||
@ -256,6 +262,10 @@ ComboBox.propTypes = {
|
||||
disableItemClick: PropTypes.bool,
|
||||
|
||||
fillIcon: PropTypes.bool,
|
||||
isExternalLink: PropTypes.bool,
|
||||
isPersonal: PropTypes.bool,
|
||||
|
||||
offsetLeft: PropTypes.number,
|
||||
};
|
||||
|
||||
ComboBox.defaultProps = {
|
||||
@ -273,6 +283,7 @@ ComboBox.defaultProps = {
|
||||
displaySelectedOption: false,
|
||||
fixedDirection: false,
|
||||
disableItemClick: false,
|
||||
isExternalLink: false,
|
||||
};
|
||||
|
||||
export default ComboBox;
|
||||
|
@ -119,7 +119,7 @@ class ContextMenu extends Component {
|
||||
if (event) {
|
||||
const rects = this.props.containerRef?.current.getBoundingClientRect();
|
||||
|
||||
let left = rects ? rects.left : event.pageX + 1;
|
||||
let left = rects ? rects.left - this.props.leftOffset : event.pageX + 1;
|
||||
let top = rects ? rects.top : event.pageY + 1;
|
||||
let width = this.menuRef.current.offsetParent
|
||||
? this.menuRef.current.offsetWidth
|
||||
@ -392,7 +392,10 @@ ContextMenu.propTypes = {
|
||||
containerRef: PropTypes.any,
|
||||
/** Scale with by container component*/
|
||||
scaled: PropTypes.bool,
|
||||
|
||||
getContextModel: PropTypes.func,
|
||||
|
||||
leftOffset: PropTypes.number,
|
||||
};
|
||||
|
||||
ContextMenu.defaultProps = {
|
||||
@ -407,6 +410,7 @@ ContextMenu.defaultProps = {
|
||||
onHide: null,
|
||||
scaled: false,
|
||||
containerRef: null,
|
||||
leftOffset: 0,
|
||||
};
|
||||
|
||||
export default ContextMenu;
|
||||
|
@ -6,9 +6,10 @@ import { classNames } from "../../utils/classNames";
|
||||
import { CSSTransition } from "react-transition-group";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import ArrowIcon from "../svg/arrow.right.react.svg";
|
||||
import CustomScrollbarsVirtualList from "../../scrollbar/custom-scrollbars-virtual-list";
|
||||
import Scrollbar from "../../scrollbar";
|
||||
|
||||
import { VariableSizeList } from "react-window";
|
||||
//import CustomScrollbarsVirtualList from "../../scrollbar/custom-scrollbars-virtual-list";
|
||||
//import { VariableSizeList } from "react-window";
|
||||
|
||||
const SubMenu = (props) => {
|
||||
const { onLeafClick, root, resetMenu, model, changeView } = props;
|
||||
@ -225,27 +226,38 @@ const SubMenu = (props) => {
|
||||
return 36;
|
||||
});
|
||||
|
||||
const getItemSize = (index) => rowHeights[index];
|
||||
//const getItemSize = (index) => rowHeights[index];
|
||||
|
||||
const height = rowHeights.reduce((a, b) => a + b);
|
||||
|
||||
const viewport = DomHelpers.getViewport();
|
||||
|
||||
const listHeight =
|
||||
height + 61 > viewport.height - 64 ? viewport.height - 125 : height;
|
||||
height + 61 > viewport.height - 64
|
||||
? viewport.height - 125
|
||||
: height + 5;
|
||||
|
||||
return (
|
||||
<VariableSizeList
|
||||
height={listHeight}
|
||||
width={"auto"}
|
||||
itemCount={newModel.length}
|
||||
itemSize={getItemSize}
|
||||
itemData={newModel}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{renderItem}
|
||||
</VariableSizeList>
|
||||
<Scrollbar style={{ height: listHeight }} stype="mediumBlack">
|
||||
{model.map((item, index) => {
|
||||
if (item.disabled) return null;
|
||||
return renderItem(item, index);
|
||||
})}
|
||||
</Scrollbar>
|
||||
);
|
||||
|
||||
// return (
|
||||
// <VariableSizeList
|
||||
// height={listHeight}
|
||||
// width={"auto"}
|
||||
// itemCount={newModel.length}
|
||||
// itemSize={getItemSize}
|
||||
// itemData={newModel}
|
||||
// outerElementType={CustomScrollbarsVirtualList}
|
||||
// >
|
||||
// {renderItem}
|
||||
// </VariableSizeList>
|
||||
// );
|
||||
}
|
||||
|
||||
return model.map((item, index) => {
|
||||
|
@ -16,6 +16,10 @@ const DropDownItem = (props) => {
|
||||
className,
|
||||
theme,
|
||||
fillIcon,
|
||||
isSubMenu,
|
||||
isActive,
|
||||
withoutIcon,
|
||||
noHover,
|
||||
} = props;
|
||||
|
||||
const onClickAction = (e) => {
|
||||
@ -25,19 +29,33 @@ const DropDownItem = (props) => {
|
||||
return (
|
||||
<StyledDropdownItem
|
||||
{...props}
|
||||
noHover={noHover}
|
||||
className={className}
|
||||
onClick={onClickAction}
|
||||
disabled={disabled}
|
||||
isActive={isActive}
|
||||
>
|
||||
{icon && (
|
||||
<IconWrapper>
|
||||
{!withoutIcon && (
|
||||
<ReactSVG
|
||||
src={icon}
|
||||
className={fillIcon ? "drop-down-item_icon" : ""}
|
||||
/>
|
||||
)}
|
||||
</IconWrapper>
|
||||
)}
|
||||
|
||||
{isSeparator ? "\u00A0" : label ? label : children && children}
|
||||
|
||||
{isSubMenu && (
|
||||
<IconWrapper className="submenu-arrow">
|
||||
<ReactSVG
|
||||
src={icon}
|
||||
className={fillIcon ? "drop-down-item_icon" : ""}
|
||||
src="/static/images/right.arrow.react.svg"
|
||||
className="drop-down-item_icon"
|
||||
/>
|
||||
</IconWrapper>
|
||||
)}
|
||||
{isSeparator ? "\u00A0" : label ? label : children && children}
|
||||
</StyledDropdownItem>
|
||||
);
|
||||
};
|
||||
@ -70,6 +88,9 @@ DropDownItem.propTypes = {
|
||||
/** Accepts css text-overflow */
|
||||
textOverflow: PropTypes.bool,
|
||||
fillIcon: PropTypes.bool,
|
||||
isSubMenu: PropTypes.bool,
|
||||
isActive: PropTypes.bool,
|
||||
withoutIcon: PropTypes.bool,
|
||||
};
|
||||
|
||||
DropDownItem.defaultProps = {
|
||||
@ -81,6 +102,9 @@ DropDownItem.defaultProps = {
|
||||
noHover: false,
|
||||
textOverflow: false,
|
||||
fillIcon: true,
|
||||
isSubMenu: false,
|
||||
isActive: false,
|
||||
withoutIcon: false,
|
||||
};
|
||||
|
||||
export default DropDownItem;
|
||||
|
@ -105,6 +105,22 @@ const StyledDropdownItem = styled.div`
|
||||
}
|
||||
|
||||
${(props) => props.disabled && disabledAndHeaderStyle}
|
||||
|
||||
.submenu-arrow {
|
||||
margin-left: auto;
|
||||
${(props) =>
|
||||
props.isActive &&
|
||||
css`
|
||||
transform: rotate(90deg);
|
||||
`}
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
props.isActive &&
|
||||
css`
|
||||
background-color: ${(props) =>
|
||||
props.theme.dropDownItem.hoverBackgroundColor} !important;
|
||||
`}
|
||||
`;
|
||||
StyledDropdownItem.defaultProps = { theme: Base };
|
||||
|
||||
|
@ -62,7 +62,7 @@ class DropDown extends React.PureComponent {
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.open !== prevProps.open) {
|
||||
if (this.props.open) {
|
||||
!isMobile && this.props.enableOnClickOutside(); //fixed main-button-mobile click, remove !isMobile if have dd problem
|
||||
this.props.enableOnClickOutside(); //fixed main-button-mobile click, remove !isMobile if have dd problem
|
||||
this.bindDocumentResizeListener();
|
||||
if (this.props.isDefaultMode) {
|
||||
return this.checkPositionPortal();
|
||||
@ -190,7 +190,7 @@ class DropDown extends React.PureComponent {
|
||||
this.dropDownRef.current.style.left =
|
||||
rects.right - this.dropDownRef.current.clientWidth + "px";
|
||||
} else {
|
||||
this.dropDownRef.current.style.left = left + "px";
|
||||
this.dropDownRef.current.style.left = left + this.props.offsetLeft + "px";
|
||||
}
|
||||
|
||||
this.dropDownRef.current.style.top = this.props.top || bottom + "px";
|
||||
@ -255,6 +255,8 @@ class DropDown extends React.PureComponent {
|
||||
directionX={directionX}
|
||||
directionY={directionY}
|
||||
manualY={manualY}
|
||||
isExternalLink={this.props.isExternalLink}
|
||||
isPersonal={this.props.isPersonal}
|
||||
{...dropDownMaxHeightProp}
|
||||
>
|
||||
{maxHeight ? (
|
||||
@ -295,7 +297,7 @@ class DropDownContainer extends React.Component {
|
||||
};
|
||||
render() {
|
||||
const { withBackdrop = true, withBlur = false, open } = this.props;
|
||||
const eventTypesProp = isMobile ? { eventTypes: ["touchend"] } : {};
|
||||
const eventTypesProp = isMobile ? { eventTypes: ["click, touchend"] } : {};
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -320,6 +322,8 @@ class DropDownContainer extends React.Component {
|
||||
DropDown.propTypes = {
|
||||
disableOnClickOutside: PropTypes.func,
|
||||
enableOnClickOutside: PropTypes.func,
|
||||
isExternalLink: PropTypes.bool,
|
||||
isPersonal: PropTypes.bool,
|
||||
};
|
||||
|
||||
DropDownContainer.propTypes = {
|
||||
@ -362,6 +366,8 @@ DropDownContainer.propTypes = {
|
||||
fixedDirection: PropTypes.bool,
|
||||
/**Enable blur for backdrop */
|
||||
withBlur: PropTypes.bool,
|
||||
|
||||
offsetLeft: PropTypes.number,
|
||||
};
|
||||
|
||||
DropDownContainer.defaultProps = {
|
||||
@ -371,6 +377,7 @@ DropDownContainer.defaultProps = {
|
||||
showDisabledItems: false,
|
||||
isDefaultMode: true,
|
||||
fixedDirection: false,
|
||||
offsetLeft: 0,
|
||||
};
|
||||
|
||||
export default DropDownContainer;
|
||||
|
@ -2,6 +2,17 @@ import styled, { css } from "styled-components";
|
||||
import Base from "../themes/base";
|
||||
|
||||
const StyledDropdown = styled.div`
|
||||
@media (orientation: landscape) {
|
||||
${(props) =>
|
||||
props.isPersonal &&
|
||||
props.isExternalLink &&
|
||||
window.innerHeight < 500 &&
|
||||
css`
|
||||
top: 10% !important;
|
||||
left: 45% !important;
|
||||
`}
|
||||
}
|
||||
|
||||
font-family: ${(props) => props.theme.fontFamily};
|
||||
font-style: normal;
|
||||
font-weight: ${(props) => props.theme.dropDown.fontWeight};
|
||||
@ -59,6 +70,12 @@ const StyledDropdown = styled.div`
|
||||
-moz-column-count: ${props.columnCount};
|
||||
column-count: ${props.columnCount};
|
||||
`}
|
||||
|
||||
.scroll-drop-down-item {
|
||||
.scroll-body {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
StyledDropdown.defaultProps = { theme: Base };
|
||||
|
@ -10,6 +10,8 @@ import {
|
||||
StyledLinkWithDropdown,
|
||||
Caret,
|
||||
} from "./styled-link-with-dropdown";
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
import Scrollbar from "@appserver/components/scrollbar";
|
||||
|
||||
class LinkWithDropdown extends React.Component {
|
||||
constructor(props) {
|
||||
@ -17,6 +19,7 @@ class LinkWithDropdown extends React.Component {
|
||||
|
||||
this.state = {
|
||||
isOpen: props.isOpen,
|
||||
orientation: window.orientation,
|
||||
};
|
||||
|
||||
this.ref = React.createRef();
|
||||
@ -35,6 +38,16 @@ class LinkWithDropdown extends React.Component {
|
||||
this.setIsOpen(!this.state.isOpen);
|
||||
};
|
||||
|
||||
onSetOrientation = () => {
|
||||
this.setState({
|
||||
orientation: window.orientation,
|
||||
});
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener("orientationchange", this.onSetOrientation);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.dropdownType !== prevProps.dropdownType) {
|
||||
if (this.props.isOpen !== prevProps.isOpen) {
|
||||
@ -45,6 +58,10 @@ class LinkWithDropdown extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("orientationchange", this.onSetOrientation);
|
||||
}
|
||||
|
||||
onClickDropDownItem = (e) => {
|
||||
const { key } = e.target.dataset;
|
||||
const item = this.props.data.find((x) => x.key === key);
|
||||
@ -52,6 +69,15 @@ class LinkWithDropdown extends React.Component {
|
||||
item && item.onClick && item.onClick(e);
|
||||
};
|
||||
|
||||
onCheckManualWidth = () => {
|
||||
const padding = 32;
|
||||
const width = this.ref.current
|
||||
?.querySelector(".text")
|
||||
.getBoundingClientRect().width;
|
||||
|
||||
return width + padding + "px";
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
return !equal(this.props, nextProps) || !equal(this.state, nextState);
|
||||
}
|
||||
@ -74,9 +100,24 @@ class LinkWithDropdown extends React.Component {
|
||||
isDisabled,
|
||||
directionY,
|
||||
theme,
|
||||
hasScroll,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
const showScroll =
|
||||
hasScroll && isMobileOnly && this.state.orientation === 90;
|
||||
|
||||
const dropDownItem = data.map((item) => (
|
||||
<DropDownItem
|
||||
className="drop-down-item"
|
||||
key={item.key}
|
||||
{...item}
|
||||
onClick={this.onClickDropDownItem}
|
||||
data-key={item.key}
|
||||
textOverflow={isTextOverflow}
|
||||
/>
|
||||
));
|
||||
|
||||
return (
|
||||
<StyledSpan className={className} id={id} style={style} ref={this.ref}>
|
||||
<span onClick={this.onOpen}>
|
||||
@ -87,6 +128,7 @@ class LinkWithDropdown extends React.Component {
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
<StyledText
|
||||
className="text"
|
||||
isTextOverflow={isTextOverflow}
|
||||
truncate={isTextOverflow}
|
||||
fontSize={fontSize}
|
||||
@ -109,6 +151,7 @@ class LinkWithDropdown extends React.Component {
|
||||
</span>
|
||||
<DropDown
|
||||
className="fixed-max-width"
|
||||
manualWidth={showScroll ? this.onCheckManualWidth() : null}
|
||||
open={this.state.isOpen}
|
||||
withArrow={false}
|
||||
forwardedRef={this.ref}
|
||||
@ -116,16 +159,18 @@ class LinkWithDropdown extends React.Component {
|
||||
clickOutsideAction={this.onClose}
|
||||
{...rest}
|
||||
>
|
||||
{data.map((item) => (
|
||||
<DropDownItem
|
||||
className="drop-down-item"
|
||||
key={item.key}
|
||||
{...item}
|
||||
onClick={this.onClickDropDownItem}
|
||||
data-key={item.key}
|
||||
textOverflow={isTextOverflow}
|
||||
/>
|
||||
))}
|
||||
{showScroll ? (
|
||||
<Scrollbar
|
||||
className="scroll-drop-down-item"
|
||||
style={{
|
||||
height: 108,
|
||||
}}
|
||||
>
|
||||
{dropDownItem}
|
||||
</Scrollbar>
|
||||
) : (
|
||||
dropDownItem
|
||||
)}
|
||||
</DropDown>
|
||||
</StyledSpan>
|
||||
);
|
||||
@ -166,6 +211,7 @@ LinkWithDropdown.propTypes = {
|
||||
isDisabled: PropTypes.bool,
|
||||
/** Sets the opening direction relative to the parent */
|
||||
directionY: PropTypes.oneOf(["bottom", "top", "both"]),
|
||||
hasScroll: PropTypes.bool,
|
||||
};
|
||||
|
||||
LinkWithDropdown.defaultProps = {
|
||||
@ -178,6 +224,7 @@ LinkWithDropdown.defaultProps = {
|
||||
isOpen: false,
|
||||
className: "",
|
||||
isDisabled: false,
|
||||
hasScroll: false,
|
||||
};
|
||||
|
||||
export default LinkWithDropdown;
|
||||
|
@ -25,6 +25,8 @@ import styled from "styled-components";
|
||||
import ButtonAlertIcon from "../../../public/images/main-button.alert.react.svg";
|
||||
import commonIconsStyles from "../utils/common-icons-style";
|
||||
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
|
||||
const StyledButtonAlertIcon = styled(ButtonAlertIcon)`
|
||||
${commonIconsStyles}
|
||||
`;
|
||||
@ -116,6 +118,7 @@ const MainButtonMobile = (props) => {
|
||||
const [isOpen, setIsOpen] = useState(opened);
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
const [height, setHeight] = useState(window.innerHeight - 48 + "px");
|
||||
const [isOpenSubMenu, setIsOpenSubMenu] = useState(false);
|
||||
|
||||
const divRef = useRef();
|
||||
const ref = useRef();
|
||||
@ -184,7 +187,7 @@ const MainButtonMobile = (props) => {
|
||||
|
||||
useEffect(() => {
|
||||
recalculateHeight();
|
||||
}, [isOpen, isOpenButton, window.innerHeight, isUploading]);
|
||||
}, [isOpen, isOpenButton, window.innerHeight, isUploading, isOpenSubMenu]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("resize", recalculateHeight);
|
||||
@ -220,6 +223,8 @@ const MainButtonMobile = (props) => {
|
||||
}
|
||||
}, [progressOptions]);
|
||||
|
||||
const noHover = isMobileOnly ? true : false;
|
||||
|
||||
const renderItems = () => {
|
||||
return (
|
||||
<StyledRenderItem ref={divRef}>
|
||||
@ -230,6 +235,50 @@ const MainButtonMobile = (props) => {
|
||||
option.onClick && option.onClick({ action: option.action });
|
||||
};
|
||||
|
||||
const onClickSub = () => {
|
||||
setIsOpenSubMenu(!isOpenSubMenu);
|
||||
};
|
||||
|
||||
if (option.items)
|
||||
return (
|
||||
<div key="mobile-submenu">
|
||||
<StyledDropDownItem
|
||||
key={option.key}
|
||||
label={option.label}
|
||||
className={`${option.className} ${
|
||||
option.isSeparator && "is-separator"
|
||||
}`}
|
||||
onClick={onClickSub}
|
||||
icon={option.icon ? option.icon : ""}
|
||||
action={option.action}
|
||||
isActive={isOpenSubMenu}
|
||||
isSubMenu={true}
|
||||
noHover={noHover}
|
||||
/>
|
||||
{isOpenSubMenu &&
|
||||
option.items.map((item) => {
|
||||
const subMenuOnClickAction = () => {
|
||||
toggle(false);
|
||||
setIsOpenSubMenu(false);
|
||||
item.onClick && item.onClick({ action: item.action });
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledDropDownItem
|
||||
key={item.key}
|
||||
label={item.label}
|
||||
className={`${item.className} sublevel`}
|
||||
onClick={subMenuOnClickAction}
|
||||
icon={item.icon ? item.icon : ""}
|
||||
action={item.action}
|
||||
withoutIcon={item.withoutIcon}
|
||||
noHover={noHover}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledDropDownItem
|
||||
key={option.key}
|
||||
@ -240,6 +289,7 @@ const MainButtonMobile = (props) => {
|
||||
onClick={optionOnClickAction}
|
||||
icon={option.icon ? option.icon : ""}
|
||||
action={option.action}
|
||||
noHover={noHover}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -134,7 +134,9 @@ const StyledDropDown = styled(DropDown)`
|
||||
|
||||
&:hover {
|
||||
background-color: ${(props) =>
|
||||
props.theme.mainButtonMobile.dropDown.hoverButtonColor};
|
||||
isMobileOnly
|
||||
? props.theme.mainButtonMobile.buttonOptions.backgroundColor
|
||||
: props.theme.mainButtonMobile.dropDown.hoverButtonColor};
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,6 +167,10 @@ StyledButtonOptions.defaultProps = { theme: Base };
|
||||
|
||||
const StyledContainerAction = styled.div`
|
||||
padding: 16px 0px;
|
||||
|
||||
.sublevel {
|
||||
padding-left: 48px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledButtonWrapper = styled.div`
|
||||
|
@ -40,7 +40,7 @@ const Paging = (props) => {
|
||||
return (
|
||||
<StyledPaging id={id} className={className} style={style}>
|
||||
<Button
|
||||
className="buttonCustomStyle not-selectable"
|
||||
className="not-selectable"
|
||||
size="small"
|
||||
scale={true}
|
||||
label={previousLabel}
|
||||
@ -51,6 +51,7 @@ const Paging = (props) => {
|
||||
{pageItems && (
|
||||
<StyledPage>
|
||||
<ComboBox
|
||||
isDisabled={disablePrevious && disableNext}
|
||||
className="manualWidth"
|
||||
directionY={openDirection}
|
||||
options={pageItems}
|
||||
@ -62,7 +63,7 @@ const Paging = (props) => {
|
||||
</StyledPage>
|
||||
)}
|
||||
<Button
|
||||
className="buttonCustomStyle not-selectable"
|
||||
className="not-selectable"
|
||||
size="small"
|
||||
scale={true}
|
||||
label={nextLabel}
|
||||
|
@ -10,10 +10,6 @@ const StyledPaging = styled.div`
|
||||
margin-right: ${(props) => props.theme.paging.button.marginRight};
|
||||
max-width: ${(props) => props.theme.paging.button.maxWidth};
|
||||
}
|
||||
|
||||
.buttonCustomStyle {
|
||||
padding: ${(props) => props.theme.paging.button.padding};
|
||||
}
|
||||
`;
|
||||
StyledPaging.defaultProps = { theme: Base };
|
||||
|
||||
|
@ -30,7 +30,12 @@ const StyledRow = styled.div`
|
||||
align-content: center;
|
||||
|
||||
.row-loader {
|
||||
padding: 15px 12px 12px 0px;
|
||||
padding: 0;
|
||||
margin-left: 9px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
|
@ -48,10 +48,14 @@ class SaveCancelButtons extends React.Component {
|
||||
className,
|
||||
id,
|
||||
isSaving,
|
||||
cancelEnable,
|
||||
} = this.props;
|
||||
|
||||
const cancelButtonDisabled =
|
||||
isFirstWelcomePageSettings === "true" ? false : !showReminder;
|
||||
const cancelButtonDisabled = cancelEnable
|
||||
? false
|
||||
: isFirstWelcomePageSettings === "true"
|
||||
? false
|
||||
: !showReminder;
|
||||
|
||||
return (
|
||||
<StyledSaveCancelButtons
|
||||
@ -112,6 +116,7 @@ SaveCancelButtons.propTypes = {
|
||||
minwidth: PropTypes.string,
|
||||
isFirstWelcomePageSettings: PropTypes.string,
|
||||
isSaving: PropTypes.bool,
|
||||
cancelEnable: PropTypes.bool,
|
||||
};
|
||||
|
||||
SaveCancelButtons.defaultProps = {
|
||||
|
@ -613,7 +613,6 @@ const Base = {
|
||||
button: {
|
||||
marginRight: "8px",
|
||||
maxWidth: "110px",
|
||||
padding: "6px 8px 10px",
|
||||
},
|
||||
|
||||
page: {
|
||||
@ -2571,6 +2570,10 @@ const Base = {
|
||||
},
|
||||
},
|
||||
|
||||
downloadDialog: {
|
||||
background: "#f8f9f9",
|
||||
},
|
||||
|
||||
studio: {
|
||||
about: {
|
||||
linkColor: blueMain,
|
||||
|
@ -611,7 +611,6 @@ const Dark = {
|
||||
button: {
|
||||
marginRight: "8px",
|
||||
maxWidth: "110px",
|
||||
padding: "6px 8px 10px",
|
||||
},
|
||||
|
||||
page: {
|
||||
@ -2521,8 +2520,8 @@ const Dark = {
|
||||
|
||||
badge: {
|
||||
color: black,
|
||||
stroke: "#858585",
|
||||
fill: "#858585",
|
||||
stroke: "#ADADAD",
|
||||
fill: "#ADADAD",
|
||||
defaultFill: black,
|
||||
badgeFill: "#F58D31",
|
||||
},
|
||||
@ -2581,6 +2580,10 @@ const Dark = {
|
||||
},
|
||||
},
|
||||
|
||||
downloadDialog: {
|
||||
background: "#282828",
|
||||
},
|
||||
|
||||
studio: {
|
||||
about: {
|
||||
linkColor: "#E06A1B",
|
||||
|
@ -20,6 +20,7 @@ const StyledToastContainer = styled(ToastContainer)`
|
||||
animation: Toastify__trackProgress linear 1 forwards;
|
||||
}
|
||||
.Toastify__toast-body {
|
||||
overflow-wrap: anywhere;
|
||||
margin: auto 0;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
|
@ -14,6 +14,8 @@ export default function getCorrectDate(locale, date) {
|
||||
// .toLocaleString(locale, options)
|
||||
// .replace(",", "");
|
||||
|
||||
if (!date || date === "0001-01-01T00:00:00.0000000Z") return "—";
|
||||
|
||||
const curDate = moment(date).locale(locale).format("L");
|
||||
const curTime = moment(date).locale(locale).format("LT");
|
||||
|
||||
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"ModuleDescription": "Կառավարեք Ձեր կոնտակտները և վաճառքները"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import Backend from "@appserver/common/utils/i18next-http-backend";
|
||||
import config from "../package.json";
|
||||
import { LANGUAGE } from "@appserver/common/constants";
|
||||
import { loadLanguagePath } from "@appserver/common/utils";
|
||||
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"ModuleDescription": "Պլանավորել հանդիպումներ և իրադարձություններ"
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import Backend from "@appserver/common/utils/i18next-http-backend";
|
||||
import config from "../package.json";
|
||||
import { LANGUAGE } from "@appserver/common/constants";
|
||||
import { loadLanguagePath } from "@appserver/common/utils";
|
||||
|
@ -0,0 +1,10 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_26408_15469)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 1C0.895431 1 0 1.89543 0 3V13C0 14.1046 0.89543 15 2 15H5V13H2V3L6.58579 3L9 5.41421C9.37507 5.78929 9.88378 6 10.4142 6H14V13H11V15H14C15.1046 15 16 14.1046 16 13V6C16 4.89543 15.1046 4 14 4H10.4142L8 1.58579C7.62493 1.21071 7.11622 1 6.58579 1H2ZM5.70711 11.7071L7 10.4142V15H9V10.4142L10.2929 11.7071L11.7071 10.2929L8.70711 7.29289C8.51957 7.10536 8.26522 7 8 7C7.73478 7 7.48043 7.10536 7.29289 7.29289L4.29289 10.2929L5.70711 11.7071Z" fill="#333333"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_26408_15469">
|
||||
<rect width="16" height="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 764 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 3C1 1.89543 1.89543 1 3 1H8H10C10.2652 1 10.5196 1.10536 10.7071 1.29289L14.7071 5.29289C14.8946 5.48043 15 5.73478 15 6V8V13C15 14.1046 14.1046 15 13 15H3C1.89543 15 1 14.1046 1 13V3ZM12.5858 6L10 3.41421V6L12.5858 6ZM8 6V3L3 3V13H13V8L8 8V7V6Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 419 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="M4.85714 0C3.83147 0 3 0.83147 3 1.85714V2H5H14V11V13H14.1429C15.1685 13 16 12.1685 16 11.1429V1.85714C16 0.831472 15.1685 0 14.1429 0H4.85714ZM0 4.85714C0 3.83147 0.831472 3 1.85714 3H11.1429C12.1685 3 13 3.83147 13 4.85714V14.1429C13 15.1685 12.1685 16 11.1429 16H1.85714C0.83147 16 0 15.1685 0 14.1429V4.85714ZM11 5H2V14H11V5ZM10 6H3V8H10V6ZM5 9H10V11H5V9Z" fill="#333333"/>
|
||||
</svg>
|
After Width: | Height: | Size: 530 B |
@ -1,6 +1,5 @@
|
||||
{
|
||||
"EmptyScreenDescription": "Lütfən, internet bağlantınızı yoxlayın və səhifəni yeniləyin, yaxud da bir qədər sonra yenidən yoxlayın",
|
||||
"FormTemplateInfo": "Forma şablonu məlumatı",
|
||||
"GalleryEmptyScreenDescription": "Detalları görmək üçün istənilən forma şablonunu seçin",
|
||||
"GalleryEmptyScreenHeader": "Forma şablonlarının yüklənməsi uğursuz oldu",
|
||||
"TemplateInfo": "Şablon məlumatı"
|
||||
|
@ -66,7 +66,6 @@
|
||||
"SendByEmail": "Elektron poçt vasitəsi ilə göndər",
|
||||
"Share": "Paylaş",
|
||||
"SharedEmptyContainerDescription": "'Mənimlə Paylaşılanlar' bölməsi komanda yoldaşlarınız tərəfindən sizinlə paylaşılan faylları göstərir. Ən son dəyişiklikləri görməmisinizsə, onlar yeni olaraq qeyd olunur. Kontekst menyusundan istifadə edərək faylları siyahıdan silə bilərsiniz. ",
|
||||
"SharingSettings": "Paylaşma sazlamaları",
|
||||
"ShowVersionHistory": "Versiya tarixçəsinə bax",
|
||||
"Spreadsheet": "Cədvəl",
|
||||
"SubheadingEmptyText": "Bu bölmə üzrə heç bir fayl yoxdur",
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"MoveConfirmation": "Yerdəyişmənin təsdiqi",
|
||||
"MoveConfirmationAlert": "Elementlərin yerini dəyişmək istədiyinizdən əminsinizmi?",
|
||||
"MoveConfirmationMessage": "Elementləri {{provider}} qovluğundan köçürmək üzrəsiniz. Onlar {{provider}} hesabınızdan silinəcək və artıq digər istifadəçilər üçün əlçatan olmayacaq. "
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
"DeleteFromTrash": "Seçilmiş elementlər zibil qutusundan silindi",
|
||||
"DeleteOperation": "Silinir",
|
||||
"DeleteSelectedElem": "Seçilmiş elementlər müvəffəqiyyətlə silindi",
|
||||
"DeleteThirdParty": "Üçüncü tərəf mənbələrin silinməsi",
|
||||
"DownloadApps": "Tətbiqləri endirin",
|
||||
"DownloadAs": "Kimi yüklə",
|
||||
"EncryptedFileSaving": "Şifrlənmiş faylın yaddaşda saxlanılması",
|
||||
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"EmptyScreenDescription": "Моля, проверете интернет връзка си и опреснете страницата или опитайте по-късно",
|
||||
"FormTemplateInfo": "Информация за шаблон на формуляр",
|
||||
"GalleryEmptyScreenDescription": "Изберете всеки шаблон на формуляр, за да видите подробностите",
|
||||
"GalleryEmptyScreenHeader": "Неуспешно зареждане на шаблони за формуляри",
|
||||
"TemplateInfo": "Информация за шаблона"
|
||||
|
@ -66,7 +66,6 @@
|
||||
"SendByEmail": "Изпратен по имейл",
|
||||
"Share": "Сподели",
|
||||
"SharedEmptyContainerDescription": "Разделът 'Споделено с мен' показва файлове, споделени с Вас от съотборниците Ви. Ако не сте видели последните промени, те са маркирани като нови. Можете да премахвате файловете от списъка с помощта на контекстното меню.",
|
||||
"SharingSettings": "Настройки за споделяне",
|
||||
"ShowVersionHistory": "Покажи история на версията",
|
||||
"Spreadsheet": "Таблица",
|
||||
"SubheadingEmptyText": "Няма файлове за показване в този раздел",
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"MoveConfirmation": "Потвърждение за преместване",
|
||||
"MoveConfirmationAlert": "Сигурни ли сте, че искате да преместите елементите?",
|
||||
"MoveConfirmationMessage": "Ще преместите елементи от директорията {{provider}}. Те ще бъдат изтрити от вашия {{provider}} профил и другите потребители няма да имат достъп до тях."
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
"DeleteFromTrash": "Избраните елементи бяха успешно изтрити от Кошчето",
|
||||
"DeleteOperation": "Изтриване",
|
||||
"DeleteSelectedElem": "Избраните елементи бяха успешно изтрити",
|
||||
"DeleteThirdParty": "Изтрий трето лице",
|
||||
"DownloadApps": "Изтегли приложенията",
|
||||
"DownloadAs": "Изтегли като",
|
||||
"EncryptedFileSaving": "Запазване на криптиран файл",
|
||||
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"EmptyScreenDescription": "Zkontrolujte prosím své internetové připojení a obnovte stránku nebo to zkuste později",
|
||||
"FormTemplateInfo": "Informace o šabloně formuláře",
|
||||
"GalleryEmptyScreenDescription": "Pro zobrazení podrobností vyberte libovolnou šablonu formuláře",
|
||||
"GalleryEmptyScreenHeader": "Nepodařilo se načíst šablony formulářů",
|
||||
"TemplateInfo": "Informace o šabloně"
|
||||
|
@ -66,7 +66,6 @@
|
||||
"SendByEmail": "Odeslat emailem",
|
||||
"Share": "Sdílet",
|
||||
"SharedEmptyContainerDescription": "V sekci 'Sdíleno se mnou' se zobrazují soubory které vám nasdíleli spoluhráči. Pokud jste neviděli poslední změny jsou označeny jako nové. Soubory můžete ze seznamu odstranit pomocí kontextové nabídky.",
|
||||
"SharingSettings": "Nastavení sdílení",
|
||||
"ShowVersionHistory": "Zobrazit historii verzí",
|
||||
"Spreadsheet": "Tabulka",
|
||||
"SubheadingEmptyText": "V této sekci se nezobrazují žádné soubory",
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"MoveConfirmation": "Potvrzení přesunu",
|
||||
"MoveConfirmationAlert": "Určitě chcete přesunout prvky?",
|
||||
"MoveConfirmationMessage": "Chystáte se přesunout prvky z adresáře {{provider}}. Budou smazány z vašeho účtu {{provider}} a nebudou již přístupné ostatním uživatelům."
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
"DeleteFromTrash": "Vybrané prvky byly úspěšně odstraněny z koše",
|
||||
"DeleteOperation": "Mazání",
|
||||
"DeleteSelectedElem": "Vybrané prvky byly úspěšně odstraněny",
|
||||
"DeleteThirdParty": "Smazat třetí stranu",
|
||||
"DownloadApps": "Aplikace ke staženi",
|
||||
"DownloadAs": "Stáhnout jako",
|
||||
"EncryptedFileSaving": "Uložení zašifrovaného souboru",
|
||||
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"EmptyScreenDescription": "Bitte überprüfen Sie Ihre Internetverbindung und laden Sie die Seite neu oder versuchen Sie es später",
|
||||
"FormTemplateInfo": "Informationen zur Formularvorlage",
|
||||
"GalleryEmptyScreenDescription": "Wählen Sie eine beliebige Formularvorlage aus, um die Details zu sehen",
|
||||
"GalleryEmptyScreenHeader": "Formularvorlagen konnten nicht geladen werden",
|
||||
"TemplateInfo": "Informationen zur Vorlage"
|
||||
|
@ -66,7 +66,6 @@
|
||||
"SendByEmail": "Per E-Mail senden",
|
||||
"Share": "Freigeben",
|
||||
"SharedEmptyContainerDescription": "'Für mich freigegeben' ist der Bereich mit geteilten Dateien. Wenn Sie die letzten Änderungen nicht gesehen haben, werden diese als neue gekennzeichnet. Im Kontextmenü können Sie die Dateien aus der Liste entfernen.",
|
||||
"SharingSettings": "Freigabeeinstellungen",
|
||||
"ShowVersionHistory": "Versionshistorie anzeigen",
|
||||
"Spreadsheet": "Tabellenkalkulation",
|
||||
"SubheadingEmptyText": "In dieser Sektion gibt es keine Dateien zum Anzeigen.",
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"MoveConfirmation": "Verschiebung bestätigen",
|
||||
"MoveConfirmationAlert": "Möchten Sie diese Elemente wirklich verschieben?",
|
||||
"MoveConfirmationMessage": "Sie verschieben Elemente aus dem Ordner {{provider}}. Diese werden aus dem Konto {{provider}} entfernt und für andere Benutzer unverfügbar."
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
"DeleteFromTrash": "Die ausgewählten Elemente wurden aus dem Papierkorb gelöscht",
|
||||
"DeleteOperation": "Löschen",
|
||||
"DeleteSelectedElem": "Die ausgewählten Elemente wurden gelöscht",
|
||||
"DeleteThirdParty": "Drittanbieterdienst deaktivieren",
|
||||
"DownloadApps": "Apps herunterladen",
|
||||
"DownloadAs": "Herunterladen als",
|
||||
"EncryptedFileSaving": "Die verschlüsselte Datei wird gespeichert",
|
||||
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"EmptyScreenDescription": "Ελέγξτε τη σύνδεσή σας στο διαδίκτυο και ανανεώστε τη σελίδα ή δοκιμάστε αργότερα",
|
||||
"FormTemplateInfo": "Πληροφορίες προτύπου φόρμας",
|
||||
"GalleryEmptyScreenDescription": "Επιλέξτε οποιοδήποτε πρότυπο φόρμας για να δείτε τις λεπτομέρειες",
|
||||
"GalleryEmptyScreenHeader": "Απέτυχε η φόρτωση προτύπων φόρμας",
|
||||
"TemplateInfo": "Πληροφορίες προτύπου"
|
||||
|
@ -66,7 +66,6 @@
|
||||
"SendByEmail": "Αποστολή μέσω email",
|
||||
"Share": "Κοινή χρήση",
|
||||
"SharedEmptyContainerDescription": "Η ενότητα 'Κοινή χρήση με μένα' εμφανίζει τα αρχεία που μοιράζονται μαζί σας οι συνάδελφοί σας. Αν δεν έχετε δει τις τελευταίες αλλαγές, αυτές επισημαίνονται ως νέες. Μπορείτε να αφαιρέσετε τα αρχεία από τη λίστα χρησιμοποιώντας το μενού περιβάλλοντος.",
|
||||
"SharingSettings": "Ρυθμίσεις κοινής χρήσης",
|
||||
"ShowVersionHistory": "Εμφάνιση ιστορικού έκδοσης",
|
||||
"Spreadsheet": "Υπολογιστικό φύλλο",
|
||||
"SubheadingEmptyText": "Δεν υπάρχουν αρχεία που θα εμφανιστούν σε αυτήν την ενότητα",
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"MoveConfirmation": "Επιβεβαίωση μετακίνησης",
|
||||
"MoveConfirmationAlert": "Θέλετε σίγουρα να μετακινήσετε τα στοιχεία;",
|
||||
"MoveConfirmationMessage": "Πρόκειται να μετακινήσετε στοιχεία από τον κατάλογο {{provider}}. Αυτά θα διαγραφούν από το λογαριασμό σας {{provider}} και δεν θα είναι πλέον προσβάσιμα σε άλλους χρήστες."
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
"DeleteFromTrash": "Τα επιλεγμένα στοιχεία διαγράφηκαν επιτυχώς από τον Κάδο απορριμμάτων",
|
||||
"DeleteOperation": "Διαγραφή",
|
||||
"DeleteSelectedElem": "Τα επιλεγμένα στοιχεία διαγράφηκαν με επιτυχία",
|
||||
"DeleteThirdParty": "Διαγραφή τρίτου μέρους",
|
||||
"DownloadApps": "Λήψη εφαρμογών",
|
||||
"DownloadAs": "Λήψη ως",
|
||||
"EncryptedFileSaving": "Αποθήκευση κρυπτογραφημένου αρχείου",
|
||||
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"EmptyScreenDescription": "Please check your Internet connection and refresh the page or try later",
|
||||
"FormTemplateInfo": "Form template info",
|
||||
"GalleryEmptyScreenDescription": "Select any form template to see the details",
|
||||
"GalleryEmptyScreenHeader": "Failed to load form templates",
|
||||
"TemplateInfo": "Template info"
|
||||
|
@ -66,7 +66,6 @@
|
||||
"SendByEmail": "Send by email",
|
||||
"Share": "Share",
|
||||
"SharedEmptyContainerDescription": "The 'Shared with Me' section shows files shared to you by teammates. If you haven't seen the latest changes, they are marked as new. You can remove the files from the list using the context menu. ",
|
||||
"SharingSettings": "Sharing settings",
|
||||
"ShowVersionHistory": "Show version history",
|
||||
"Spreadsheet": "Spreadsheet",
|
||||
"SubheadingEmptyText": "No files to be displayed in this section",
|
||||
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"MoveConfirmation": "Move confirmation",
|
||||
"MoveConfirmationAlert": "Are you sure you want to move the elements?",
|
||||
"MoveConfirmationMessage": "You are about to move elements from the {{provider}} directory. They will be deleted from your {{provider}} account and will no longer be accessible to other users."
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
"DeleteFromTrash": "Selected elements were successfully deleted from Trash",
|
||||
"DeleteOperation": "Deleting",
|
||||
"DeleteSelectedElem": "Selected elements were successfully deleted",
|
||||
"DeleteThirdParty": "Delete third-party",
|
||||
"DownloadApps": "Download applications",
|
||||
"DownloadAs": "Download as",
|
||||
"EncryptedFileSaving": "Saving encrypted file",
|
||||
|
@ -1,6 +1,5 @@
|
||||
{
|
||||
"EmptyScreenDescription": "Por favor, compruebe su conexión a Internet y actualice la página o inténtelo más tarde",
|
||||
"FormTemplateInfo": "Información sobre la plantilla de formulario",
|
||||
"GalleryEmptyScreenDescription": "Seleccione cualquier plantilla de formulario para ver los detalles",
|
||||
"GalleryEmptyScreenHeader": "Error al cargar las plantillas de formulario",
|
||||
"TemplateInfo": "Información sobre la plantilla"
|
||||
|
@ -66,7 +66,6 @@
|
||||
"SendByEmail": "Enviar por correo electrónico",
|
||||
"Share": "Compartir",
|
||||
"SharedEmptyContainerDescription": "La sección 'Compartido para mi' muestra los archivos que sus compañeros de equipo han compartido con usted. Si usted no ha visto los últimos cambios, están marcados como nuevos. Es posible eliminar los archivos de la lista mediante el menú contextual. ",
|
||||
"SharingSettings": "Configuración de uso compartido",
|
||||
"ShowVersionHistory": "Mostrar historial de versiones",
|
||||
"Spreadsheet": "Hoja de cálculo",
|
||||
"SubheadingEmptyText": "No hay archivos para mostrar en esta sección",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user