Merge branch 'develop' into feature/integration-system

This commit is contained in:
Ilya Oleshko 2022-07-11 13:12:25 +03:00
commit 81a62b4b2a
425 changed files with 3524 additions and 1285 deletions

View 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);
}
});

View File

@ -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;

View File

@ -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();

View File

@ -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)

View File

@ -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);

View File

@ -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>

View File

@ -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;

View File

@ -26,6 +26,7 @@
namespace ASC.Common.Security.Authorizing;
[EnumExtensions]
public enum AceType
{
Allow,

View File

@ -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;
}

View File

@ -31,6 +31,7 @@ namespace ASC.Core.Users;
[Flags]
[JsonConverter(typeof(JsonStringEnumConverter))]
[EnumExtensions]
public enum EmployeeType
{
All = 0,

View File

@ -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;
}

View File

@ -26,6 +26,7 @@
namespace ASC.Core;
[EnumExtensions]
public enum UserGroupRefType
{
Contains,

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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",

View File

@ -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>

View File

@ -57,4 +57,6 @@ global using CsvHelper.Configuration;
global using Microsoft.Extensions.Logging;
global using NetEscapades.EnumGenerators;
global using Newtonsoft.Json;

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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,

View File

@ -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))
{

View File

@ -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;

View File

@ -1,4 +1,3 @@
{
"kafka": {
}
"kafka": {}
}

View File

@ -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}",

View File

@ -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 &&

View File

@ -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 />

View File

@ -50,7 +50,7 @@ const StyledFilterBlock = styled.div`
}
.filter-body {
height: calc(100% - 125px);
height: ${(props) => (props.showFooter ? "calc(100% - 125px)" : "100%")};
}
`;

View File

@ -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 {

View File

@ -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}

View File

@ -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;

View File

@ -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";

View File

@ -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) =>

View File

@ -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"],

View File

@ -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",

View File

@ -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";

View File

@ -0,0 +1,2 @@
import backend from './lib/index.js'
export default backend

View File

@ -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
}

View 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;

View File

@ -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

View File

@ -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)
}

View 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;

View File

@ -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);

View File

@ -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>
)}

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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) => {

View File

@ -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;

View File

@ -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 };

View File

@ -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;

View File

@ -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 };

View File

@ -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;

View File

@ -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}
/>
);
})}

View File

