Merge branch 'develop' into feature/fix-hide/show-header

# Conflicts:
#	products/ASC.Files/Client/src/components/pages/Home/index.js
This commit is contained in:
TatianaLopaeva 2020-12-24 11:03:52 +03:00
commit 6a1e80f1fb
129 changed files with 1237 additions and 754 deletions

View File

@ -202,7 +202,7 @@ namespace ASC.Core.Data
public Group GetGroup(int tenant, Guid id)
{
return GetGroupQuery(UserDbContext, tenant, default)
return GetGroupQuery(tenant)
.Where(r => r.Id == id)
.Select(FromDbGroupToGroup)
.FirstOrDefault();
@ -210,14 +210,14 @@ namespace ASC.Core.Data
public IDictionary<Guid, Group> GetGroups(int tenant, DateTime from)
{
return GetGroupQuery(UserDbContext, tenant, from)
return GetGroupQuery(tenant, from)
.Select(FromDbGroupToGroup)
.ToDictionary(r => r.Id, r => r);
}
public UserInfo GetUser(int tenant, Guid id)
{
return GetUserQuery(UserDbContext, tenant, default)
return GetUserQuery(tenant)
.Where(r => r.Id == id)
.Select(FromUserToUserInfo)
.FirstOrDefault();
@ -234,7 +234,7 @@ namespace ASC.Core.Data
var pwdHash = GetPasswordHash(userId, passwordHash);
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
var q = UserDbContext.Users
var q = GetUserQuery(tenant)
.Where(r => !r.Removed)
.Where(r => r.Id == userId)
.Join(UserDbContext.UserSecurity, r => r.Id, r => r.UserId, (user, security) => new DbUserSecurity
@ -247,22 +247,19 @@ namespace ASC.Core.Data
if (tenant != Tenant.DEFAULT_TENANT)
{
q = q.Where(r => r.User.Tenant == tenant);
q = q.Where(r => r.UserSecurity.Tenant == tenant);
}
return q.Select(r => r.User).Select(FromUserToUserInfo).FirstOrDefault();
}
else
{
var q = UserDbContext.Users
var q = GetUserQuery(tenant)
.Where(r => !r.Removed)
.Where(r => r.Email == login)
;
if (tenant != Tenant.DEFAULT_TENANT)
{
q = q.Where(r => r.Tenant == tenant);
}
var user = q.Select(FromUserToUserInfo).FirstOrDefault();
var user = q.Select(FromUserToUserInfo).Take(1).FirstOrDefault();
if (user != null)
{
RegeneratePassword(tenant, user.ID);
@ -270,12 +267,10 @@ namespace ASC.Core.Data
var pwdHash = GetPasswordHash(user.ID, passwordHash);
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
var count = UserDbContext.UserSecurity
.Where(r => r.UserId == user.ID)
.Where(r => r.PwdHash == pwdHash || r.PwdHash == oldHash)
.Count();//todo: remove old scheme
var any = UserDbContext.UserSecurity
.Any(r => r.UserId == user.ID && (r.PwdHash == pwdHash || r.PwdHash == oldHash));//todo: remove old scheme
if (count > 0) return user;
if (any) return user;
}
return null;
@ -289,6 +284,7 @@ namespace ASC.Core.Data
.Where(r => r.Tenant == tenant)
.Where(r => r.UserId == userId)
.Select(r => r.PwdHashSha512)
.Take(1)
.FirstOrDefault();
if (string.IsNullOrEmpty(h2)) return;
@ -338,7 +334,7 @@ namespace ASC.Core.Data
public IDictionary<Guid, UserInfo> GetUsers(int tenant, DateTime from)
{
return GetUserQuery(UserDbContext, tenant, from)
return GetUserQuery(tenant, from)
.Select(FromUserToUserInfo)
.ToDictionary(r => r.ID, r => r);
}
@ -346,11 +342,11 @@ namespace ASC.Core.Data
public IQueryable<UserInfo> GetUsers(int tenant, bool isAdmin, EmployeeStatus? employeeStatus, List<List<Guid>> includeGroups, List<Guid> excludeGroups, EmployeeActivationStatus? activationStatus, string text, string sortBy, bool sortOrderAsc, long limit, long offset, out int total, out int count)
{
var userDbContext = UserDbContextManager.GetNew(DbId);
var totalQuery = userDbContext.Users.Where(r => r.Tenant == tenant);
var totalQuery = GetUserQuery(userDbContext, tenant);
totalQuery = GetUserQueryForFilter(totalQuery, isAdmin, employeeStatus, includeGroups, excludeGroups, activationStatus, text);
total = totalQuery.Count();
var q = GetUserQuery(userDbContext, tenant, default);
var q = GetUserQuery(userDbContext, tenant);
q = GetUserQueryForFilter(q, isAdmin, employeeStatus, includeGroups, excludeGroups, activationStatus, text);
@ -377,8 +373,8 @@ namespace ASC.Core.Data
public IQueryable<UserInfo> GetUsers(int tenant, out int total)
{
var userDbContext = UserDbContextManager.GetNew(DbId);
total = userDbContext.Users.Where(r => r.Tenant == tenant).Count();
return userDbContext.Users.Where(r => r.Tenant == tenant).Select(FromUserToUserInfo);
total = userDbContext.Users.Count(r => r.Tenant == tenant);
return GetUserQuery(userDbContext, tenant).Select(FromUserToUserInfo);
}
@ -527,16 +523,18 @@ namespace ASC.Core.Data
user.Email = user.Email.Trim();
using var tx = UserDbContext.Database.BeginTransaction();
var count = UserDbContext.Users.Where(r => r.UserName == user.UserName && r.Id != user.ID && !r.Removed).Count();
var any = GetUserQuery(tenant)
.Any(r => r.UserName == user.UserName && r.Id != user.ID && !r.Removed);
if (count != 0)
if (any)
{
throw new ArgumentOutOfRangeException("Duplicate username.");
}
count = UserDbContext.Users.Where(r => r.Email == user.Email && r.Id != user.ID && !r.Removed).Count();
any = GetUserQuery(tenant)
.Any(r => r.Email == user.Email && r.Id != user.ID && !r.Removed);
if (count != 0)
if (any)
{
throw new ArgumentOutOfRangeException("Duplicate email.");
}
@ -559,7 +557,7 @@ namespace ASC.Core.Data
UserDbContext.AddOrUpdate(r => r.UserGroups, FromUserGroupRefToUserGroup(r));
var user = UserDbContext.Users.FirstOrDefault(a => a.Tenant == tenant && a.Id == r.UserId);
var user = GetUserQuery(tenant).FirstOrDefault(a => a.Tenant == tenant && a.Id == r.UserId);
if (user != null)
{
user.LastModified = r.LastModified;
@ -620,9 +618,14 @@ namespace ASC.Core.Data
tr.Commit();
}
private IQueryable<User> GetUserQuery(UserDbContext UserDbContext, int tenant, DateTime from)
private IQueryable<User> GetUserQuery(int tenant, DateTime from = default)
{
var q = UserDbContext.Users.Where(r => true);
return GetUserQuery(UserDbContext, tenant, from);
}
private IQueryable<User> GetUserQuery(UserDbContext userDbContext, int tenant, DateTime from = default)
{
var q = userDbContext.Users.AsQueryable();
if (tenant != Tenant.DEFAULT_TENANT)
{
@ -637,7 +640,7 @@ namespace ASC.Core.Data
return q;
}
private IQueryable<DbGroup> GetGroupQuery(UserDbContext UserDbContext, int tenant, DateTime from)
private IQueryable<DbGroup> GetGroupQuery(int tenant, DateTime from = default)
{
var q = UserDbContext.Groups.Where(r => true);
@ -752,7 +755,7 @@ namespace ASC.Core.Data
public UserInfo GetUser(int tenant, Guid id, Expression<Func<User, UserInfo>> exp)
{
return GetUserQuery(UserDbContext, tenant, default)
return GetUserQuery(tenant)
.Where(r => r.Id == id)
.Select(exp ?? FromUserToUserInfo)
.FirstOrDefault();

View File

@ -1,8 +1,8 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace ASC.Core.Common.EF.Model
{
[Table("tenants_partners")]
@ -21,7 +21,7 @@ namespace ASC.Core.Common.EF.Model
[Column("campaign")]
public string Campaign { get; set; }
public DbTenant Tenant { get; set; }
//public DbTenant Tenant { get; set; }
}
public static class DbTenantPartnerExtension
{

View File

@ -49,17 +49,28 @@ namespace ASC.Data.Storage
TenantManager tenantManager,
PathUtils pathUtils,
EmailValidationKeyProvider emailValidationKeyProvider,
IHttpContextAccessor httpContextAccessor,
IOptionsMonitor<ILog> options)
{
TenantManager = tenantManager;
PathUtils = pathUtils;
EmailValidationKeyProvider = emailValidationKeyProvider;
HttpContextAccessor = httpContextAccessor;
Options = options;
Log = options.CurrentValue;
}
public BaseStorage(
TenantManager tenantManager,
PathUtils pathUtils,
EmailValidationKeyProvider emailValidationKeyProvider,
IHttpContextAccessor httpContextAccessor,
IOptionsMonitor<ILog> options) : this(tenantManager,
pathUtils,
emailValidationKeyProvider,
options)
{
HttpContextAccessor = httpContextAccessor;
}
#region IDataStore Members
internal string _modulename;

View File

@ -74,6 +74,19 @@ namespace ASC.Data.Storage.DiscStorage
return this;
}
public DiscDataStore(
TenantManager tenantManager,
PathUtils pathUtils,
EmailValidationKeyProvider emailValidationKeyProvider,
IOptionsMonitor<ILog> options,
EncryptionSettingsHelper encryptionSettingsHelper,
EncryptionFactory encryptionFactory)
: base(tenantManager, pathUtils, emailValidationKeyProvider, options)
{
EncryptionSettingsHelper = encryptionSettingsHelper;
EncryptionFactory = encryptionFactory;
}
public DiscDataStore(
TenantManager tenantManager,
PathUtils pathUtils,

View File

@ -71,6 +71,14 @@ namespace ASC.Data.Storage.GoogleCloud
private bool _lowerCasing = true;
public GoogleCloudStorage(
TenantManager tenantManager,
PathUtils pathUtils,
EmailValidationKeyProvider emailValidationKeyProvider,
IOptionsMonitor<ILog> options) : base(tenantManager, pathUtils, emailValidationKeyProvider, options)
{
}
public GoogleCloudStorage(
TenantManager tenantManager,
PathUtils pathUtils,

View File

@ -64,6 +64,16 @@ namespace ASC.Data.Storage.RackspaceCloud
private readonly ILog _logger;
public RackspaceCloudStorage(
TenantManager tenantManager,
PathUtils pathUtils,
EmailValidationKeyProvider emailValidationKeyProvider,
IOptionsMonitor<ILog> options)
: base(tenantManager, pathUtils, emailValidationKeyProvider, options)
{
_logger = options.Get("ASC.Data.Storage.Rackspace.RackspaceCloudStorage");
}
public RackspaceCloudStorage(
TenantManager tenantManager,
PathUtils pathUtils,

View File

@ -77,6 +77,15 @@ namespace ASC.Data.Storage.S3
private string _distributionId = string.Empty;
private string _subDir = string.Empty;
public S3Storage(
TenantManager tenantManager,
PathUtils pathUtils,
EmailValidationKeyProvider emailValidationKeyProvider,
IOptionsMonitor<ILog> options)
: base(tenantManager, pathUtils, emailValidationKeyProvider, options)
{
}
public S3Storage(
TenantManager tenantManager,
PathUtils pathUtils,

View File

@ -1,6 +1,6 @@
{
"name": "asc-files-client",
"version": "0.0.3",
"version": "0.0.4",
"private": true,
"homepage": "/products/files",
"dependencies": {

View File

@ -0,0 +1,9 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="webm">
<path id="Vector" d="M3 1H16L21 7V23H3V1Z" fill="white"/>
<path id="Vector_2" d="M21 7L16 1H3V16H2V0H16L22 7V16H21V7Z" fill="#BFBFBF"/>
<path id="format" fill-rule="evenodd" clip-rule="evenodd" d="M3 15C2.44772 15 2 15.4477 2 16V23C2 23.5523 2.44772 24 3 24H21C21.5523 24 22 23.5523 22 23V16C22 15.4477 21.5523 15 21 15H3ZM6 17H5L6 22H7L7.5 19.5L8 22H9L10 17H9L8.5 19.5L8 17H7L6.5 19.5L6 17ZM16 22L15 19.5V22H14V17H15L16.5 20.75L18 17H19V22H18V19.5L17 22H16ZM13 19H11V20H13V19Z" fill="#1DAA91"/>
<path id="logo" d="M7.49039 2.13392C7.79726 1.95336 8.17676 1.94866 8.488 2.12157L15 5.73935V8H18V7.90115C18.0032 7.93379 18.0049 7.96677 18.0049 7.99999C18.0049 8.36492 17.807 8.70118 17.488 8.8784L8.488 13.8784C8.17676 14.0513 7.79726 14.0466 7.49039 13.8661C7.18352 13.6855 6.99512 13.356 6.99512 13V2.99999C6.99512 2.64394 7.18352 2.31448 7.49039 2.13392Z" fill="#BFBFBF"/>
<path id="Vector_3" opacity="0.3" d="M14 9V1H15V8H21V9H14Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,9 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="webm">
<path id="Vector" d="M4 1H19L28 9V31H4V1Z" fill="white"/>
<path id="Vector_2" fill-rule="evenodd" clip-rule="evenodd" d="M4 31H28V9L19 1H4V31ZM19 0H3V32H29V9L19 0Z" fill="#BFBFBF"/>
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M7 20C6.44772 20 6 20.4477 6 21V28C6 28.5523 6.44772 29 7 29H25C25.5523 29 26 28.5523 26 28V21C26 20.4477 25.5523 20 25 20H7ZM10 22H9L10 27H11L11.5 24.5L12 27H13L14 22H13L12.5 24.5L12 22H11L10.5 24.5L10 22ZM20 27L19 24.5V27H18V22H19L20.5 25.75L22 22H23V27H22V24.5L21 27H20ZM17 24H15V25H17V24Z" fill="#1DAA91"/>
<path id="logo" d="M11.4948 5.13869C11.8014 4.95828 12.1806 4.95358 12.4916 5.12635L18 8.18682V10H21.2635L21.4836 10.1223C21.8023 10.2994 22 10.6354 22 11C22 11.3646 21.8023 11.7006 21.4836 11.8777L12.4916 16.8736C12.1806 17.0464 11.8014 17.0417 11.4948 16.8613C11.1882 16.6809 11 16.3517 11 15.9959V6.00406C11 5.6483 11.1882 5.3191 11.4948 5.13869Z" fill="#BFBFBF"/>
<path id="Vector_3" opacity="0.3" d="M17 11V1H18V10H28V11H17Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,9 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="webm">
<path id="Vector" d="M7 1H38L57 20V63H7V1Z" fill="white"/>
<path id="Vector_2" fill-rule="evenodd" clip-rule="evenodd" d="M7 63H57V20L38 1H7V63ZM38 0H6V64H58V20L38 0Z" fill="#BFBFBF"/>
<path id="format" fill-rule="evenodd" clip-rule="evenodd" d="M15 39C13.8954 39 13 39.8954 13 41V57C13 58.1046 13.8954 59 15 59H49C50.1046 59 51 58.1046 51 57V41C51 39.8954 50.1046 39 49 39H15ZM16 43.2627L18.5635 54H20.9146L23.0459 45.9727L25.1846 54H27.4844L30.0918 43.2627H27.9092L26.2612 50.7627L24.3789 43.2627H21.8008L19.8379 50.6382L18.2192 43.2627H16ZM36 54V43.2627H39.4414L41.5078 50.5869L43.5508 43.2627H47V54H44.8637V45.5479L42.6031 54H40.3891L38.1363 45.5479V54H36ZM34 48H31V50H34V48Z" fill="#1DAA91"/>
<path id="logo" d="M22.5027 10.1343C22.8138 9.95492 23.1969 9.95526 23.5076 10.1352L37.9975 18.5245V19.0012H38.8209L42.4988 21.1307C42.809 21.3103 43 21.6416 43 22C43 22.3584 42.809 22.6897 42.4988 22.8693L23.5076 33.8648C23.1969 34.0447 22.8138 34.0451 22.5027 33.8657C22.1917 33.6864 22 33.3546 22 32.9955V11.0045C22 10.6454 22.1917 10.3136 22.5027 10.1343Z" fill="#BFBFBF"/>
<path id="Vector_3" opacity="0.3" d="M37 20V1H38V19H57L58 20H37Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,9 @@
<svg width="96" height="96" viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="webm">
<path id="Vector" d="M10 1H57L86 30V95H10V1Z" fill="white"/>
<path id="Vector_2" fill-rule="evenodd" clip-rule="evenodd" d="M10 95H86V30L57 1H10V95ZM57 0H9.00003V96H87V30L57 0Z" fill="#BFBFBF"/>
<path id="format" fill-rule="evenodd" clip-rule="evenodd" d="M23 58C21.3431 58 20 59.3431 20 61V86C20 87.6569 21.3431 89 23 89H73C74.6569 89 76 87.6569 76 86V61C76 59.3431 74.6569 58 73 58H23ZM24 65.5361L27.9307 82H31.5356L34.8037 69.6914L38.083 82H41.6094L45.6074 65.5361H42.2607L39.7339 77.0361L36.8477 65.5361H32.8945L29.8848 76.8452L27.4028 65.5361H24ZM55.0488 82V65.5361H60.0239L63.0112 76.7666L65.9648 65.5361H70.9512V82H67.8628V69.04L64.5947 82H61.394L58.1372 69.04V82H55.0488ZM52 73H47V76H52V73Z" fill="#1DAA91"/>
<path id="logo" d="M32.4988 14.1366C32.8076 13.9566 33.1888 13.9543 33.4998 14.1306L56.9973 27.4462V29.0008H59.7406L63.4907 31.126C63.8055 31.3043 64 31.6382 64 32C64 32.3618 63.8055 32.6957 63.4907 32.874L33.4998 49.8694C33.1888 50.0457 32.8076 50.0434 32.4988 49.8634C32.1899 49.6834 32 49.3529 32 48.9954V15.0046C32 14.6471 32.1899 14.3166 32.4988 14.1366Z" fill="#BFBFBF"/>
<path id="Vector_3" opacity="0.3" d="M56 30V1H57V29H86L87 30H56Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -12,7 +12,7 @@
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<link id="favicon" rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- Tell the browser it's a PWA -->

View File

@ -12,6 +12,7 @@ import {
setExpandSettingsTree,
getFilesSettings,
setSelectedFolder,
setIsLoading,
} from "../../../store/files/actions";
import {
getIsLoading,
@ -77,16 +78,22 @@ const PureTreeSettings = ({
getFilesSettings,
setSelectedFolder,
selectedFolder,
setIsLoading,
t,
}) => {
useEffect(() => {
const { setting } = match.params;
if (setting && !expandedSetting) setExpandSettingsTree(["settings"]);
}, [match, expandedSetting, setExpandSettingsTree]);
setIsLoading(true);
getFilesSettings().then(() => {
setIsLoading(false);
setSelectedNode([setting]);
});
}, []);
useEffect(() => {
getFilesSettings();
}, [getFilesSettings]);
const { setting } = match.params;
if (setting && !expandedSetting) setExpandSettingsTree(["settings"]);
}, [match, expandedSetting, setExpandSettingsTree]);
const switcherIcon = (obj) => {
if (obj.isLeaf) {
@ -146,7 +153,7 @@ const PureTreeSettings = ({
title={t("TreeSettingsAdminSettings")}
/>
) : null}
{enableThirdParty ? (
{/*enableThirdParty ? (
<TreeNode
selectable={true}
className="settings-node"
@ -155,7 +162,7 @@ const PureTreeSettings = ({
isLeaf={true}
title={t("TreeSettingsConnectedCloud")}
/>
) : null}
) : null*/}
</TreeNode>
);
};
@ -211,4 +218,5 @@ export default connect(mapStateToProps, {
setExpandSettingsTree,
getFilesSettings,
setSelectedFolder,
setIsLoading,
})(withRouter(TreeSettings));

View File

@ -4,6 +4,7 @@ import PropTypes from "prop-types";
import { withRouter } from "react-router";
import { MainButton, DropDownItem } from "asc-web-components";
import { withTranslation, I18nextProvider } from "react-i18next";
import { isMobile } from "react-device-detect";
import { setAction, startUpload } from "../../../store/files/actions";
import {
canCreate,
@ -109,12 +110,14 @@ class PureArticleMainButtonContent extends React.Component {
label={t("UploadFiles")}
onClick={this.onUploadFileClick}
/>
<DropDownItem
className="main-button_drop-down"
icon="ActionsUploadIcon"
label={t("UploadFolder")}
onClick={this.onUploadFolderClick}
/>
{!isMobile && (
<DropDownItem
className="main-button_drop-down"
icon="ActionsUploadIcon"
label={t("UploadFolder")}
onClick={this.onUploadFolderClick}
/>
)}
<input
id="customFileInput"
className="custom-file-input"

View File

@ -6,6 +6,14 @@ import {
Text,
LinkWithDropdown,
} from "asc-web-components";
import styled from "styled-components";
const StyledDownloadContent = styled.div`
.row_content,
.row-content_tablet-side-info {
overflow: unset;
}
`;
const DownloadContent = (props) => {
const {
@ -236,7 +244,7 @@ const DownloadContent = (props) => {
const documentsTitle = getTitleLabel(titleFormat);
return (
<>
<StyledDownloadContent>
{showTitle && (
<Row
key={"title"}
@ -244,7 +252,7 @@ const DownloadContent = (props) => {
checked={checkedTitle}
indeterminate={indeterminateTitle}
>
<RowContent>
<RowContent convertSideInfo={false}>
<Text truncate type="page" title={title} fontSize="14px">
{title}
</Text>
@ -286,7 +294,7 @@ const DownloadContent = (props) => {
checked={file.checked}
element={element}
>
<RowContent>
<RowContent convertSideInfo={false}>
<Text truncate type="page" title={file.title} fontSize="14px">
{file.title}
</Text>
@ -309,7 +317,7 @@ const DownloadContent = (props) => {
);
})}
</RowContainer>
</>
</StyledDownloadContent>
);
};

View File

@ -16,10 +16,7 @@ import { utils, api, toastr } from "asc-web-common";
import {
getFileIcon,
getFolderIcon,
isSpreadsheet,
isPresentation,
isDocument,
getSelection,
getSortedFiles,
} from "../../../store/files/selectors";
import {
setSecondaryProgressBarData,
@ -52,38 +49,15 @@ const formatKeys = Object.freeze({
class DownloadDialogComponent extends React.Component {
constructor(props) {
super(props);
const { sortedFiles } = this.props;
changeLanguage(i18n);
const documents = [];
const spreadsheets = [];
const presentations = [];
const other = [];
for (let item of props.items) {
item.checked = true;
item.format = formatKeys.OriginalFormat;
if (item.fileExst) {
if (isSpreadsheet(item.fileExst)) {
spreadsheets.push(item);
} else if (isPresentation(item.fileExst)) {
presentations.push(item);
} else if (item.fileExst !== ".pdf" && isDocument(item.fileExst)) {
documents.push(item);
} else {
other.push(item);
}
} else {
other.push(item);
}
}
this.state = {
documents,
spreadsheets,
presentations,
other,
documents: sortedFiles.documents,
spreadsheets: sortedFiles.spreadsheets,
presentations: sortedFiles.presentations,
other: sortedFiles.other,
documentsTitleFormat: formatKeys.OriginalFormat,
spreadsheetsTitleFormat: formatKeys.OriginalFormat,
@ -631,7 +605,7 @@ const DownloadDialog = (props) => (
const mapStateToProps = (state) => {
return {
items: getSelection(state),
sortedFiles: getSortedFiles(state),
};
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -2,8 +2,24 @@ import React from "react";
import { withRouter } from "react-router";
import { Toast, Box } from "asc-web-components";
import { utils, api, toastr, Loaders } from "asc-web-common";
import { isIOS, deviceType } from "react-device-detect";
import { setDocumentTitle } from "../../../helpers/utils";
import { changeTitle, setFavicon, isIPad } from "./utils";
import throttle from "lodash/throttle";
const { getObjectByLocation, showLoader, hideLoader } = utils;
const { getObjectByLocation, showLoader, hideLoader, tryRedirectTo } = utils;
let documentIsReady = false;
let docTitle = null;
let fileType = null;
let docSaved = null;
const throttledChangeTitle = throttle(
() => changeTitle(docSaved, docTitle),
500
);
class PureEditor extends React.Component {
constructor(props) {
@ -28,13 +44,21 @@ class PureEditor extends React.Component {
console.log("PureEditor componentDidMount", fileId, doc);
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty("--vh", `${vh}px`);
if (isIPad()) {
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty("--vh", `${vh}px`);
}
showLoader();
const docApiUrl = await api.files.getDocServiceUrl();
if (!doc) {
const isAuthenticated = await api.user.checkIsAuthenticated();
if (!isAuthenticated) return tryRedirectTo("/login");
}
const config = await api.files.openEdit(fileId, doc);
this.setState({ isLoading: false }, () =>
@ -42,7 +66,12 @@ class PureEditor extends React.Component {
);
} catch (error) {
console.log(error);
toastr.error(error.message, null, 0, true);
toastr.error(
typeof error === "string" ? error : error.message,
null,
0,
true
);
}
}
@ -62,23 +91,62 @@ class PureEditor extends React.Component {
onLoad = (config) => {
try {
docTitle = config.document.title;
fileType = config.document.fileType;
setFavicon(fileType);
setDocumentTitle(docTitle);
if (window.innerWidth < 720) {
config.type = "mobile";
}
const events = {
events: {
onDocumentStateChange: this.onDocumentStateChange,
onMetaChange: this.onMetaChange,
onDocumentReady: this.onDocumentReady,
},
};
const newConfig = Object.assign(config, events);
if (!window.DocsAPI) throw new Error("DocsAPI is not defined");
hideLoader();
window.DocsAPI.DocEditor("editor", config);
window.DocsAPI.DocEditor("editor", newConfig);
} catch (error) {
console.log(error);
toastr.error(error.message, null, 0, true);
}
};
onDocumentStateChange = (event) => {
if (!documentIsReady) return;
docSaved = !event.data;
throttledChangeTitle();
};
onDocumentReady = () => {
documentIsReady = true;
};
onMetaChange = (event) => {
const newTitle = event.data.title;
if (newTitle && newTitle !== docTitle) {
setDocumentTitle(newTitle);
docTitle = newTitle;
}
};
render() {
return (
<Box widthProp="100vw" heightProp="100vh">
<Box
widthProp="100vw"
heightProp={isIPad() ? "calc(var(--vh, 1vh) * 100)" : "100vh"}
>
<Toast />
{!this.state.isLoading ? (

View File

@ -0,0 +1,34 @@
import { setDocumentTitle } from "../../../helpers/utils";
import { isIOS, deviceType } from "react-device-detect";
import textIcon from "./icons/text.ico";
import presentationIcon from "./icons/presentation.ico";
import spreadsheetIcon from "./icons/spreadsheet.ico";
export const changeTitle = (docSaved, docTitle) => {
docSaved ? setDocumentTitle(docTitle) : setDocumentTitle(`*${docTitle}`);
};
export const setFavicon = (fileType) => {
const favicon = document.getElementById("favicon");
if (!favicon) return;
switch (fileType) {
case "docx":
favicon.href = textIcon;
break;
case "pptx":
favicon.href = presentationIcon;
break;
case "xlsx":
favicon.href = spreadsheetIcon;
break;
default:
break;
}
};
export const isIPad = () => {
return isIOS && deviceType === "tablet";
};

View File

@ -64,8 +64,11 @@ const EditingWrapperComponent = (props) => {
if (code === 13) {
return onClickUpdateItem(e);
}
if (code === 27) return cancelUpdateItem(e);
//if (code === 27) return cancelUpdateItem(e);
};
const onEscapeKeyPress = (e) => {
if (e.keyCode === 27) return cancelUpdateItem(e);
return;
};
const setIsHoveredOkHandler = () => {
@ -89,6 +92,7 @@ const EditingWrapperComponent = (props) => {
isAutoFocussed={true}
onChange={renameTitle}
onKeyPress={onKeyUpUpdateItem}
onKeyDown={onEscapeKeyPress}
onFocus={onFocus}
isDisabled={isLoading}
data-itemid={itemId}

View File

@ -146,7 +146,12 @@ class FilesRowContent extends React.PureComponent {
const originalTitle = getTitleWithoutExst(item);
setIsLoading(true);
if (originalTitle === itemTitle) return this.completeAction(fileAction.id);
if (originalTitle === itemTitle || itemTitle.trim() === "") {
this.setState({
itemTitle: originalTitle,
});
return this.completeAction(fileAction.id);
}
item.fileExst
? updateFile(fileAction.id, itemTitle)
@ -165,7 +170,10 @@ class FilesRowContent extends React.PureComponent {
const itemId = e.currentTarget.dataset.itemid;
if (itemTitle.trim() === "") return this.completeAction(itemId);
if (itemTitle.trim() === "") {
toastr.warning(this.props.t("CreateWithEmptyTitle"));
return this.completeAction(itemId);
}
let tab = item.fileExst
? window.open("/products/files/doceditor", "_blank")
@ -174,12 +182,15 @@ class FilesRowContent extends React.PureComponent {
!item.fileExst
? createFolder(item.parentId, itemTitle)
.then(() => this.completeAction(itemId))
.finally(() => {
.then(() =>
toastr.success(
<Trans i18nKey="FolderCreated" i18n={i18n}>
New folder {{ itemTitle }} is created
</Trans>
);
)
)
.catch((e) => toastr.error(e))
.finally(() => {
return setIsLoading(false);
})
: createFile(item.parentId, `${itemTitle}.${item.fileExst}`)
@ -187,13 +198,16 @@ class FilesRowContent extends React.PureComponent {
openDocEditor(file.id, tab, file.webUrl);
this.completeAction(itemId);
})
.finally(() => {
.then(() => {
const exst = item.fileExst;
toastr.success(
return toastr.success(
<Trans i18nKey="FileCreated" i18n={i18n}>
New file {{ itemTitle }}.{{ exst }} is created
</Trans>
);
})
.catch((e) => toastr.error(e))
.finally(() => {
return setIsLoading(false);
});
};
@ -217,11 +231,23 @@ class FilesRowContent extends React.PureComponent {
}
renameTitle = (e) => {
this.setState({ itemTitle: e.target.value });
let title = e.target.value;
//const chars = '*+:"<>?|/'; TODO: think how to solve problem with interpolation escape values in i18n translate
const regexp = new RegExp('[*+:"<>?|\\\\/]', "gim");
if (title.match(regexp)) {
toastr.warning(this.props.t("ContainsSpecCharacter"));
}
title = title.replace(regexp, "_");
return this.setState({ itemTitle: title });
};
cancelUpdateItem = (e) => {
this.completeAction(e);
const originalTitle = getTitleWithoutExst(this.props.item);
this.setState({
itemTitle: originalTitle,
});
return this.completeAction(e);
};
onClickUpdateItem = (e) => {

View File

@ -206,6 +206,7 @@ class SectionBodyContent extends React.Component {
let previewId = queryString.parse(this.props.location.search).preview;
if (previewId) {
this.removeQuery("preview");
this.onMediaFileClick(+previewId);
}
@ -249,7 +250,7 @@ class SectionBodyContent extends React.Component {
}
shouldComponentUpdate(nextProps, nextState) {
if (this.props && this.props.firstLoad) return true;
//if (this.props && this.props.firstLoad) return true;
const { showMoveToPanel, showCopyPanel, isDrag } = this.state;
if (this.props.sharingPanelVisible !== nextProps.sharingPanelVisible) {
@ -279,11 +280,15 @@ class SectionBodyContent extends React.Component {
}
onOpenLocation = () => {
const item = this.props.selection[0];
const { folderId, checked } = this.props.selection[0];
const { filter, selection } = this.props;
const { folderId, checked, id, isFolder } = selection[0];
const item = selection[0];
const locationId = isFolder ? id : folderId;
const locationFilter = isFolder ? filter : null;
return this.props
.fetchFiles(folderId)
.then(() => this.onContentRowSelect(!checked, item));
.fetchFiles(locationId, locationFilter)
.then(() => (isFolder ? null : this.onContentRowSelect(!checked, item)));
};
onClickFavorite = (e) => {
@ -294,6 +299,7 @@ class SectionBodyContent extends React.Component {
fetchFavoritesFolder,
isFavorites,
selectedFolderId,
setSelected,
//selection,
t,
} = this.props;
@ -313,6 +319,7 @@ class SectionBodyContent extends React.Component {
: getFileInfo(id);
})
.then(() => toastr.success(t("RemovedFromFavorites")))
.then(() => setSelected("close"))
.catch((e) => toastr.error(e));
default:
return;
@ -346,7 +353,7 @@ class SectionBodyContent extends React.Component {
setAction,
selection,
} = this.props;
const selectedItem = selection[0] ?? {};
const selectedItem = selection[0];
const items = [...folders, ...files];
const item = items.find((o) => o.id === id && !o.fileExst); //TODO maybe need files find and folders find, not at one function?
if (
@ -371,7 +378,8 @@ class SectionBodyContent extends React.Component {
setAction({ type: null });
setIsLoading(false);
});
this.onSelectItem(selectedItem);
fileAction.type === FileAction.Rename &&
this.onSelectItem(selectedItem);
});
}
@ -514,13 +522,10 @@ class SectionBodyContent extends React.Component {
const item = selection[0];
const isFile = !!item.fileExst;
const { t } = this.props;
copy(
isFile
? item.canOpenPlayer
? `${window.location.origin + settings.homepage}/filter?folder=${
item.folderId
}&preview=${item.id}`
? `${window.location.href}&preview=${item.id}`
: item.webUrl
: `${window.location.origin + settings.homepage}/filter?folder=${
item.id
@ -625,7 +630,7 @@ class SectionBodyContent extends React.Component {
selection[0].fileExst
? fileIds.push(selection[0].id)
: folderIds.push(selection[0].id);
const conflictResolveType = 0; //Skip = 0, Overwrite = 1, Duplicate = 2
const conflictResolveType = 2; //Skip = 0, Overwrite = 1, Duplicate = 2
const deleteAfter = false;
setSecondaryProgressBarData({
@ -651,6 +656,14 @@ class SectionBodyContent extends React.Component {
return options.map((option) => {
switch (option) {
case "open":
return {
key: option,
label: t("Open"),
icon: "CatalogFolderIcon",
onClick: this.onOpenLocation,
disabled: false,
};
case "show-version-history":
return {
key: option,
@ -673,6 +686,7 @@ class SectionBodyContent extends React.Component {
case "separator0":
case "separator1":
case "separator2":
case "separator3":
return { key: option, isSeparator: true };
case "open-location":
return {
@ -1503,6 +1517,18 @@ class SectionBodyContent extends React.Component {
});
};
removeQuery = (queryName) => {
const { location, history } = this.props;
const queryParams = new URLSearchParams(location.search);
if (queryParams.has(queryName)) {
queryParams.delete(queryName);
history.replace({
search: queryParams.toString(),
});
}
};
onSelectItem = (item) => {
const { selected, setSelected, setSelection } = this.props;
selected === "close" && setSelected("none");
@ -1613,11 +1639,6 @@ class SectionBodyContent extends React.Component {
const { editingId, showMoveToPanel, showCopyPanel } = this.state;
const operationsPanelProps = {
setIsLoading,
isLoading,
};
let fileMoveTooltip;
if (dragging) {
fileMoveTooltip = tooltipValue
@ -1669,8 +1690,6 @@ class SectionBodyContent extends React.Component {
<>
{showMoveToPanel && (
<OperationsPanel
{...operationsPanelProps}
isCopy={false}
visible={showMoveToPanel}
onClose={this.onMoveAction}
/>
@ -1678,8 +1697,7 @@ class SectionBodyContent extends React.Component {
{showCopyPanel && (
<OperationsPanel
{...operationsPanelProps}
isCopy={true}
isCopy
visible={showCopyPanel}
onClose={this.onCopyAction}
/>

View File

@ -37,6 +37,7 @@ import {
import { OperationsPanel } from "../../../../panels";
import {
isCanBeDeleted,
getWebEditSelected,
getIsRecycleBinFolder,
canCreate,
getSelectedFolderTitle,
@ -48,7 +49,6 @@ import {
getHeaderVisible,
getHeaderIndeterminate,
getHeaderChecked,
getOnlyFoldersSelected,
getAccessedSelected,
getSelectionLength,
getSharePanelVisible,
@ -292,6 +292,10 @@ class SectionHeaderContent extends React.Component {
const folderIds = [];
const items = [];
if (selection.length === 1) {
return window.open(selection[0].viewUrl, "_blank");
}
for (let item of selection) {
if (item.fileExst) {
fileIds.push(item.id);
@ -411,7 +415,7 @@ class SectionHeaderContent extends React.Component {
t,
isItemsSelected,
isAccessedSelected,
isOnlyFoldersSelected,
isWebEditSelected,
deleteDialogVisible,
isRecycleBin,
} = this.props;
@ -480,7 +484,7 @@ class SectionHeaderContent extends React.Component {
},
{
label: t("DownloadAs"),
disabled: !isItemsSelected || isOnlyFoldersSelected,
disabled: !isItemsSelected || !isWebEditSelected,
onClick: this.downloadAsAction,
},
{
@ -693,11 +697,11 @@ const mapStateToProps = (state) => {
deleteDialogVisible: isCanBeDeleted(state),
currentFolderId: getSelectedFolderId(state),
canCreate: canCreate(state),
isWebEditSelected: getWebEditSelected(state),
isHeaderVisible: getHeaderVisible(state),
isHeaderIndeterminate: getHeaderIndeterminate(state),
isHeaderChecked: getHeaderChecked(state),
isAccessedSelected: getAccessedSelected(state),
isOnlyFoldersSelected: getOnlyFoldersSelected(state),
isItemsSelected: getSelectionLength(state),
sharingPanelVisible: getSharePanelVisible(state),
};

View File

@ -1,15 +1,20 @@
import React, { useCallback, useMemo } from "react";
import { connect } from "react-redux";
import { isMobile } from "react-device-detect";
import { fetchFiles, setIsLoading } from "../../../../../store/files/actions";
import {
getFilter,
getSelectedFolderId,
getFiles,
getFolders,
} from "../../../../../store/files/selectors";
import { Paging } from "asc-web-components";
import { useTranslation } from "react-i18next";
const SectionPagingContent = ({
filter,
files,
folders,
fetchFiles,
setIsLoading,
selectedCount,
@ -132,7 +137,12 @@ const SectionPagingContent = ({
//console.log("SectionPagingContent render", filter);
return filter.total < filter.pageCount ? (
const currItemsLength = useMemo(() => {
if (files && folders)
return files.length + folders.length === filter.pageCount;
}, [files, folders, filter]);
return filter.total < filter.pageCount && filter.total < 26 ? (
<></>
) : (
<Paging
@ -145,11 +155,13 @@ const SectionPagingContent = ({
displayItems={false}
disablePrevious={!filter.hasPrev()}
disableNext={!filter.hasNext()}
disableHover={isMobile}
previousAction={onPrevClick}
nextAction={onNextClick}
openDirection="top"
selectedPageItem={selectedPageItem} //FILTER CURRENT PAGE
selectedCountItem={selectedCountItem} //FILTER PAGE COUNT
showCountItem={currItemsLength}
/>
);
};
@ -158,6 +170,8 @@ function mapStateToProps(state) {
return {
filter: getFilter(state),
selectedFolderId: getSelectedFolderId(state),
files: getFiles(state),
folders: getFolders(state),
};
}

View File

@ -4,8 +4,8 @@ import PropTypes from "prop-types";
import { withRouter } from "react-router";
import { isMobile } from "react-device-detect";
//import { RequestLoader } from "asc-web-components";
import { PageLayout, utils, api, store } from "asc-web-common";
import { withTranslation, I18nextProvider } from "react-i18next";
import { PageLayout, utils, api, store, toastr } from "asc-web-common";
import { withTranslation, I18nextProvider, Trans } from "react-i18next";
import {
ArticleBodyContent,
ArticleHeaderContent,
@ -41,6 +41,9 @@ import {
getHeaderVisible,
getSharePanelVisible,
getFirstLoad,
isSecondaryProgressFinished,
getSelectionLength,
getSelectionTitle,
} from "../../../store/files/selectors";
import { ConvertDialog } from "../../dialogs";
@ -169,9 +172,51 @@ class PureHome extends React.Component {
startUpload(files, folderId, t);
};
showOperationToast = (type, qty, title) => {
const { i18n } = this.props;
switch (type) {
case "move":
if (qty > 1) {
return toastr.success(
<Trans i18nKey="MoveItems" i18n={i18n}>
{{ qty }} elements has been moved
</Trans>
);
}
return toastr.success(
<Trans i18nKey="MoveItem" i18n={i18n}>
{{ title }} moved
</Trans>
);
case "duplicate":
if (qty > 1) {
return toastr.success(
<Trans i18nKey="CopyItems" i18n={i18n}>
{{ qty }} elements copied
</Trans>
);
}
return toastr.success(
<Trans i18nKey="CopyItem" i18n={i18n}>
{{ title }} copied
</Trans>
);
default:
break;
}
};
componentDidUpdate(prevProps) {
if (this.props.isLoading !== prevProps.isLoading) {
if (this.props.isLoading) {
const {
isLoading,
isProgressFinished,
secondaryProgressData,
selectionLength,
selectionTitle,
} = this.props;
if (isLoading !== prevProps.isLoading) {
if (isLoading) {
utils.showLoader();
} else {
utils.hideLoader();
@ -181,6 +226,17 @@ class PureHome extends React.Component {
if (this.props.isHeaderVisible !== prevProps.isHeaderVisible) {
this.props.setHeaderVisible(this.props.isHeaderVisible);
}
if (
isProgressFinished &&
isProgressFinished !== prevProps.isProgressFinished
) {
this.showOperationToast(
secondaryProgressData.icon,
selectionLength,
selectionTitle
);
}
}
render() {
@ -299,6 +355,9 @@ function mapStateToProps(state) {
sharingPanelVisible: getSharePanelVisible(state),
firstLoad: getFirstLoad(state),
isHeaderVisible: getHeaderVisible(state),
isProgressFinished: isSecondaryProgressFinished(state),
selectionLength: getSelectionLength(state),
selectionTitle: getSelectionTitle(state),
};
}

View File

@ -13,6 +13,7 @@
"MarkedAsFavorite": "Added to favorites",
"RemoveFromFavorites": "Remove from favorites",
"RemovedFromFavorites": "Removed from favorites",
"Open": "Open",
"Edit": "Edit",
"Preview": "Preview",
"View": "View",
@ -112,5 +113,11 @@
"FolderCreated": "New folder <strong>{{itemTitle}}</strong> is created",
"FileCreated": "New file <strong>{{itemTitle}}.{{exst}}</strong> is created",
"FolderRemoved": "Folder moved to recycle bin",
"FileRemoved": "File moved to recycle bin"
"FileRemoved": "File moved to recycle bin",
"MoveItem": "<strong>{{title}}</strong> moved",
"MoveItems": "<strong>{{qty}}</strong> elements has been moved",
"CopyItem": "<strong>{{title}}</strong> copied",
"CopyItems": "<strong>{{qty}}</strong> elements copied",
"ContainsSpecCharacter": "The title cannot contain any of the following characters: *+:\"<>?|/",
"CreateWithEmptyTitle": "Can't create folder or file with empty title"
}

View File

@ -13,6 +13,7 @@
"MarkedAsFavorite": "Добавлено в избранное",
"RemoveFromFavorites": "Удалить из избранного",
"RemovedFromFavorites": "Удалено из избранного",
"Open": "Открыть",
"Edit": "Редактировать",
"Preview": "Просмотр",
"View": "Просмотр",
@ -112,5 +113,11 @@
"FolderCreated": "Создана новая папка <strong>{{itemTitle}}</strong>",
"FileCreated": "Создан новый файл <strong>{{itemTitle}}.{{exst}}</strong>",
"FolderRemoved": "Папка перемещена в корзину",
"FileRemoved": "Файл перемещен в корзину"
"FileRemoved": "Файл перемещен в корзину",
"MoveItem": "<strong>{{title}}</strong> перемещен",
"MoveItems": "Перемещено элементов: <strong>{{qty}}</strong>",
"CopyItem": "<strong>{{title}}</strong> скопирован",
"CopyItems": "Скопировано элементов: <strong>{{qty}}</strong>",
"ContainsSpecCharacter": "Название не должно содержать следующих символов: *+:\"<>?|/",
"CreateWithEmptyTitle": "Нельзя создать папку или файл с пустым названием"
}

View File

@ -170,7 +170,8 @@ const SectionBodyContent = ({
if (setting === "admin" && isAdmin) content = renderAdminSettings();
if (setting === "common") content = renderCommonSettings();
if (setting === "thirdparty" && enableThirdParty) content = renderClouds();
if (setting === "thirdparty" && enableThirdParty)
content = renderCommonSettings(); //renderClouds();
return isLoading ? null : (!enableThirdParty && setting === "thirdparty") ||
(!isAdmin && setting === "admin") ? (

View File

@ -29,17 +29,19 @@ const { changeLanguage } = utils;
const PureSettings = ({
match,
history,
t,
isLoading,
settingsTree,
getFilesSettings,
setIsLoading,
setFirstLoad,
setSelectedNode,
}) => {
const [title, setTitle] = useState("");
const { setting } = match.params;
useEffect(() => {
setFirstLoad(false);
}, []);
useEffect(() => {
switch (setting) {
case "common":
@ -49,30 +51,14 @@ const PureSettings = ({
setTitle("AdminSettings");
break;
case "thirdparty":
setTitle("ThirdPartySettings");
//setTitle("ThirdPartySettings");
history.push("/products/files/settings/common");
break;
default:
setTitle("CommonSettings");
break;
}
}, [setting]);
useEffect(() => {
if (Object.keys(settingsTree).length === 0) {
setIsLoading(true);
getFilesSettings().then(() => {
setIsLoading(false);
setFirstLoad(false);
setSelectedNode([setting]);
});
}
}, [
setting,
getFilesSettings,
setIsLoading,
setFirstLoad,
settingsTree,
setSelectedNode,
]);
useEffect(() => {
if (isLoading) {

View File

@ -30,7 +30,7 @@ const StyledRow = styled(Row)`
min-height: 69px;
}
.version_badge {
cursor: pointer;
cursor: ${(props) => (props.canEdit ? "pointer" : "default")};
.version_badge-text {
position: absolute;
@ -100,8 +100,8 @@ const StyledRow = styled(Row)`
}
.version_link {
display: ${(props) => (props.showEditPanel ? "none" : "block")};
text-decoration: underline dashed;
display: ${(props) =>
props.showEditPanel ? "none" : props.canEdit ? "block" : "none"};
white-space: break-spaces;
margin-left: -7px;
margin-top: 4px;
@ -113,7 +113,9 @@ const StyledRow = styled(Row)`
}
.version_text {
display: none;
display: ${(props) => (props.canEdit ? "none" : "block")};
margin-left: -7px;
margin-top: 5px;
@media ${tablet} {
display: block;
@ -122,18 +124,22 @@ const StyledRow = styled(Row)`
}
}
.version_link-action {
display: block;
.version_links-container {
display: flex;
margin-left: auto;
margin-top: 5px;
:last-child {
margin-left: 8px;
margin-right: -7px;
}
.version_link-action {
display: block;
margin-top: 5px;
@media ${tablet} {
display: none;
:last-child {
margin-right: -7px;
margin-left: 8px;
}
@media ${tablet} {
display: none;
}
}
}
@ -193,6 +199,8 @@ const VersionRow = (props) => {
const [commentValue, setCommentValue] = useState(info.comment);
const [displayComment, setDisplayComment] = useState(info.comment);
const canEdit = info.access === 1 || info.access === 0;
const VersionBadge = (props) => (
<Box {...props} marginProp="0 8px" displayProp="flex">
<svg
@ -262,8 +270,8 @@ const VersionRow = (props) => {
};
const contextOptions = [
{ key: "edit", label: t("EditComment"), onClick: onEditComment },
{ key: "restore", label: t("Restore"), onClick: onRestoreClick },
canEdit && { key: "edit", label: t("EditComment"), onClick: onEditComment },
canEdit && { key: "restore", label: t("Restore"), onClick: onRestoreClick },
{
key: "download",
label: `${t("Download")} (${info.contentLength})`,
@ -271,11 +279,17 @@ const VersionRow = (props) => {
},
];
const onClickProp = canEdit ? { onClick: onVersionClick } : {};
return (
<StyledRow showEditPanel={showEditPanel} contextOptions={contextOptions}>
<StyledRow
showEditPanel={showEditPanel}
contextOptions={contextOptions}
canEdit={canEdit}
>
<>
<Box displayProp="flex">
<VersionBadge className="version_badge" onClick={onVersionClick} />
<VersionBadge className="version_badge" {...onClickProp} />
<Link
onClick={onOpenFile}
fontWeight={600}
@ -340,26 +354,36 @@ const VersionRow = (props) => {
</Box>
</>
)}
<Link onClick={onEditComment} className="version_link">
<Link
type="action"
isHovered
onClick={onEditComment}
className="version_link"
>
{displayComment}
</Link>
<Text className="version_text">{displayComment}</Text>
</>
<Link
onClick={onRestoreClick}
{...linkStyles}
className="version_link-action"
>
{t("Restore")}
</Link>
<Link
onClick={onDownloadAction}
{...linkStyles}
className="version_link-action"
>
{t("Download")}
</Link>
<div className="version_links-container">
{canEdit && (
<Link
onClick={onRestoreClick}
{...linkStyles}
className="version_link-action"
>
{t("Restore")}
</Link>
)}
<Link
onClick={onDownloadAction}
{...linkStyles}
className="version_link-action"
>
{t("Download")}
</Link>
</div>
</Box>
{showEditPanel && (
<Box className="version_edit-comment" marginProp="8px 0 16px 70px">

View File

@ -1,13 +1,15 @@
import React from "react";
import styled, { css } from "styled-components";
import styled from "styled-components";
import { withRouter } from "react-router";
import { Headline, store } from "asc-web-common";
import { Headline } from "asc-web-common";
import { IconButton, utils } from "asc-web-components";
import { connect } from "react-redux";
import { withTranslation } from "react-i18next";
import { setFilesFilter } from "../../../../../store/files/actions";
import { getFilter } from "../../../../../store/files/selectors";
const { tablet, desktop } = utils.device;
const { getSettings } = store.auth.selectors;
const StyledContainer = styled.div`
display: grid;
@ -73,8 +75,8 @@ const SectionHeaderContent = (props) => {
const { title } = props;
const onClickBack = () => {
const { history, settings } = props;
history.push(settings.homepage);
const { filter, setFilesFilter } = props;
setFilesFilter(filter);
};
return (
@ -98,10 +100,10 @@ const SectionHeaderContent = (props) => {
const mapStateToProps = (state) => {
return {
settings: getSettings(state),
filter: getFilter(state),
};
};
export default connect(mapStateToProps)(
export default connect(mapStateToProps, { setFilesFilter })(
withTranslation()(withRouter(SectionHeaderContent))
);

View File

@ -4,9 +4,5 @@
"CopyOperation": "Copying",
"MoveToOperation": "Moving",
"Restore": "Restore",
"MoveToFolderMessage": "You cannot move the folder to its subfolder",
"MoveItem": "<strong>{{title}}</strong> moved",
"MoveItems": "<strong>{{qty}}</strong> elements has been moved",
"CopyItem": "<strong>{{title}}</strong> copied",
"CopyItems": "<strong>{{qty}}</strong> elements copied"
"MoveToFolderMessage": "You cannot move the folder to its subfolder"
}

View File

@ -4,9 +4,5 @@
"CopyOperation": "Копирование",
"MoveToOperation": "Перемещение",
"Restore": "Восстановить",
"MoveToFolderMessage": "Нельзя перенести папку в свою дочернюю папку",
"MoveItem": "<strong>{{title}}</strong> перемещен",
"MoveItems": "Перемещено элементов: <strong>{{qty}}</strong>",
"CopyItem": "<strong>{{title}}</strong> скопирован",
"CopyItems": "Скопировано элементов: <strong>{{qty}}</strong>"
"MoveToFolderMessage": "Нельзя перенести папку в свою дочернюю папку"
}

View File

@ -29,14 +29,13 @@ const SharingRow = (props) => {
onRemoveUserClick,
onShowEmbeddingPanel,
onToggleLink,
externalLinkData,
internalLink,
} = props;
const externalLinkVisible =
selection && selection.length === 1 && item.shareLink;
const internalLinkVisible = index === 0 && internalLink;
const linkVisible = selection && selection.length === 1 && item.shareLink;
const onCopyInternalLink = () => {
const internalLink = selection.webUrl
? selection.webUrl
: selection[0].webUrl;
copy(internalLink);
toastr.success(t("LinkCopySuccess"));
};
@ -135,11 +134,16 @@ const SharingRow = (props) => {
window.open(`mailto:?subject=${subject}&body=${body}`);
};
const onShareTwitter = () =>
window.open(`https://twitter.com/intent/tweet?text=${item.shareLink}`);
const onShareTwitter = () => {
const encodedLink = encodeURIComponent(item.shareLink);
window.open(`https://twitter.com/intent/tweet?text=${encodedLink}`);
};
const onShareFacebook = () => window.open(`https://www.facebook.com`);
/*window.open(`https://www.facebook.com/dialog/feed?app_id=645528132139019&display=popup&link=${item.shareLink}`);*/
const onShareFacebook = () => {
window.open(
`https://www.facebook.com/sharer/sharer.php?u=${item.shareLink}`
);
};
const internalLinkData = [
{
@ -193,24 +197,23 @@ const SharingRow = (props) => {
//console.log("SharingRow render");
return (
<>
{linkVisible && (
<>
<LinkRow
linkText="ExternalLink"
options={externalLinkOptions}
externalLinkData={externalLinkData}
embeddedComponentRender={embeddedComponentRender}
onToggleLink={onToggleLink}
withToggle={true}
{...props}
/>
<LinkRow
linkText="InternalLink"
options={internalLinkData}
embeddedComponentRender={embeddedComponentRender}
{...props}
/>
</>
{externalLinkVisible && (
<LinkRow
linkText="ExternalLink"
options={externalLinkOptions}
embeddedComponentRender={embeddedComponentRender}
onToggleLink={onToggleLink}
withToggle={true}
{...props}
/>
)}
{internalLinkVisible && (
<LinkRow
linkText="InternalLink"
options={internalLinkData}
embeddedComponentRender={embeddedComponentRender}
{...props}
/>
)}
{!item.shareLink && (

View File

@ -46,6 +46,7 @@ const { ShareAccessRights } = constants;
const {
getCurrentUserId,
getSettingsCustomNamesGroupsCaption,
getSettings,
} = store.auth.selectors;
const SharingBodyStyle = { height: `calc(100vh - 156px)` };
@ -526,6 +527,22 @@ class SharingPanelComponent extends React.Component {
}
};
getInternalLink = () => {
const { settings, selectedItems } = this.props;
const item = selectedItems[0];
const isFile = !!item.fileExst;
if (selectedItems.length !== 1) return null;
return isFile
? item.canOpenPlayer
? `${window.location.href}&preview=${item.id}`
: item.webUrl
: `${window.location.origin + settings.homepage}/filter?folder=${
item.id
}`;
};
onShowEmbeddingPanel = (link) =>
this.setState({
showEmbeddingPanel: !this.state.showEmbeddingPanel,
@ -600,6 +617,7 @@ class SharingPanelComponent extends React.Component {
const visible = showPanel;
const zIndex = 310;
const internalLink = selectedItems && this.getInternalLink();
const advancedOptions = (
<>
@ -744,6 +762,7 @@ class SharingPanelComponent extends React.Component {
isMyId={isMyId}
accessOptions={accessOptions}
externalAccessOptions={externalAccessOptions}
internalLink={internalLink}
onFullAccessClick={this.onFullAccessItemClick}
onReadOnlyClick={this.onReadOnlyItemClick}
onReviewClick={this.onReviewItemClick}
@ -839,6 +858,7 @@ const mapStateToProps = (state) => {
selectedItems: getSelection(state),
groupsCaption: getSettingsCustomNamesGroupsCaption(state),
sharingPanelVisible: getSharePanelVisible(state),
settings: getSettings(state),
};
};

View File

@ -1373,7 +1373,7 @@ export const loopFilesOperations = (id, destFolderId, isCopy) => {
if (currentItem && currentItem.progress !== 100) {
dispatch(
setSecondaryProgressBarData({
icon: "move",
icon: isCopy ? "duplicate" : "move",
label: progressData.label,
percent: currentItem.progress,
visible: true,
@ -1384,7 +1384,7 @@ export const loopFilesOperations = (id, destFolderId, isCopy) => {
} else {
dispatch(
setSecondaryProgressBarData({
icon: "move",
icon: isCopy ? "duplicate" : "move",
label: progressData.label,
percent: 100,
visible: true,

View File

@ -132,7 +132,7 @@ export const isSound = (extension) => {
};
export const isVideo = (extension) => {
return createSelector(getVideoFormats, (formats) => {
return createSelector(getMediaViewerMediaFormats, (formats) => {
return presentInArray(formats, extension);
});
};
@ -538,6 +538,8 @@ export const getFileIcon = (
return `${folderPath}/svg.svg`;
case ".txt":
return `${folderPath}/txt.svg`;
case ".webm":
return `${folderPath}/webm.svg`;
case ".xls":
return `${folderPath}/xls.svg`;
case ".xlsx":
@ -588,6 +590,11 @@ export const getSelectionLength = (state) => {
return state.files.selection.length;
};
export const getSelectionTitle = createSelector(getSelection, (selection) => {
if (selection.length === 0) return null;
return selection.find((el) => el.title).title;
});
export const getViewAs = (state) => {
return state.files.viewAs;
};
@ -649,6 +656,7 @@ const getFilesContextOptions = (
const isFile = !!item.fileExst;
const isFavorite = item.fileStatus === 32;
const isFullAccess = item.access < 2;
if (item.id <= 0) return [];
@ -656,29 +664,36 @@ const getFilesContextOptions = (
options.push("download");
options.push("download-as");
options.push("restore");
options.push("separator2");
options.push("separator0");
options.push("delete");
} else {
if (!isFile) {
options.push("open");
options.push("separator0");
}
if (!(isRecent || isFavorites || isVisitor)) {
options.push("sharing-settings");
}
if (isFile) {
if (isFile && !isVisitor) {
options.push("send-by-email");
}
options.push("link-for-portal-users");
if (!isVisitor) {
options.push("separator0");
options.push("separator1");
}
if (isFile) {
options.push("show-version-history");
if (!isVisitor) {
options.push("show-version-history");
options.push("finalize-version");
options.push("block-unblock-version");
options.push("separator1");
if (isFullAccess) {
options.push("finalize-version");
options.push("block-unblock-version");
}
options.push("separator2");
if (isRecent) {
options.push("open-location");
@ -686,6 +701,8 @@ const getFilesContextOptions = (
if (!isFavorite) {
options.push("mark-as-favorite");
}
} else {
options.push("separator3");
}
if (canOpenPlayer) {
@ -708,6 +725,8 @@ const getFilesContextOptions = (
options.push("rename");
options.push("delete");
} else {
options.push("copy");
}
}
if (isFavorite && !isRecycleBin) {
@ -1148,6 +1167,17 @@ export const getOnlyFoldersSelected = createSelector(
}
);
export const getWebEditSelected = createSelector(
getSelection,
getEditedFormats,
(selection, editedFormats) => {
return selection.some((selected) => {
if (selected.isFolder === true || !selected.fileExst) return false;
return editedFormats.find((format) => selected.fileExst === format);
});
}
);
export const getAccessedSelected = createSelector(
getSelection,
getSelectionLength,
@ -1214,3 +1244,46 @@ export const getIconOfDraggedFile = (state) => {
export const getSharePanelVisible = (state) => {
return state.files.sharingPanelVisible;
};
export const isSecondaryProgressFinished = createSelector(
getSecondaryProgressData,
(data) => {
return data && data.percent === 100;
}
);
export const getSortedFiles = (state) => {
const formatKeys = Object.freeze({
OriginalFormat: 0,
});
const items = getSelection(state);
let sortedFiles = {
documents: [],
spreadsheets: [],
presentations: [],
other: [],
};
for (let item of items) {
item.checked = true;
item.format = formatKeys.OriginalFormat;
if (item.fileExst) {
if (isSpreadsheet(item.fileExst)(state)) {
sortedFiles.spreadsheets.push(item);
} else if (isPresentation(item.fileExst)(state)) {
sortedFiles.presentations.push(item);
} else if (item.fileExst !== ".pdf" && canWebEdit(item.fileExst)(state)) {
sortedFiles.documents.push(item);
} else {
sortedFiles.other.push(item);
}
} else {
sortedFiles.other.push(item);
}
}
return sortedFiles;
};

View File

@ -1511,9 +1511,9 @@
loader-utils "^1.2.3"
"@tanem/svg-injector@^8.2.0":
version "8.2.0"
resolved "https://registry.yarnpkg.com/@tanem/svg-injector/-/svg-injector-8.2.0.tgz#ae44af69c843e2de5325c326483c3c3343fd63fe"
integrity sha512-PTiUF9im6kwn5Rt7w5CcHgBXFvDiLO1SOW8AYbWarJ7EVPV2ZR/4UcgLlOPNBNs8gYgEEwdJA2Nx2t9fO/U1/g==
version "8.2.1"
resolved "https://registry.yarnpkg.com/@tanem/svg-injector/-/svg-injector-8.2.1.tgz#8d6780be1fcc142c7ff1949e4e00e942377a230e"
integrity sha512-F8KbsSQnxLHRqoenP2MmB3IWKYANGqDtpyBIQZ6/tnkW7JYgZFG8PxM+QVrfiNbe62C+1b+HfGzb4xJjdu3NYQ==
dependencies:
"@babel/runtime" "^7.12.5"
content-type "^1.0.4"
@ -2165,7 +2165,7 @@ asap@~2.0.6:
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
"asc-web-common@file:../../../packages/asc-web-common":
version "1.0.297"
version "1.0.309"
dependencies:
axios "^0.19.1"
history "4.10.1"
@ -2182,7 +2182,7 @@ asap@~2.0.6:
sjcl "^1.0.8"
"asc-web-components@file:../../../packages/asc-web-components":
version "1.0.494"
version "1.0.496"
dependencies:
email-addresses "^3.1.0"
html-to-react "^1.4.2"
@ -2779,9 +2779,9 @@ buffer@^4.3.0:
isarray "^1.0.0"
builtin-modules@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
version "3.2.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==
builtin-status-codes@^3.0.0:
version "3.0.0"
@ -2942,9 +2942,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001165:
version "1.0.30001168"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz#6fcd098c139d003b9bd484cbb9ca26cb89907f9a"
integrity sha512-P2zmX7swIXKu+GMMR01TWa4csIKELTNnZKc+f1CjebmZJQtTAEXmpQSoKVJVVcvPGAA0TEYTOUp3VehavZSFPQ==
version "1.0.30001170"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz#0088bfecc6a14694969e391cc29d7eb6362ca6a7"
integrity sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA==
capture-exit@^2.0.0:
version "2.0.0"
@ -4241,9 +4241,9 @@ ejs@^2.6.1:
integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.621:
version "1.3.628"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.628.tgz#be5a14ddf3a455de876274c84de0926439a287a7"
integrity sha512-fmhO4YGo/kapy+xL9Eq/cZwDASaTHZu3psIFYo4yc+RY1LzbZr84xjKlDImDrlrmWhOxsrDi98nX097U/xK/cQ==
version "1.3.632"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.632.tgz#3b1d89fe5065dd6a65a1dafc25bbe6f218ca9326"
integrity sha512-LkaEH9HHr9fodmm3txF4nFMyHN3Yr50HcpD/DBHpLCxzM9doV8AV0er6aBWva4IDs2aA9kGguces0rp+WKL7rg==
elliptic@^6.5.3:
version "6.5.3"
@ -5249,9 +5249,9 @@ get-caller-file@^2.0.1:
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.0.0, get-intrinsic@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.1.tgz#94a9768fcbdd0595a1c9273aacf4c89d075631be"
integrity sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49"
integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
@ -5600,9 +5600,9 @@ html-encoding-sniffer@^1.0.2:
whatwg-encoding "^1.0.1"
html-entities@^1.3.1:
version "1.3.3"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.3.tgz#3dca638a43ee7de316fc23067398491152ad4736"
integrity sha512-/VulV3SYni1taM7a4RMdceqzJWR39gpZHjBwUnsCFKWV/GJkD14CJ5F7eWcZozmHJK0/f/H5U3b3SiPkuvxMgg==
version "1.4.0"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
html-escaper@^2.0.0:
version "2.0.2"
@ -5836,9 +5836,9 @@ import-fresh@^2.0.0:
resolve-from "^3.0.0"
import-fresh@^3.0.0, import-fresh@^3.1.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.2.tgz#fc129c160c5d68235507f4331a6baad186bdbc3e"
integrity sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
resolve-from "^4.0.0"
@ -9059,9 +9059,9 @@ postcss-selector-matches@^4.0.0:
postcss "^7.0.2"
postcss-selector-not@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz#c68ff7ba96527499e832724a2674d65603b645c0"
integrity sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ==
version "4.0.1"
resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz#263016eef1cf219e0ade9a913780fc1f48204cbf"
integrity sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==
dependencies:
balanced-match "^1.0.0"
postcss "^7.0.2"
@ -9171,9 +9171,9 @@ prettier@2.1.2:
integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==
pretty-bytes@^5.1.0, pretty-bytes@^5.3.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.4.1.tgz#cd89f79bbcef21e3d21eb0da68ffe93f803e884b"
integrity sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==
version "5.5.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.5.0.tgz#0cecda50a74a941589498011cf23275aa82b339e"
integrity sha512-p+T744ZyjjiaFlMUZZv6YPC5JrkNj8maRmPaQCWFJFplUAzpIUTRaTcS+7wmZtUoFXHtESJb23ISliaWyz3SHA==
pretty-error@^2.1.1:
version "2.1.2"
@ -9514,11 +9514,11 @@ react-dev-utils@^10.2.1:
text-table "0.2.0"
react-device-detect@^1.11.14:
version "1.14.0"
resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-1.14.0.tgz#ae8bf8cff85055c030f97aa491a0c2b06c472644"
integrity sha512-fXFsZoTeLVrONrUr2sqCAXvnbouwyuqlBWoa3K92goCiPM1lUBvZqekv5TY3C02U/IrdoKLOBPFITYluwxKFyw==
version "1.15.0"
resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-1.15.0.tgz#5321f94ae3c4d51ef399b0502a6c739e32d0f315"
integrity sha512-ywjtWW04U7vaJK87IAFHhKozZhTPeDVWsfYx5CxQSQCjU5+fnMMxWZt9HnVWaNTqBEn6g8wCNWyqav7sXJrURg==
dependencies:
ua-parser-js "^0.7.22"
ua-parser-js "^0.7.23"
react-dom@^16.12.0:
version "16.14.0"
@ -9688,9 +9688,9 @@ react-scripts@3.4.3:
fsevents "2.1.2"
react-svg@^11.0.9:
version "11.2.0"
resolved "https://registry.yarnpkg.com/react-svg/-/react-svg-11.2.0.tgz#c06fa9bb974193cf6eb8317d541ef990de3e9cf6"
integrity sha512-Av00b/MBBooZepVsM19gGq5pWtOQJ1qLwcRLb1w2Q4IhYuv8Le3AWF4oKOIMTQYvmxsamN8sWXXWwqth9xA/tA==
version "11.2.1"
resolved "https://registry.yarnpkg.com/react-svg/-/react-svg-11.2.1.tgz#f2c756c54b7fda95a39872da21b2b5c1d32066b8"
integrity sha512-melHPgs52FQ0h9A6Q8I6jtBj12wQLF8ZhHrTd3pUbyTOXkkxn7DmGiNyyc0zh66pKuXaXrYMgOXl/N3ToOYs7A==
dependencies:
"@babel/runtime" "^7.12.5"
"@tanem/svg-injector" "^8.2.0"
@ -9738,9 +9738,9 @@ react-viewer@^3.2.1:
classnames "^2.2.5"
react-virtualized-auto-sizer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"
integrity sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==
version "1.0.3"
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.3.tgz#a491577dc70102b9faaef473d640437eab9db120"
integrity sha512-HnJo3Hk5Ky2TUL2GpLOs5sKiyskFwdNllI3P5Mp0tgFatz6ClnEG1gnK76/NhSkd/3YtYPTVjIsINYVBd/fRxw==
react-window-infinite-loader@^1.0.5:
version "1.0.5"
@ -11515,7 +11515,7 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
ua-parser-js@^0.7.22:
ua-parser-js@^0.7.23:
version "0.7.23"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.23.tgz#704d67f951e13195fbcd3d78818577f5bc1d547b"
integrity sha512-m4hvMLxgGHXG3O3fQVAyyAQpZzDOvwnhOTjYz5Xmr7r/+LpkNy3vJXdVRWgd1TkAb7NGROZuSy96CrlNVjA7KA==

View File

@ -1166,8 +1166,10 @@ namespace ASC.Files.Core.Data
public Dictionary<string, string> GetBunchObjectIDs(List<int> folderIDs)
{
var folderSIds = folderIDs.Select(r => r.ToString()).ToList();
return Query(FilesDbContext.BunchObjects)
.Where(r => folderIDs.Any(a => a.ToString() == r.LeftNode))
.Where(r => folderSIds.Any(a => a == r.LeftNode))
.ToDictionary(r => r.LeftNode, r => r.RightNode);
}

View File

@ -588,7 +588,7 @@ namespace ASC.Files.Core.Security
foreach (var e in filteredEntries)
{
var adapter = findedAdapters[e.RootFolderId.ToString()];
findedAdapters.TryGetValue(e.RootFolderId.ToString(), out var adapter);
if (adapter == null) continue;

View File

@ -80,11 +80,10 @@ namespace ASC.Web.Files
}
public async Task Invoke(HttpContext context)
{
using var scope = ServiceProvider.CreateScope();
var fileHandlerService = scope.ServiceProvider.GetService<FileHandlerService>();
await fileHandlerService.Invoke(context);
await Next.Invoke(context);
{
using var scope = ServiceProvider.CreateScope();
var fileHandlerService = scope.ServiceProvider.GetService<FileHandlerService>();
await fileHandlerService.Invoke(context).ConfigureAwait(false);
}
}
@ -187,31 +186,31 @@ namespace ASC.Web.Files
{
case "view":
case "download":
await DownloadFile(context);
await DownloadFile(context).ConfigureAwait(false);
break;
case "bulk":
await BulkDownloadFile(context);
await BulkDownloadFile(context).ConfigureAwait(false);
break;
case "stream":
await StreamFile(context);
await StreamFile(context).ConfigureAwait(false);
break;
case "empty":
await EmptyFile(context);
await EmptyFile(context).ConfigureAwait(false);
break;
case "tmp":
await TempFile(context);
await TempFile(context).ConfigureAwait(false);
break;
case "create":
await CreateFile(context);
await CreateFile(context).ConfigureAwait(false);
break;
case "redirect":
Redirect(context);
break;
case "diff":
await DifferenceFile(context);
await DifferenceFile(context).ConfigureAwait(false);
break;
case "track":
await TrackFile(context);
await TrackFile(context).ConfigureAwait(false);
break;
default:
throw new HttpException((int)HttpStatusCode.BadRequest, FilesCommonResource.ErrorMassage_BadRequest);
@ -696,7 +695,8 @@ namespace ASC.Web.Files
try
{
await context.Response.Body.FlushAsync();
await context.Response.Body.FlushAsync();
await context.Response.CompleteAsync();
//context.Response.SuppressContent = true;
//context.ApplicationInstance.CompleteRequest();
}

View File

@ -1,6 +1,6 @@
{
"name": "asc-people-client",
"version": "0.0.3",
"version": "0.0.4",
"private": true,
"homepage": "/products/people",
"dependencies": {

View File

@ -5,7 +5,6 @@ import { store, Headline, Loaders } from "asc-web-common";
const { getCurrentProductName } = store.auth.selectors;
const ArticleHeaderContent = ({ currentModuleName }) => {
console.log("CurrentModuleName", currentModuleName);
return currentModuleName ? (
<Headline type="menu">{currentModuleName}</Headline>
) : (

View File

@ -357,6 +357,7 @@ class SectionBodyContent extends React.Component {
groupsCaption={groupsCaption}
defaultOption={me}
defaultOptionLabel={t("MeLabel")}
employeeStatus={1}
/>
</FieldContainer>
<FieldContainer
@ -394,6 +395,7 @@ class SectionBodyContent extends React.Component {
defaultOption={me}
defaultOptionLabel={t("MeLabel")}
selectedOptions={groupMembers}
employeeStatus={1}
/>
</FieldContainer>
{groupMembers && groupMembers.length > 0 && (

View File

@ -1,5 +1,6 @@
import React, { useCallback, useMemo } from "react";
import { connect } from "react-redux";
import { isMobile } from "react-device-detect";
import { fetchPeople } from "../../../../../store/people/actions";
import { Paging } from "asc-web-components";
import { useTranslation } from "react-i18next";
@ -137,6 +138,7 @@ const SectionPagingContent = ({
displayItems={false}
disablePrevious={!filter.hasPrev()}
disableNext={!filter.hasNext()}
disableHover={isMobile}
previousAction={onPrevClick}
nextAction={onNextClick}
openDirection="top"

View File

@ -86,23 +86,13 @@ const IconButtonWrapper = styled.div`
}
`;
const capitalizeFirstLetter = (string) => {
return string && string.charAt(0).toUpperCase() + string.slice(1);
};
class ProfileInfo extends React.PureComponent {
constructor(props) {
super(props);
this.state = this.mapPropsToState(props);
}
mapPropsToState = (props) => {
const newState = {
this.state = {
profile: props.profile,
};
return newState;
};
}
onGroupClick = (e) => {
const group = e.currentTarget.dataset.id;
@ -137,9 +127,12 @@ class ProfileInfo extends React.PureComponent {
};
onSentInviteAgain = (id) => {
const { t } = this.props;
resendUserInvites(new Array(id))
.then(() => toastr.success("The invitation was successfully sent"))
.catch((error) => toastr.error(error));
.then(() => toastr.success(t("SuccessSentInvitation")))
.catch((error) =>
toastr.error(error && error.message ? error.message : error)
);
};
onEmailClick = (e) => {
@ -153,8 +146,8 @@ class ProfileInfo extends React.PureComponent {
if (profile.cultureName === language.key) return;
updateProfileCulture(profile.id, language.key).catch((err) =>
console.log(err)
updateProfileCulture(profile.id, language.key).catch((error) =>
toastr.error(error && error.message ? error.message : error)
);
};
@ -196,7 +189,9 @@ class ProfileInfo extends React.PureComponent {
const type = isVisitor ? guestCaption : userCaption;
const language = cultureName || currentCulture || this.props.culture;
const languages = this.getLanguages();
const selectedLanguage = languages.find((item) => item.key === language);
const selectedLanguage =
languages.find((item) => item.key === language) ||
languages.find((item) => item.key === this.props.culture);
const workFromDate = new Date(workFrom).toLocaleDateString(language);
const birthDayDate = new Date(birthday).toLocaleDateString(language);
const formatedSex =
@ -217,6 +212,7 @@ class ProfileInfo extends React.PureComponent {
<Link
isHovered={true}
href="https://helpcenter.onlyoffice.com/ru/guides/become-translator.aspx"
target="_blank"
>
{t("LearnMore")}
</Link>

View File

@ -121,7 +121,7 @@ class SectionBodyContent extends React.PureComponent {
source={profile.avatarMax}
userName={profile.displayName}
/>
{(isAdmin || isSelf) && (
{profile.status !== 2 && (isAdmin || isSelf) && (
<EditButtonWrapper>
<Button
size="big"

View File

@ -32,6 +32,7 @@
"SaveButton": "Save",
"ChangesApplied": "Changes are applied",
"SuccessChangeUserStatus": "The user status was successfully changed",
"SuccessSentInvitation": "The invitation was successfully sent",
"MessageEmailActivationInstuctionsSentOnEmail": "The email activation instructions have been sent to the <strong>{{ email }}</strong> email address",
"People": "People",
"Profile": "Profile",

View File

@ -32,6 +32,7 @@
"SaveButton": "Сохранить",
"ChangesApplied": "Изменения успешно применены",
"SuccessChangeUserStatus": "Статус пользователя успешно изменен",
"SuccessSentInvitation": "Приглашение было успешно отправлено",
"MessageEmailActivationInstuctionsSentOnEmail": "Инструкция по активации почты пользователя была отправлена по адресу <strong>{{ email }}</strong>",
"People": "Люди",
"Profile": "Профиль",

View File

@ -12,6 +12,11 @@ class DepartmentField extends React.Component {
return !equal(this.props, nextProps);
}
onRemoveGroup = (e) => {
const groupId = e.currentTarget.parentElement.dataset.id;
this.props.onRemoveGroup(groupId);
};
render() {
console.log("DepartmentField render");
@ -25,7 +30,6 @@ class DepartmentField extends React.Component {
onShowGroupSelector,
onCloseGroupSelector,
onRemoveGroup,
selectorIsVisible,
selectorSelectedOptions,
@ -55,11 +59,11 @@ class DepartmentField extends React.Component {
<SelectedItem
key={`department_${option.key}`}
text={option.label}
onClose={() => {
onRemoveGroup(option.key);
}}
data-id={option.key}
onClose={this.onRemoveGroup}
isInline={true}
className="department-item"
isDisabled={isDisabled}
/>
))}
</FieldContainer>

View File

@ -586,7 +586,7 @@ class CreateUserForm extends React.Component {
inputOnChange={this.onWorkFromDateChange}
inputTabIndex={6}
calendarMinDate={
profile.birthday ? new Date(profile.birthday) : new Date()
profile.birthday ? new Date(profile.birthday) : undefined
}
/>
<TextField

View File

@ -33,6 +33,7 @@ import {
setIsEditingForm,
toggleAvatarEditor,
} from "../../../../../store/people/actions";
import { getDisableProfileType } from "../../../../../store/profile/selectors";
import {
MainContainer,
AvatarContainer,
@ -47,7 +48,7 @@ import ContactsField from "./FormFields/ContactsField";
import InfoFieldContainer from "./FormFields/InfoFieldContainer";
import styled from "styled-components";
import { DataLossWarningDialog } from "../../../../dialogs";
import { api, toastr } from "asc-web-common";
import { api, toastr, store } from "asc-web-common";
import {
ChangeEmailDialog,
ChangePasswordDialog,
@ -56,6 +57,7 @@ import {
import { isMobile } from "react-device-detect";
const { createThumbnailsAvatar, loadAvatar, deleteAvatar } = api.people;
const { isTablet } = utils.device;
const { isAdmin } = store.auth.selectors;
const dialogsDataset = {
changeEmail: "changeEmail",
@ -543,7 +545,14 @@ class UpdateUserForm extends React.Component {
dialogsVisible,
isMobile,
} = this.state;
const { t, i18n, settings, avatarMax } = this.props;
const {
t,
i18n,
settings,
avatarMax,
disableProfileType,
isAdmin,
} = this.props;
const {
guestCaption,
userCaption,
@ -769,7 +778,7 @@ class UpdateUserForm extends React.Component {
{ value: "true", label: guestCaption },
{ value: "false", label: userCaption },
]}
radioIsDisabled={isLoading}
radioIsDisabled={isLoading || disableProfileType}
radioOnChange={this.onUserTypeChange}
tooltipContent={tooltipTypeContent}
helpButtonHeaderContent={t("UserType")}
@ -781,7 +790,7 @@ class UpdateUserForm extends React.Component {
inputValue={
profile.workFrom ? new Date(profile.workFrom) : undefined
}
inputIsDisabled={isLoading}
inputIsDisabled={isLoading || !isAdmin}
inputOnChange={this.onWorkFromDateChange}
inputTabIndex={7}
calendarMinDate={
@ -800,13 +809,13 @@ class UpdateUserForm extends React.Component {
labelText={`${userPostCaption}:`}
inputName="title"
inputValue={profile.title}
inputIsDisabled={isLoading}
inputIsDisabled={isLoading || !isAdmin}
inputOnChange={this.onInputChange}
inputTabIndex={9}
/>
<DepartmentField
labelText={`${groupCaption}:`}
isDisabled={isLoading}
isDisabled={isLoading || !isAdmin}
showGroupSelectorButtonTitle={t("AddButton")}
onShowGroupSelector={this.onShowGroupSelector}
onCloseGroupSelector={this.onCloseGroupSelector}
@ -909,6 +918,8 @@ const mapStateToProps = (state) => {
groups: state.people.groups,
editingForm: state.people.editingForm,
filter: state.people.filter,
disableProfileType: getDisableProfileType(state),
isAdmin: isAdmin(state),
};
};

View File

@ -91,11 +91,9 @@ class ProfileAction extends React.Component {
</PageLayout.ArticleBody>
)}
{loaded && (
<PageLayout.SectionHeader>
<SectionHeaderContent />
</PageLayout.SectionHeader>
)}
<PageLayout.SectionHeader>
{loaded ? <SectionHeaderContent /> : <Loaders.SectionHeader />}
</PageLayout.SectionHeader>
<PageLayout.SectionBody>
{loaded ? (

View File

@ -0,0 +1,19 @@
import { createSelector } from "reselect";
import { store } from "asc-web-common";
const { isAdmin, getCurrentUserId } = store.auth.selectors;
const getProfileId = (state) =>
state.profile.targetUser && state.profile.targetUser.id;
const getIsAdminProfile = (state) =>
state.profile.targetUser.listAdminModules &&
state.profile.targetUser.listAdminModules.includes("people");
export const getDisableProfileType = createSelector(
[isAdmin, getCurrentUserId, getProfileId, getIsAdminProfile],
(isAdmin, currentUserId, profileId, isAdminProfile) => {
return currentUserId === profileId || !isAdmin || isAdminProfile
? true
: false;
}
);

View File

@ -1511,9 +1511,9 @@
loader-utils "^1.2.3"
"@tanem/svg-injector@^8.2.0":
version "8.2.0"
resolved "https://registry.yarnpkg.com/@tanem/svg-injector/-/svg-injector-8.2.0.tgz#ae44af69c843e2de5325c326483c3c3343fd63fe"
integrity sha512-PTiUF9im6kwn5Rt7w5CcHgBXFvDiLO1SOW8AYbWarJ7EVPV2ZR/4UcgLlOPNBNs8gYgEEwdJA2Nx2t9fO/U1/g==
version "8.2.1"
resolved "https://registry.yarnpkg.com/@tanem/svg-injector/-/svg-injector-8.2.1.tgz#8d6780be1fcc142c7ff1949e4e00e942377a230e"
integrity sha512-F8KbsSQnxLHRqoenP2MmB3IWKYANGqDtpyBIQZ6/tnkW7JYgZFG8PxM+QVrfiNbe62C+1b+HfGzb4xJjdu3NYQ==
dependencies:
"@babel/runtime" "^7.12.5"
content-type "^1.0.4"
@ -2158,7 +2158,7 @@ asap@~2.0.6:
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
"asc-web-common@file:../../../packages/asc-web-common":
version "1.0.297"
version "1.0.309"
dependencies:
axios "^0.19.1"
history "4.10.1"
@ -2175,7 +2175,7 @@ asap@~2.0.6:
sjcl "^1.0.8"
"asc-web-components@file:../../../packages/asc-web-components":
version "1.0.494"
version "1.0.496"
dependencies:
email-addresses "^3.1.0"
html-to-react "^1.4.2"
@ -2772,9 +2772,9 @@ buffer@^4.3.0:
isarray "^1.0.0"
builtin-modules@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
version "3.2.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==
builtin-status-codes@^3.0.0:
version "3.0.0"
@ -2935,9 +2935,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001165:
version "1.0.30001168"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001168.tgz#6fcd098c139d003b9bd484cbb9ca26cb89907f9a"
integrity sha512-P2zmX7swIXKu+GMMR01TWa4csIKELTNnZKc+f1CjebmZJQtTAEXmpQSoKVJVVcvPGAA0TEYTOUp3VehavZSFPQ==
version "1.0.30001170"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz#0088bfecc6a14694969e391cc29d7eb6362ca6a7"
integrity sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA==
capture-exit@^2.0.0:
version "2.0.0"
@ -4234,9 +4234,9 @@ ejs@^2.6.1:
integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.621:
version "1.3.628"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.628.tgz#be5a14ddf3a455de876274c84de0926439a287a7"
integrity sha512-fmhO4YGo/kapy+xL9Eq/cZwDASaTHZu3psIFYo4yc+RY1LzbZr84xjKlDImDrlrmWhOxsrDi98nX097U/xK/cQ==
version "1.3.632"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.632.tgz#3b1d89fe5065dd6a65a1dafc25bbe6f218ca9326"
integrity sha512-LkaEH9HHr9fodmm3txF4nFMyHN3Yr50HcpD/DBHpLCxzM9doV8AV0er6aBWva4IDs2aA9kGguces0rp+WKL7rg==
elliptic@^6.5.3:
version "6.5.3"
@ -5242,9 +5242,9 @@ get-caller-file@^2.0.1:
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.0.0, get-intrinsic@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.1.tgz#94a9768fcbdd0595a1c9273aacf4c89d075631be"
integrity sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.2.tgz#6820da226e50b24894e08859469dc68361545d49"
integrity sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
@ -5593,9 +5593,9 @@ html-encoding-sniffer@^1.0.2:
whatwg-encoding "^1.0.1"
html-entities@^1.3.1:
version "1.3.3"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.3.tgz#3dca638a43ee7de316fc23067398491152ad4736"
integrity sha512-/VulV3SYni1taM7a4RMdceqzJWR39gpZHjBwUnsCFKWV/GJkD14CJ5F7eWcZozmHJK0/f/H5U3b3SiPkuvxMgg==
version "1.4.0"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
html-escaper@^2.0.0:
version "2.0.2"
@ -5829,9 +5829,9 @@ import-fresh@^2.0.0:
resolve-from "^3.0.0"
import-fresh@^3.0.0, import-fresh@^3.1.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.2.tgz#fc129c160c5d68235507f4331a6baad186bdbc3e"
integrity sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
resolve-from "^4.0.0"
@ -9052,9 +9052,9 @@ postcss-selector-matches@^4.0.0:
postcss "^7.0.2"
postcss-selector-not@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz#c68ff7ba96527499e832724a2674d65603b645c0"
integrity sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ==
version "4.0.1"
resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz#263016eef1cf219e0ade9a913780fc1f48204cbf"
integrity sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==
dependencies:
balanced-match "^1.0.0"
postcss "^7.0.2"
@ -9164,9 +9164,9 @@ prettier@2.1.2:
integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==
pretty-bytes@^5.1.0, pretty-bytes@^5.3.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.4.1.tgz#cd89f79bbcef21e3d21eb0da68ffe93f803e884b"
integrity sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==
version "5.5.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.5.0.tgz#0cecda50a74a941589498011cf23275aa82b339e"
integrity sha512-p+T744ZyjjiaFlMUZZv6YPC5JrkNj8maRmPaQCWFJFplUAzpIUTRaTcS+7wmZtUoFXHtESJb23ISliaWyz3SHA==
pretty-error@^2.1.1:
version "2.1.2"
@ -9507,11 +9507,11 @@ react-dev-utils@^10.2.1:
text-table "0.2.0"
react-device-detect@^1.11.14:
version "1.14.0"
resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-1.14.0.tgz#ae8bf8cff85055c030f97aa491a0c2b06c472644"
integrity sha512-fXFsZoTeLVrONrUr2sqCAXvnbouwyuqlBWoa3K92goCiPM1lUBvZqekv5TY3C02U/IrdoKLOBPFITYluwxKFyw==
version "1.15.0"
resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-1.15.0.tgz#5321f94ae3c4d51ef399b0502a6c739e32d0f315"
integrity sha512-ywjtWW04U7vaJK87IAFHhKozZhTPeDVWsfYx5CxQSQCjU5+fnMMxWZt9HnVWaNTqBEn6g8wCNWyqav7sXJrURg==
dependencies:
ua-parser-js "^0.7.22"
ua-parser-js "^0.7.23"
react-dom@^16.12.0:
version "16.14.0"
@ -9681,9 +9681,9 @@ react-scripts@3.4.3:
fsevents "2.1.2"
react-svg@^11.0.9:
version "11.2.0"
resolved "https://registry.yarnpkg.com/react-svg/-/react-svg-11.2.0.tgz#c06fa9bb974193cf6eb8317d541ef990de3e9cf6"
integrity sha512-Av00b/MBBooZepVsM19gGq5pWtOQJ1qLwcRLb1w2Q4IhYuv8Le3AWF4oKOIMTQYvmxsamN8sWXXWwqth9xA/tA==
version "11.2.1"
resolved "https://registry.yarnpkg.com/react-svg/-/react-svg-11.2.1.tgz#f2c756c54b7fda95a39872da21b2b5c1d32066b8"
integrity sha512-melHPgs52FQ0h9A6Q8I6jtBj12wQLF8ZhHrTd3pUbyTOXkkxn7DmGiNyyc0zh66pKuXaXrYMgOXl/N3ToOYs7A==
dependencies:
"@babel/runtime" "^7.12.5"
"@tanem/svg-injector" "^8.2.0"
@ -9731,9 +9731,9 @@ react-viewer@^3.2.1:
classnames "^2.2.5"
react-virtualized-auto-sizer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"
integrity sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==
version "1.0.3"
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.3.tgz#a491577dc70102b9faaef473d640437eab9db120"
integrity sha512-HnJo3Hk5Ky2TUL2GpLOs5sKiyskFwdNllI3P5Mp0tgFatz6ClnEG1gnK76/NhSkd/3YtYPTVjIsINYVBd/fRxw==
react-window-infinite-loader@^1.0.5:
version "1.0.5"
@ -11508,7 +11508,7 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
ua-parser-js@^0.7.22:
ua-parser-js@^0.7.23:
version "0.7.23"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.23.tgz#704d67f951e13195fbcd3d78818577f5bc1d547b"
integrity sha512-m4hvMLxgGHXG3O3fQVAyyAQpZzDOvwnhOTjYz5Xmr7r/+LpkNy3vJXdVRWgd1TkAb7NGROZuSy96CrlNVjA7KA==

View File

@ -456,7 +456,7 @@ namespace ASC.Employee.Core.Controllers
UpdateContacts(memberModel.Contacts, user);
user = UserManagerWrapper.AddUser(user, memberModel.PasswordHash, false, true, memberModel.IsVisitor);
user = UserManagerWrapper.AddUser(user, memberModel.PasswordHash, memberModel.FromInviteLink, true, memberModel.IsVisitor, memberModel.FromInviteLink);
var messageAction = memberModel.IsVisitor ? MessageAction.GuestCreated : MessageAction.UserCreated;
MessageService.Send(messageAction, MessageTarget.Create(user.ID), user.DisplayUserName(false, DisplayUserSettingsHelper));
@ -1380,6 +1380,24 @@ namespace ASC.Employee.Core.Controllers
foreach (var user in users)
{
if (user.IsActive) continue;
var viewer = UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
if (user == null) throw new Exception(Resource.ErrorUserNotFound);
if (viewer == null) throw new Exception(Resource.ErrorAccessDenied);
if (viewer.IsAdmin(UserManager) || viewer.ID == user.ID)
{
if (user.ActivationStatus == EmployeeActivationStatus.Activated)
{
user.ActivationStatus = EmployeeActivationStatus.NotActivated;
}
if (user.ActivationStatus == (EmployeeActivationStatus.AutoGenerated | EmployeeActivationStatus.Activated))
{
user.ActivationStatus = EmployeeActivationStatus.AutoGenerated;
}
UserManager.SaveUserInfo(user);
}
if (user.ActivationStatus == EmployeeActivationStatus.Pending)
{

View File

@ -24,6 +24,7 @@ namespace ASC.People.Models
public string Files { get; set; }
public string Password { get; set; }
public string PasswordHash { get; set; }
public bool FromInviteLink { get; set; }
}
public class UpdateMemberModel : MemberModel

View File

@ -1,6 +1,6 @@
{
"name": "asc-web-client",
"version": "0.0.3",
"version": "0.0.4",
"private": true,
"dependencies": {
"asc-web-common": "file:../../packages/asc-web-common",

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -48,6 +48,9 @@ const BodyStyle = styled.div`
}
.copyright-line {
display: grid;
grid-template-columns: 1fr max-content 1fr;
grid-column-gap: 24px;
padding-bottom: 15px;
text-align: center;
@ -56,7 +59,6 @@ const BodyStyle = styled.div`
content: "";
height: 2px;
margin-top: 9px;
width: 26%;
float: right;
}
@ -65,7 +67,6 @@ const BodyStyle = styled.div`
content: "";
height: 2px;
margin-top: 9px;
width: 26%;
float: left;
}
}
@ -86,7 +87,7 @@ const Body = () => {
useEffect(() => {
changeLanguage(i18n);
setDocumentTitle(t("AboutTitle")); //TODO: implement the ability to read the current module in redux to implement the template `${t("AboutTitle")} ${t("People")}`
}, [t, setDocumentTitle]);
}, [t]);
const gitHub = "GitHub";
const license = "AGPL-3.0";
@ -103,6 +104,7 @@ const Body = () => {
href="https://www.gnu.org/licenses/gpl-3.0.html"
isHovered={true}
fontSize="12px"
target="_blank"
>
{{ license }}
</Link>
@ -172,7 +174,7 @@ const Body = () => {
{phone}
</Text>
</div>
<Link href="http://www.onlyoffice.com" fontSize="12px">
<Link href="http://www.onlyoffice.com" fontSize="12px" target="_blank">
{link}
</Link>
@ -182,9 +184,10 @@ const Body = () => {
<Text className="text_style" fontSize="12px">
{t("SourceCode")}:{" "}
<Link
href="https://github.com/ONLYOFFICE/CommunityServer"
href="https://github.com/ONLYOFFICE/AppServer"
isHovered={true}
fontSize="12px"
target="_blank"
>
{gitHub}
</Link>

Some files were not shown because too many files have changed in this diff Show More