@ -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`

View File

@ -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}

View File

@ -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 };

View File

@ -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) =>

View File

@ -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 = {

View File

@ -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,

View File

@ -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",

View File

@ -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;

View File

@ -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");

View File

@ -0,0 +1,3 @@
{
"ModuleDescription": "Կառավարեք Ձեր կոնտակտները և վաճառքները"
}

View File

@ -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";

View File

@ -0,0 +1,4 @@
{
"ModuleDescription": "Պլանավորել հանդիպումներ և իրադարձություններ"
}

View File

@ -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";

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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ı"

View File

@ -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",

View File

@ -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. "
}

View File

@ -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ı",

View File

@ -1,6 +1,5 @@
{
"EmptyScreenDescription": "Моля, проверете интернет връзка си и опреснете страницата или опитайте по-късно",
"FormTemplateInfo": "Информация за шаблон на формуляр",
"GalleryEmptyScreenDescription": "Изберете всеки шаблон на формуляр, за да видите подробностите",
"GalleryEmptyScreenHeader": "Неуспешно зареждане на шаблони за формуляри",
"TemplateInfo": "Информация за шаблона"

View File

@ -66,7 +66,6 @@
"SendByEmail": "Изпратен по имейл",
"Share": "Сподели",
"SharedEmptyContainerDescription": "Разделът 'Споделено с мен' показва файлове, споделени с Вас от съотборниците Ви. Ако не сте видели последните промени, те са маркирани като нови. Можете да премахвате файловете от списъка с помощта на контекстното меню.",
"SharingSettings": "Настройки за споделяне",
"ShowVersionHistory": "Покажи история на версията",
"Spreadsheet": "Таблица",
"SubheadingEmptyText": "Няма файлове за показване в този раздел",

View File

@ -1,5 +1,4 @@
{
"MoveConfirmation": "Потвърждение за преместване",
"MoveConfirmationAlert": "Сигурни ли сте, че искате да преместите елементите?",
"MoveConfirmationMessage": "Ще преместите елементи от директорията {{provider}}. Те ще бъдат изтрити от вашия {{provider}} профил и другите потребители няма да имат достъп до тях."
}

View File

@ -10,7 +10,6 @@
"DeleteFromTrash": "Избраните елементи бяха успешно изтрити от Кошчето",
"DeleteOperation": "Изтриване",
"DeleteSelectedElem": "Избраните елементи бяха успешно изтрити",
"DeleteThirdParty": "Изтрий трето лице",
"DownloadApps": "Изтегли приложенията",
"DownloadAs": "Изтегли като",
"EncryptedFileSaving": "Запазване на криптиран файл",

View File

@ -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ě"

View File

@ -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",

View File

@ -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."
}

View File

@ -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",

View File

@ -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"

View File

@ -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.",

View File

@ -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."
}

View File

@ -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",

View File

@ -1,6 +1,5 @@
{
"EmptyScreenDescription": "Ελέγξτε τη σύνδεσή σας στο διαδίκτυο και ανανεώστε τη σελίδα ή δοκιμάστε αργότερα",
"FormTemplateInfo": "Πληροφορίες προτύπου φόρμας",
"GalleryEmptyScreenDescription": "Επιλέξτε οποιοδήποτε πρότυπο φόρμας για να δείτε τις λεπτομέρειες",
"GalleryEmptyScreenHeader": "Απέτυχε η φόρτωση προτύπων φόρμας",
"TemplateInfo": "Πληροφορίες προτύπου"

View File

@ -66,7 +66,6 @@
"SendByEmail": "Αποστολή μέσω email",
"Share": "Κοινή χρήση",
"SharedEmptyContainerDescription": "Η ενότητα 'Κοινή χρήση με μένα' εμφανίζει τα αρχεία που μοιράζονται μαζί σας οι συνάδελφοί σας. Αν δεν έχετε δει τις τελευταίες αλλαγές, αυτές επισημαίνονται ως νέες. Μπορείτε να αφαιρέσετε τα αρχεία από τη λίστα χρησιμοποιώντας το μενού περιβάλλοντος.",
"SharingSettings": "Ρυθμίσεις κοινής χρήσης",
"ShowVersionHistory": "Εμφάνιση ιστορικού έκδοσης",
"Spreadsheet": "Υπολογιστικό φύλλο",
"SubheadingEmptyText": "Δεν υπάρχουν αρχεία που θα εμφανιστούν σε αυτήν την ενότητα",

View File

@ -1,5 +1,4 @@
{
"MoveConfirmation": "Επιβεβαίωση μετακίνησης",
"MoveConfirmationAlert": "Θέλετε σίγουρα να μετακινήσετε τα στοιχεία;",
"MoveConfirmationMessage": "Πρόκειται να μετακινήσετε στοιχεία από τον κατάλογο {{provider}}. Αυτά θα διαγραφούν από το λογαριασμό σας {{provider}} και δεν θα είναι πλέον προσβάσιμα σε άλλους χρήστες."
}

View File

@ -10,7 +10,6 @@
"DeleteFromTrash": "Τα επιλεγμένα στοιχεία διαγράφηκαν επιτυχώς από τον Κάδο απορριμμάτων",
"DeleteOperation": "Διαγραφή",
"DeleteSelectedElem": "Τα επιλεγμένα στοιχεία διαγράφηκαν με επιτυχία",
"DeleteThirdParty": "Διαγραφή τρίτου μέρους",
"DownloadApps": "Λήψη εφαρμογών",
"DownloadAs": "Λήψη ως",
"EncryptedFileSaving": "Αποθήκευση κρυπτογραφημένου αρχείου",

View File

@ -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"

View File

@ -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",

View File

@ -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."
}

View File

@ -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",

View 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"

View File

@ -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