Merge branch 'develop' of github.com:ONLYOFFICE/DocSpace into develop

This commit is contained in:
Alexey Bannov 2022-11-08 15:38:04 +03:00
commit bfa927fcf8
50 changed files with 883 additions and 2826 deletions

View File

@ -41,23 +41,23 @@ namespace Utils
{
try
{
using (var redis = new Redis(session["REDIS_HOST_PROP"], Convert.ToInt32(session["REDIS_PORT_PROP"])))
using (var redis = new Redis(session["REDIS_HOST"], Convert.ToInt32(session["REDIS_PORT"])))
{
if (!String.IsNullOrEmpty(session["REDIS_PASSWORD_PROP"].Trim()))
redis.Password = session["REDIS_PASSWORD_PROP"];
if (!String.IsNullOrEmpty(session["REDIS_PWD"].Trim()))
redis.Password = session["REDIS_PWD"];
var pong = redis.Ping("ONLYOFFICE");
session.Log("Redis Status: IsConnected is {0}", !String.IsNullOrEmpty(pong));
session["RedisServerConnectionError"] = !String.IsNullOrEmpty(pong) ? "" : String.Format("Connection Refused HOST:{0},PORT:{1},PASS:{2}", session["REDIS_HOST_PROP"], session["REDIS_PORT_PROP"], session["REDIS_PASSWORD_PROP"]);
session["RedisServerConnectionError"] = !String.IsNullOrEmpty(pong) ? "" : String.Format("Connection Refused HOST:{0},PORT:{1},PASS:{2}", session["REDIS_HOST"], session["REDIS_PORT"], session["REDIS_PWD"]);
}
}
catch (Exception ex)
{
session.Log("RedisConnectionException '{0}'", ex.Message);
session["RedisServerConnectionError"] = String.Format("Connection Refused HOST:{0},PORT:{1},PASS:{2}", session["REDIS_HOST_PROP"], session["REDIS_PORT_PROP"], session["REDIS_PASSWORD_PROP"]);
session["RedisServerConnectionError"] = String.Format("Connection Refused HOST:{0},PORT:{1},PASS:{2}", session["REDIS_HOST"], session["REDIS_PORT"], session["REDIS_PWD"]);
}
return ActionResult.Success;
@ -69,11 +69,11 @@ namespace Utils
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = session["RABBITMQ_HOSTNAME_PROP"];
factory.Port = Convert.ToInt32(session["RABBITMQ_PORT_PROP"]);
factory.VirtualHost = session["RABBITMQ_VIRTUALHOST_PROP"];
factory.UserName = session["RABBITMQ_USERNAME_PROP"];
factory.Password = session["RABBITMQ_PASSWORD_PROP"];
factory.HostName = session["AMQP_HOST"];
factory.Port = Convert.ToInt32(session["AMQP_PORT"]);
factory.VirtualHost = session["AMQP_VHOST"];
factory.UserName = session["AMQP_USER"];
factory.Password = session["AMQP_PWD"];
try
{
@ -82,11 +82,11 @@ namespace Utils
session.Log("RabbitMQ Status: IsConnected is {0}", conn.IsOpen);
session["RabbitMQServerConnectionError"] = conn.IsOpen ? "" : String.Format("Connection Refused HOST:{0}, PORT:{1}, VirtualHost:{2}, UserName:{3}, PASS:{4}",
session["RABBITMQ_HOSTNAME_PROP"],
session["RABBITMQ_PORT_PROP"],
session["RABBITMQ_VIRTUALHOST_PROP"],
session["RABBITMQ_USERNAME_PROP"],
session["RABBITMQ_PASSWORD_PROP"]
session["AMQP_HOST"],
session["AMQP_PORT"],
session["AMQP_VHOST"],
session["AMQP_USER"],
session["AMQP_PWD"]
);
}
}
@ -95,11 +95,11 @@ namespace Utils
session.Log("RabbitMQ.Client.Exceptions.BrokerUnreachableException {0}", ex.Message);
session["RabbitMQServerConnectionError"] = String.Format("Connection Refused HOST:{0}, PORT:{1}, VirtualHost:{2}, UserName:{3}, PASS:{4}",
session["RABBITMQ_HOSTNAME_PROP"],
session["RABBITMQ_PORT_PROP"],
session["RABBITMQ_VIRTUALHOST_PROP"],
session["RABBITMQ_USERNAME_PROP"],
session["RABBITMQ_PASSWORD_PROP"]
session["AMQP_HOST"],
session["AMQP_PORT"],
session["AMQP_VHOST"],
session["AMQP_USER"],
session["AMQP_PWD"]
);
}

File diff suppressed because it is too large Load Diff

View File

@ -13,4 +13,4 @@ OutputBaseFilename="MySQL Installer Runner"
OutputDir=/
[Run]
Filename: "{pf}\MySQL\MySQL Installer for Windows\MySQLInstallerConsole.exe"; Parameters: "community install server;{param:MYSQL_VERSION|5.7.25};X64:*:servertype=Server;passwd={param:PASSWORD_PROP} -silent"; Flags: runhidden
Filename: "{pf}\MySQL\MySQL Installer for Windows\MySQLInstallerConsole.exe"; Parameters: "community install server;{param:MYSQL_VERSION|5.7.25};X64:*:servertype=Server;passwd={param:DB_PWD} -silent"; Flags: runhidden

View File

@ -1,7 +1,8 @@
REM echo ######## Set variables ########
set "publisher="Ascensio System SIA""
set "nginx_version=1.21.1"
set "nuget="%cd%\thirdparty\SimpleRestServices\src\.nuget\NuGet.exe""
set "nginx_version=1.21.1"
set "environment=test"
REM echo ######## Extracting and preparing files to build ########
%sevenzip% x build\install\win\nginx-%nginx_version%.zip -o"build\install\win\Files" -y
@ -11,7 +12,7 @@ md build\install\win\Files\nginx\temp
md build\install\win\Files\nginx\logs
md build\install\win\Files\tools
md build\install\win\Files\Logs
md build\install\win\Files\service\
md build\install\win\Files\Data
md build\install\win\Files\products\ASC.Files\server\temp
md build\install\win\Files\products\ASC.People\server\temp
md build\install\win\Files\services\ASC.Data.Backup\service\temp
@ -39,7 +40,13 @@ copy build\install\win\WinSW3.0.0.exe "build\install\win\Files\tools\Login.exe"
copy build\install\win\tools\Login.xml "build\install\win\Files\tools\Login.xml" /y
copy "build\install\win\nginx.conf" "build\install\win\Files\nginx\conf\nginx.conf" /y
rmdir build\install\win\publish /s /q
::edit environment
%sed% -i "s/\(\W\)PRODUCT.ENVIRONMENT.SUB\(\W\)/\1%environment%\2/g" build\install\win\DocSpace.aip
::delete nginx configs
del /f /q build\install\win\Files\nginx\conf\onlyoffice-login.conf
del /f /q build\install\win\Files\nginx\conf\onlyoffice-story.conf
REM echo ######## Build Utils ########
@ -50,10 +57,6 @@ rmdir build\install\win\CustomActions\C#\Utils\bin /s /q
rmdir build\install\win\CustomActions\C#\Utils\obj /s /q
REM echo ######## Delete temp files ########
del /f /q build\install\win\Files\config\sed*
del /f /q build\install\win\Files\nginx\conf\sed*
del /f /q build\install\win\Files\nginx\conf\includes\sed*
del /f /q build\install\win\Files\services\*\service\config\sed*
del /f /q build\install\win\*.back.*
REM echo ######## Build MySQL Server Installer ########
@ -61,4 +64,10 @@ iscc /Qp /S"byparam="signtool" sign /a /n "%publisher%" /t http://timestamp.digi
REM echo ######## Build DocSpace package ########
%AdvancedInstaller% /edit build\install\win\DocSpace.aip /SetVersion %BUILD_VERSION%.%BUILD_NUMBER%
IF "%SignBuild%"=="true" (
:%AdvancedInstaller% /edit build\install\win\DocSpace.aip /SetSig
:%AdvancedInstaller% /edit build\install\win\DocSpace.aip /SetDigitalCertificateFile -file %onlyoffice_codesign_path% -password "%onlyoffice_codesign_password%"
)
%AdvancedInstaller% /rebuild build\install\win\DocSpace.aip

View File

@ -12,31 +12,45 @@ $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12,Tls13'
function DownloadComponents {
param ( $prereq_list, $path )
[void](New-Item -ItemType Directory -Force -Path $path)
ForEach ( $item in $prereq_list ) {
$url = $item.link
$output = $path + $item.name
if( $item.download_allways ){
[system.console]::WriteLine("Downloading $url")
Invoke-WebRequest -Uri $url -OutFile $output
} else {
if(![System.IO.File]::Exists($output)){
try
{
if( $item.download_allways ){
[system.console]::WriteLine("Downloading $url")
Invoke-WebRequest -Uri $url -OutFile $output
} else {
if(![System.IO.File]::Exists($output)){
[system.console]::WriteLine("Downloading $url")
Invoke-WebRequest -Uri $url -OutFile $output
}
}
} catch {
Write-Host "[ERROR] Can not download" $item.name "by link" $url
}
}
}
switch ( $env:DOCUMENT_SERVER_VERSION )
{
latest { $DOCUMENT_SERVER_LINK = "https://download.onlyoffice.com/install/documentserver/windows/onlyoffice-documentserver-ee.exe" }
custom { $DOCUMENT_SERVER_LINK = $env:DOCUMENT_SERVER_CUSTOM_LINK.Replace(",", "") }
}
$nginx_version = '1.21.1'
$psql_version = '9.5.4'
$path_prereq = "${pwd}\build\install\win\"
$prerequisites = @(
@{
download_allways = $false;
name = "nginx-${nginx_version}.zip";
name = "nginx-${nginx_version}.zip";
link = "https://nginx.org/download/nginx-${nginx_version}.zip";
}
@ -45,6 +59,24 @@ $prerequisites = @(
name = "WinSW.NET4new.exe";
link = "https://github.com/winsw/winsw/releases/download/v2.11.0/WinSW.NET4.exe";
}
@{
download_allways = $true;
name = "onlyoffice-documentserver.latest.exe";
link = $DOCUMENT_SERVER_LINK
}
@{
download_allways = $false;
name = "psqlodbc_x64.msi";
link = "http://download.onlyoffice.com/install/windows/redist/psqlodbc_x64.msi"
}
@{
download_allways = $false;
name = "postgresql-${psql_version}-1-windows-x64.exe";
link = "https://get.enterprisedb.com/postgresql/postgresql-${psql_version}-1-windows-x64.exe"
}
)
$path_nuget_packages = "${pwd}\.nuget\packages\"

View File

@ -21,6 +21,7 @@ dotnet publish "%PathToRepository%\products\ASC.Files\server\ASC.Files.csproj" -
dotnet publish "%PathToRepository%\products\ASC.People\server\ASC.People.csproj" -c Release --self-contained false -o "%PathToAppFolder%\products\ASC.People\server"
rem backend services (dotnet) in directory 'services'
dotnet publish "%PathToRepository%\common\services\ASC.ApiSystem\ASC.ApiSystem.csproj" -c Release --self-contained false -o "%PathToAppFolder%\services\ASC.ApiSystem\service"
dotnet publish "%PathToRepository%\common\services\ASC.Data.Backup\ASC.Data.Backup.csproj" -c Release --self-contained false -o "%PathToAppFolder%\services\ASC.Data.Backup\service"
dotnet publish "%PathToRepository%\products\ASC.Files\service\ASC.Files.Service.csproj" -c Release --self-contained false -o "%PathToAppFolder%\services\ASC.Files.Service\service"
dotnet publish "%PathToRepository%\common\services\ASC.Notify\ASC.Notify.csproj" -c Release --self-contained false -o "%PathToAppFolder%\services\ASC.Notify\service"

View File

@ -1,3 +1,123 @@
Function RedisSetup
On Error Resume Next
Dim Shell
Set Shell = CreateObject("WScript.Shell")
Shell.Run "redis-cli config set save """"", 0, True
Shell.Run "redis-cli config rewrite", 0, True
Set Shell = Nothing
End Function
Function TestPostgreSqlConnection
On Error Resume Next
Dim ErrorText
Dim Pos, postgreSqlDriver
postgreSqlDriver = "PostgreSQL Unicode(x64)"
Session.Property("PostgreSqlConnectionError") = ""
Set ConnectionObject = CreateObject("ADODB.Connection")
ConnectionObject.Open "Driver={" & postgreSqlDriver & "};" & _
"Server=" & Session.Property("PS_DB_HOST") & ";" & _
"Port=" & Session.Property("PS_DB_PORT") & ";" & _
"Database=" & Session.Property("PS_DB_NAME") & ";" & _
"Uid=" & Session.Property("PS_DB_USER") & ";" & _
"Pwd=" & Session.Property("PS_DB_PWD")
If Err.Number <> 0 Then
ErrorText = Err.Description
Pos = InStrRev( ErrorText, "]" )
If 0 < Pos Then
ErrorText = Right( ErrorText, Len( ErrorText ) - Pos )
End If
Session.Property("PostgreSqlConnectionError") = ErrorText
End If
ConnectionObject.Close
Set ConnectionObject = Nothing
End Function
Function PostgreSqlConfigure
On Error Resume Next
If (StrComp(Session.Property("POSTGRE_SQL_PATH"),"FALSE") = 0) Then
Wscript.Quit
End If
Dim ErrorText
Dim Pos, postgreSqlDriver
Dim databaseUserName
Dim databaseUserPwd
Dim databaseName
Dim databasePort
Dim databaseHost
databaseUserName = Session.Property("PS_DB_USER")
databaseUserPwd = Session.Property("PS_DB_PWD")
databaseName = Session.Property("PS_DB_NAME")
databasePort = Session.Property("PS_DB_PORT")
databaseHost = Session.Property("PS_DB_HOST")
Call WriteToLog("PostgreSqlConfig: databaseUserName is " & databaseUserName)
Call WriteToLog("PostgreSqlConfig: databaseUserPwd is " & databaseUserPwd)
Call WriteToLog("PostgreSqlConfig: databaseName is " & databaseName)
Call WriteToLog("PostgreSqlConfig: databasePort is " & databasePort)
Call WriteToLog("PostgreSqlConfig: databaseHost is " & databaseHost)
postgreSqlDriver = "PostgreSQL Unicode(x64)"
Set ConnectionObject = CreateObject("ADODB.Connection")
ConnectionObject.Open "Driver={" & postgreSqlDriver & "};Server=" & databaseHost & ";Port=" & databasePort & ";Database=" & "postgres" & ";Uid=" & "postgres" & ";Pwd=" & "postgres"
ConnectionObject.Execute "CREATE DATABASE " & databaseName
ConnectionObject.Execute "create user " & databaseUserName & " with encrypted password '" & databaseUserPwd & "'"
ConnectionObject.Execute "grant all privileges on database " & databaseName & " to " & databaseUserName
If Err.Number <> 0 Then
ErrorText = Err.Description
Pos = InStrRev( ErrorText, "]" )
If 0 < Pos Then
Call WriteToLog("PostgreSqlConfig: error is " & ErrorText)
ErrorText = Right( ErrorText, Len( ErrorText ) - Pos )
Session.Property("PostgreSqlConnectionError") = ErrorText
End If
End If
ConnectionObject.Close
Set ConnectionObject = Nothing
End Function
Function RandomString( ByVal strLen )
Dim str, min, max
Const LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ0123456789"
min = 1
max = Len(LETTERS)
Randomize
For i = 1 to strLen
str = str & Mid( LETTERS, Int((max-min+1)*Rnd+min), 1 )
Next
RandomString = str
End Function
Function SetDocumentServerJWTSecretProp
On Error Resume Next
Session.Property("JWT_SECRET") = RandomString( 30 )
End Function
Function MySQLConfigure
On Error Resume Next
@ -28,8 +148,8 @@ Function MySQLConfigure
Session.Property("MYSQLODBCDRIVER") = mysqlDriver
Set shell = CreateObject("WScript.Shell")
dbname = Session.Property("DATABASE_PROP")
dbpass = Session.Property("PASSWORD_PROP")
dbname = Session.Property("DB_NAME")
dbpass = Session.Property("DB_PWD")
Err.Clear
installDir = shell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\MySQL AB\MySQL Server 8.0\Location")
@ -260,7 +380,7 @@ Function TestSqlConnection
Session.Property("MYSQLODBCDRIVER") = mysqlDriver
Set ConnectionObject = CreateObject("ADODB.Connection")
ConnectionObject.Open "Driver={" & mysqlDriver & "};Server=" & Session.Property("SERVER_PROP") & ";Port=" & Session.Property("PORT_PROP") & ";Uid=" & Session.Property("USERNAME_PROP") & ";Pwd=" & Session.Property("PASSWORD_PROP")
ConnectionObject.Open "Driver={" & mysqlDriver & "};Server=" & Session.Property("DB_HOST") & ";Port=" & Session.Property("DB_PORT") & ";Uid=" & Session.Property("DB_USER") & ";Pwd=" & Session.Property("DB_PWD")
If Err.Number <> 0 Then
ErrorText = Err.Description

View File

@ -91,7 +91,7 @@ public class AuditEventsRepository
var tenant = _tenantManager.GetCurrentTenant().Id;
using var auditTrailContext = _dbContextFactory.CreateDbContext();
var query =
(from q in auditTrailContext.AuditEvents
from q in auditTrailContext.AuditEvents
from p in auditTrailContext.Users.Where(p => q.UserId == p.Id).DefaultIfEmpty()
where q.TenantId == tenant
orderby q.Date descending
@ -101,16 +101,7 @@ public class AuditEventsRepository
FirstName = p.FirstName,
LastName = p.LastName,
UserName = p.UserName
});
if (startIndex > 0)
{
query = query.Skip(startIndex);
}
if (limit > 0)
{
query = query.Take(limit);
}
};
if (userId.HasValue && userId.Value != Guid.Empty)
{
@ -197,6 +188,14 @@ public class AuditEventsRepository
}
}
if (startIndex > 0)
{
query = query.Skip(startIndex);
}
if (limit > 0)
{
query = query.Take(limit);
}
return _mapper.Map<List<AuditEventQuery>, IEnumerable<AuditEventDto>>(query.ToList());
}

View File

@ -26,7 +26,6 @@ const StyledUserNameLink = styled.span`
font-size: 13px;
font-weight: 600;
display: inline-block;
${(props) => props.isVisitor && "cursor: default"};
}
.link {

View File

@ -3,7 +3,7 @@ import { useHistory } from "react-router-dom";
import Link from "@docspace/components/link";
import { StyledUserNameLink } from "../../styles/history";
import Text from "@docspace/components/text";
const HistoryBlockUser = ({ user, withComma, openUser, isVisitor }) => {
const username = user.displayName;
const history = useHistory();
@ -12,13 +12,17 @@ const HistoryBlockUser = ({ user, withComma, openUser, isVisitor }) => {
openUser(user, history);
};
const onClickProp = isVisitor ? {} : { onClick: onUserClick };
return (
<StyledUserNameLink key={user.id} className="user" isVisitor={isVisitor}>
<Link className="username link" {...onClickProp}>
{username}
</Link>
<StyledUserNameLink key={user.id} className="user">
{isVisitor ? (
<Text as="span" fontWeight={600}>
{username}
</Text>
) : (
<Link className="username link" onClick={onUserClick}>
{username}
</Link>
)}
{withComma ? "," : ""}
{withComma && <div className="space"></div>}
</StyledUserNameLink>

View File

@ -12,7 +12,7 @@ const User = ({
membersHelper,
currentMember,
updateRoomMemberRole,
currCanEditUsers,
selectionParentRoom,
setSelectionParentRoom,
}) => {
@ -22,12 +22,6 @@ const User = ({
const [userIsRemoved, setUserIsRemoved] = useState(false);
if (userIsRemoved) return null;
const currCanEditUsers =
currentMember.isOwner ||
currentMember.isAdmin ||
currentMember?.access === ShareAccessRights.FullAccess ||
currentMember?.access === ShareAccessRights.RoomManager;
const fullRoomRoleOptions = membersHelper.getOptionsByRoomType(
selectionParentRoom.roomType,
currCanEditUsers

View File

@ -117,26 +117,35 @@ const Members = ({
(member) => member.id === selfId
);
const currCanEditUsers =
currentMember.isOwner ||
currentMember.isAdmin ||
currentMember?.access === ShareAccessRights.FullAccess ||
currentMember?.access === ShareAccessRights.RoomManager;
return (
<>
<StyledUserTypeHeader>
<Text className="title">
{t("UsersInRoom")} : {members.inRoom.length}
</Text>
<IconButton
className={"icon"}
title={t("Common:AddUsers")}
iconName="/static/images/person+.react.svg"
isFill={true}
onClick={onClickInviteUsers}
size={16}
isDisabled={isDisabledInvite}
/>
{currCanEditUsers && (
<IconButton
className={"icon"}
title={t("Common:AddUsers")}
iconName="/static/images/person+.react.svg"
isFill={true}
onClick={onClickInviteUsers}
size={16}
isDisabled={isDisabledInvite}
/>
)}
</StyledUserTypeHeader>
<StyledUserList>
{Object.values(members.inRoom).map((user) => (
<User
currCanEditUsers={currCanEditUsers}
key={user.id}
t={t}
user={user}
@ -154,14 +163,16 @@ const Members = ({
{!!members.expected.length && (
<StyledUserTypeHeader isExpect>
<Text className="title">{t("ExpectPeople")}</Text>
<IconButton
className={"icon"}
title={t("Repeat invitation")}
iconName="/static/images/e-mail+.react.svg"
isFill={true}
onClick={onRepeatInvitation}
size={16}
/>
{currCanEditUsers && (
<IconButton
className={"icon"}
title={t("Repeat invitation")}
iconName="/static/images/e-mail+.react.svg"
isFill={true}
onClick={onRepeatInvitation}
size={16}
/>
)}
</StyledUserTypeHeader>
)}

View File

@ -105,16 +105,6 @@ const FilesRowContent = ({
isRoom,
} = item;
let tags = null;
if (isRoom) {
if (item.tags.length > 0) {
tags = item?.tags.join(" | ");
} else {
tags = t(RoomsTypeTranslations[item.roomType]);
}
}
return (
<>
<SimpleFilesRowContent
@ -139,18 +129,18 @@ const FilesRowContent = ({
{badgesComponent}
{!isRoom && !isRooms && quickButtons}
</div>
{!isRoom && (
<Text
containerMinWidth="200px"
containerWidth="15%"
fontSize="12px"
fontWeight={400}
// color={sideColor}
className="row_update-text"
>
{updatedDate && updatedDate}
</Text>
)}
<Text
containerMinWidth="200px"
containerWidth="15%"
fontSize="12px"
fontWeight={400}
// color={sideColor}
className="row_update-text"
>
{updatedDate && updatedDate}
</Text>
<Text
containerMinWidth="90px"
containerWidth="10%"
@ -162,7 +152,7 @@ const FilesRowContent = ({
truncate={true}
>
{isRooms
? tags
? t(RoomsTypeTranslations[item.roomType])
: !fileExst && !contentLength && !providerKey && !isMobileOnly
? `${foldersCount} ${t("Translations:Folders")} | ${filesCount} ${t(
"Translations:Files"

View File

@ -1 +0,0 @@
export { default as TrashIcon } from "./trash.react.svg";

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import commonIconsStyles from "@docspace/components/utils/common-icons-style";
import { TrashIcon } from "./svg";
import TrashIcon from "PUBLIC_DIR/images/trash.react.svg";
import PlusIcon from "@docspace/client/public/images/plus.react.svg";
import Link from "@docspace/components/link";
import TextInput from "@docspace/components/text-input";

View File

@ -1559,6 +1559,22 @@ class FilesActionStore {
const deleteOption = this.getOption("delete-room", t);
const showOption = this.getOption("show-info", t);
const { selection } = this.filesStore;
const { canArchiveRoom } = this.accessRightsStore;
const canArchive = selection.map((s) => canArchiveRoom(s)).filter((s) => s);
if (canArchive.length <= 0) {
let pinName = "unpin";
selection.forEach((item) => {
if (!item.pinned) pinName = "pin";
});
const pin = this.getOption(pinName, t);
itemsCollection.set(pinName, pin);
}
itemsCollection
.set("unarchive", archive)
.set("show-info", showOption)

View File

@ -1414,15 +1414,24 @@ class FilesStore {
}
if (isArchiveFolder) {
roomOptions = this.removeOptions(roomOptions, [
"edit-room",
"invite-users-to-room",
"pin-room",
"unpin-room",
"archive-room",
"separator1",
"room-info",
]);
if (!canArchive) {
roomOptions = this.removeOptions(roomOptions, [
"edit-room",
"invite-users-to-room",
"archive-room",
"separator1",
]);
} else {
roomOptions = this.removeOptions(roomOptions, [
"edit-room",
"invite-users-to-room",
"pin-room",
"unpin-room",
"archive-room",
"separator1",
"room-info",
]);
}
} else {
roomOptions = this.removeOptions(roomOptions, [
"delete",

View File

@ -137,7 +137,7 @@ class InfoPanelStore {
if (!this.getIsRooms) return;
const currentFolderRoomId = this.selectedFolderStore.pathParts[1];
const prevRoomId = selectionParentRoom?.id;
const prevRoomId = this.selectionParentRoom?.id;
if (!currentFolderRoomId || currentFolderRoomId === prevRoomId) return;

View File

@ -39,9 +39,7 @@ const sideInfoTabletStyle = css`
margin: ${(props) => props.theme.rowContent.sideInfo.margin};
${commonCss};
color: ${(props) => props.color && props.color};
white-space: nowrap;
overflow: ${(props) => props.theme.rowContent.sideInfo.overflow};
text-overflow: ${(props) => props.theme.rowContent.sideInfo.textOverflow};
${truncateCss};
`;
const StyledRowContent = styled.div`
@ -88,6 +86,7 @@ const MainContainerWrapper = styled.div`
${mainWrapperTabletStyle}
}
`;
MainContainerWrapper.defaultProps = { theme: Base };
const MainContainer = styled.div`

View File

@ -1,142 +0,0 @@
import React, { useState } from "react";
import styled from "styled-components";
import ModalDialog from "@appserver/components/modal-dialog";
import Button from "@appserver/components/button";
import TagHandler from "./handlers/tagHandler";
import SetRoomParams from "./sub-components/SetRoomParams";
import RoomTypeList from "./sub-components/RoomTypeList";
import { roomTypes } from "./data";
import IconButton from "@appserver/components/icon-button";
const StyledModalDialog = styled(ModalDialog)`
.header-with-button {
display: flex;
align-items: center;
flex-direction: row;
gap: 12px;
}
`;
const CreateRoomDialog = ({
t,
visible,
onClose,
onCreate,
fetchedTags,
isLoading,
folderFormValidation,
}) => {
const [isScrollLocked, setIsScrollLocked] = useState(false);
const [roomParams, setRoomParams] = useState({
title: "",
type: undefined,
tags: [],
isPrivate: false,
storageLocation: undefined,
rememberStorageLocation: false,
thirdpartyFolderName: "",
icon: "",
});
const setRoomTags = (newTags) =>
setRoomParams({ ...roomParams, tags: newTags });
const tagHandler = new TagHandler(roomParams.tags, setRoomTags, fetchedTags);
const setRoomType = (newRoomType) => {
const [roomByType] = roomTypes.filter((room) => room.type === newRoomType);
tagHandler.refreshDefaultTag(t(roomByType.title));
setRoomParams((prev) => ({
...prev,
type: newRoomType,
}));
};
const onCreateRoom = () => {
onCreate(roomParams);
};
const isChooseRoomType = roomParams.type === undefined;
const goBack = () => {
setRoomParams({
title: "",
type: undefined,
tags: [],
isPrivate: false,
storageLocation: undefined,
rememberStorageLocation: false,
thirdpartyFolderName: "",
icon: "",
});
};
return (
<StyledModalDialog
displayType="aside"
withBodyScroll
visible={visible}
onClose={onClose}
isScrollLocked={isScrollLocked}
withFooterBorder
>
<ModalDialog.Header>
{isChooseRoomType ? (
t("ChooseRoomType")
) : (
<div className="header-with-button">
<IconButton
size="15px"
iconName="/static/images/arrow.path.react.svg"
className="sharing_panel-arrow"
onClick={goBack}
/>
<div>{t("CreateRoom")}</div>
</div>
)}
</ModalDialog.Header>
<ModalDialog.Body>
{isChooseRoomType ? (
<RoomTypeList t={t} setRoomType={setRoomType} />
) : (
<SetRoomParams
t={t}
tagHandler={tagHandler}
roomParams={roomParams}
setRoomParams={setRoomParams}
setRoomType={setRoomType}
setIsScrollLocked={setIsScrollLocked}
/>
)}
</ModalDialog.Body>
{!isChooseRoomType && (
<ModalDialog.Footer>
<Button
tabIndex={5}
label={t("Common:Create")}
size="normal"
primary
scale
onClick={onCreateRoom}
isLoading={isLoading}
/>
<Button
tabIndex={5}
label={t("Common:CancelButton")}
size="normal"
scale
onClick={onClose}
/>
</ModalDialog.Footer>
)}
</StyledModalDialog>
);
};
export default CreateRoomDialog;

View File

@ -1,95 +0,0 @@
import React, { useState } from "react";
import ModalDialog from "@appserver/components/modal-dialog";
import Button from "@appserver/components/button";
import TagHandler from "./handlers/tagHandler";
import { roomTypes } from "./data";
import SetRoomParams from "./sub-components/SetRoomParams";
const EditRoomDialog = ({
t,
visible,
onClose,
onSave,
isLoading,
fetchedRoomParams,
fetchedTags,
folderFormValidation,
}) => {
const [isScrollLocked, setIsScrollLocked] = useState(false);
const [roomParams, setRoomParams] = useState({
...fetchedRoomParams,
// cant fetch
isPrivate: false,
storageLocation: undefined,
rememberStorageLocation: false,
thirdpartyFolderName: "",
});
const setRoomTags = (newTags) =>
setRoomParams({ ...roomParams, tags: newTags });
const tagHandler = new TagHandler(roomParams.tags, setRoomTags, fetchedTags);
const setRoomType = (newRoomType) => {
const [roomByType] = roomTypes.filter((room) => room.type === newRoomType);
tagHandler.refreshDefaultTag(t(roomByType.title));
setRoomParams((prev) => ({
...prev,
type: newRoomType,
}));
};
const onEditRoom = () => {
onSave(roomParams);
};
return (
<ModalDialog
displayType="aside"
withBodyScroll
visible={visible}
onClose={onClose}
isScrollLocked={isScrollLocked}
withFooterBorder
>
<ModalDialog.Header>{t("RoomEditing")}</ModalDialog.Header>
<ModalDialog.Body>
<SetRoomParams
t={t}
tagHandler={tagHandler}
roomParams={roomParams}
setRoomParams={setRoomParams}
setRoomType={setRoomType}
setIsScrollLocked={setIsScrollLocked}
isEdit
/>
</ModalDialog.Body>
<ModalDialog.Footer>
<Button
tabIndex={5}
label={t("Common:SaveButton")}
size="normal"
primary
scale
onClick={onEditRoom}
isLoading={isLoading}
/>
<Button
tabIndex={5}
label={t("Common:CancelButton")}
size="normal"
scale
onClick={onClose}
/>
</ModalDialog.Footer>
</ModalDialog>
);
};
export default EditRoomDialog;

View File

@ -1,61 +0,0 @@
import { RoomsType } from "@appserver/common/constants";
export const roomTypes = [
{
type: RoomsType.FillingFormsRoom,
title: "FillingFormsRoomTitle",
description: "FillingFormsRoomDescription",
withSecondaryInfo: true,
},
{
type: RoomsType.EditingRoom,
title: "CollaborationRoomTitle",
description: "CollaborationRoomDescription",
withSecondaryInfo: true,
},
{
type: RoomsType.ReviewRoom,
title: "ReviewRoomTitle",
description: "ReviewRoomDescription",
withSecondaryInfo: true,
},
{
type: RoomsType.ReadOnlyRoom,
title: "ViewOnlyRoomTitle",
description: "ViewOnlyRoomDescription",
withSecondaryInfo: true,
},
{
type: RoomsType.CustomRoom,
title: "CustomRoomTitle",
description: "CustomRoomDescription",
withSecondaryInfo: false,
},
];
export const thirparties = [
{
id: 1,
title: "Onlyoffice DocSpace",
},
{
id: 2,
title: "DropBox",
},
{
id: 3,
title: "Google Drive",
},
{
id: 4,
title: "OneDrive",
},
{
id: 5,
title: "Nextcloud",
},
{
id: 6,
title: "Yandex Disk",
},
];

View File

@ -1,49 +0,0 @@
class TagHandler {
constructor(tags, setTags, fetchedTags) {
this.tags = tags;
this.setTags = setTags;
this.fetchedTags = fetchedTags;
}
createRandomTagId() {
return "_" + Math.random().toString(36).substr(2, 9);
}
refreshDefaultTag(name) {
let newTags = [...this.tags].filter((tag) => !tag.isDefault);
newTags.unshift({
id: this.createRandomTagId(),
name,
isDefault: true,
});
this.setTags(newTags);
}
addTag(name) {
let newTags = [...this.tags];
newTags.push({
id: this.createRandomTagId(),
name,
});
this.setTags(newTags);
}
addNewTag(name) {
let newTags = [...this.tags];
newTags.push({
id: this.createRandomTagId(),
isNew: true,
name,
});
this.setTags(newTags);
}
deleteTag(id) {
let newTags = [...this.tags];
newTags = newTags.filter((tag) => tag.id !== id);
this.setTags(newTags);
}
}
export default TagHandler;

View File

@ -1,177 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
import styled from "styled-components";
import IconButton from "@appserver/components/icon-button";
import Text from "@appserver/components/text";
import RoomLogo from "@appserver/components/room-logo";
import HelpButton from "@appserver/components/help-button";
const StyledRoomType = styled.div`
cursor: pointer;
padding: 16px;
width: 100%;
box-sizing: border-box;
display: flex;
gap: 12px;
align-items: center;
.choose_room-logo_wrapper {
width: 32px;
margin-bottom: auto;
}
.choose_room-info_wrapper {
.choose_room-title {
display: flex;
flex-direction: row;
gap: 6px;
align-items: center;
.choose_room-title-text {
font-weight: 600;
font-size: 14px;
line-height: 16px;
}
.choose_room-title-info_button {
border-radius: 50%;
background-color: #a3a9ae;
circle,
rect {
fill: #ffffff;
}
}
}
.choose_room-description {
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: #a3a9ae;
}
}
.choose_room-forward_btn {
margin-left: auto;
max-width: 17px;
max-height: 17px;
min-width: 17px;
min-height: 17px;
}
`;
const StyledDisplayItem = styled(StyledRoomType)`
background-color: #f8f8f8;
border: 1px solid #f8f8f8;
border-radius: 6px;
.choose_room-forward_btn {
display: none;
}
`;
const StyledListItem = styled(StyledRoomType)`
background-color: #ffffff;
border: 1px solid ${(props) => (props.isOpen ? "#2DA7DB" : "#ECEEF1")};
border-radius: 6px;
`;
const StyledDropdownButton = styled(StyledRoomType)`
background-color: #ffffff;
border-radius: 6px;
border: 1px solid ${(props) => (props.isOpen ? "#2DA7DB" : "#ECEEF1")};
.choose_room-forward_btn {
&.dropdown-button {
transform: ${(props) =>
props.isOpen ? "rotate(-90deg)" : "rotate(90deg)"};
}
}
`;
const StyledDropdownItem = styled(StyledRoomType)`
&:hover {
background-color: #f3f4f4;
}
.choose_room-forward_btn {
display: none;
}
`;
const RoomType = ({ t, room, onClick, type = "listItem", isOpen }) => {
const arrowClassName =
type === "dropdownButton"
? "choose_room-forward_btn dropdown-button"
: type === "dropdownItem"
? "choose_room-forward_btn dropdown-item"
: "choose_room-forward_btn";
const onSecondaryInfoClick = (e) => {
e.stopPropagation();
};
const content = (
<>
<div className="choose_room-logo_wrapper">
<RoomLogo type={room.type} />
</div>
<div className="choose_room-info_wrapper">
<div className="choose_room-title">
<Text noSelect className="choose_room-title-text">
{t(room.title)}
</Text>
{room.withSecondaryInfo && (
<div onClick={onSecondaryInfoClick}>
<HelpButton
displayType="auto"
className="choose_room-title-info_button"
iconName="/static/images/info.react.svg"
offsetRight={0}
tooltipContent={isOpen ? t(room.description) : null}
size={12}
/>
</div>
)}
</div>
<Text noSelect className="choose_room-description">
{t(room.description)}
</Text>
</div>
<IconButton
className={arrowClassName}
iconName="images/arrow.react.svg"
size={16}
onClick={() => {}}
/>
</>
);
return type === "listItem" ? (
<StyledListItem onClick={onClick}>{content}</StyledListItem>
) : type === "dropdownButton" ? (
<StyledDropdownButton onClick={onClick} isOpen={isOpen}>
{content}
</StyledDropdownButton>
) : type === "dropdownItem" ? (
<StyledDropdownItem onClick={onClick} isOpen={isOpen}>
{content}
</StyledDropdownItem>
) : (
<StyledDisplayItem>{content}</StyledDisplayItem>
);
};
RoomType.propTypes = {
room: PropTypes.object,
onClick: PropTypes.func,
type: PropTypes.oneOf([
"displayItem",
"listItem",
"dropdownButton",
"dropdownItem",
]),
isOpen: PropTypes.bool,
};
export default RoomType;

View File

@ -1,70 +0,0 @@
import React, { useState } from "react";
import styled from "styled-components";
import { roomTypes } from "../data";
import RoomType from "./RoomType";
const StyledRoomTypeDropdown = styled.div`
display: flex;
flex-direction: column;
width: 100%;
.dropdown-content-wrapper {
max-width: 100%;
position: relative;
background: #ffffff;
${(props) => !props.isOpen && "display: none"};
.dropdown-content {
margin-top: 4px;
background: #ffffff;
overflow: visible;
z-index: 400;
top: 0;
left: 0;
box-sizing: border-box;
width: 100%;
position: absolute;
display: flex;
flex-direction: column;
padding: 6px 0;
border: 1px solid #d0d5da;
box-shadow: 0px 12px 40px rgba(4, 15, 27, 0.12);
border-radius: 6px;
}
}
`;
const RoomTypeDropdown = ({ t, currentRoom, setRoomType }) => {
const [isOpen, setIsOpen] = useState(false);
const toggleIsOpen = () => setIsOpen(!isOpen);
return (
<StyledRoomTypeDropdown isOpen={isOpen}>
<RoomType
t={t}
room={currentRoom}
type="dropdownButton"
isOpen={isOpen}
onClick={toggleIsOpen}
/>
<div className="dropdown-content-wrapper">
<div className="dropdown-content">
{roomTypes.map((room) => (
<RoomType
t={t}
key={room.type}
room={room}
type="dropdownItem"
onClick={() => {
setRoomType(room.type);
toggleIsOpen();
}}
/>
))}
</div>
</div>
</StyledRoomTypeDropdown>
);
};
export default RoomTypeDropdown;

View File

@ -1,31 +0,0 @@
import React from "react";
import styled from "styled-components";
import { roomTypes } from "../data";
import RoomType from "./RoomType";
const StyledRoomTypeList = styled.div`
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
`;
const RoomTypeList = ({ t, setRoomType }) => {
return (
<StyledRoomTypeList>
{roomTypes.map((room) => (
<RoomType
t={t}
key={room.type}
room={room}
type={"listItem"}
onClick={() => setRoomType(room.type)}
/>
))}
</StyledRoomTypeList>
);
};
export default RoomTypeList;

View File

@ -1,165 +0,0 @@
import React from "react";
import styled from "styled-components";
import RoomTypeDropdown from "./RoomTypeDropdown";
import StorageLocation from "./StorageLocation";
import TextInput from "@appserver/components/text-input";
import Label from "@appserver/components/label";
import ToggleButton from "@appserver/components/toggle-button";
import HelpButton from "@appserver/components/help-button";
import Text from "@appserver/components/text";
import AvatarEditor from "@appserver/components/avatar-editor";
import TagInput from "./TagInput";
import { StyledParam } from "./StyledParam";
import RoomType from "./RoomType";
import { roomTypes } from "../data";
const StyledSetRoomParams = styled.div`
display: flex;
flex-direction: column;
width: 100%;
gap: 20px;
.set_room_params-input {
display: flex;
flex-direction: column;
gap: 4px;
}
`;
const StyledIconEditorWrapper = styled.div`
.use_modal-avatar_editor_body {
margin: 0;
}
.use_modal-buttons_wrapper {
display: none;
}
`;
const SetRoomParams = ({
t,
roomParams,
setRoomParams,
setRoomType,
tagHandler,
setIsScrollLocked,
isEdit,
}) => {
const onChangeName = (e) =>
setRoomParams({ ...roomParams, title: e.target.value });
const onChangeIsPrivate = () =>
setRoomParams({ ...roomParams, isPrivate: !roomParams.isPrivate });
const onChangeThidpartyFolderName = (e) =>
setRoomParams({ ...roomParams, thirdpartyFolderName: e.target.value });
const [currentRoomTypeData] = roomTypes.filter(
(room) => room.type === roomParams.type
);
return (
<StyledSetRoomParams>
{isEdit ? (
<RoomType t={t} room={currentRoomTypeData} type="displayItem" />
) : (
<RoomTypeDropdown
t={t}
currentRoom={currentRoomTypeData}
setRoomType={setRoomType}
/>
)}
<div className="set_room_params-input">
<Label
display="display"
htmlFor="room-name"
text={`${t("Common:Name")}:`}
title="Fill the first name field"
/>
<TextInput
id="room-name"
value={roomParams.title}
onChange={onChangeName}
scale
placeholder={t("NamePlaceholder")}
tabIndex={1}
/>
</div>
<TagInput
t={t}
tagHandler={tagHandler}
setIsScrollLocked={setIsScrollLocked}
/>
<StyledParam isPrivate>
<div className="set_room_params-info">
<div className="set_room_params-info-title">
<Text className="set_room_params-info-title-text">
{t("MakeRoomPrivateTitle")}
</Text>
<HelpButton
displayType="auto"
className="set_room_params-info-title-help"
iconName="/static/images/info.react.svg"
offsetRight={0}
tooltipContent={t("MakeRoomPrivateDescription")}
size={12}
/>
</div>
<div className="set_room_params-info-description">
{t("MakeRoomPrivateDescription")}
</div>
</div>
<ToggleButton
className="set_room_params-toggle"
isChecked={roomParams.isPrivate}
onChange={onChangeIsPrivate}
/>
</StyledParam>
<StorageLocation
t={t}
roomParams={roomParams}
setRoomParams={setRoomParams}
setIsScrollLocked={setIsScrollLocked}
/>
<StyledParam folderName>
<div className="set_room_params-info">
<div className="set_room_params-info-title">
<Text className="set_room_params-info-title-text">
{`${t("FolderNameTitle")}:`}
</Text>
</div>
<div className="set_room_params-info-description">
{t("FolderNameDescription")}
</div>
</div>
<div className="set_room_params-input">
<TextInput
id="room-folder-title"
scale
value={roomParams.thirdpartyFolderName}
onChange={onChangeThidpartyFolderName}
placeholder={`${
roomParams.storageLocation
? roomParams.storageLocation.title + " - "
: ""
}${t("Home:NewRoom")}`}
tabIndex={1}
/>
</div>
</StyledParam>
{/* <StyledIconEditorWrapper>
<AvatarEditor useModalDialog={false}></AvatarEditor>
</StyledIconEditorWrapper> */}
</StyledSetRoomParams>
);
};
export default SetRoomParams;

View File

@ -1,184 +0,0 @@
import React, { useState, useRef } from "react";
import styled from "styled-components";
import { ReactSVG } from "react-svg";
import { thirparties } from "../../data";
import { StyledDropDown, StyledDropDownWrapper } from "../StyledDropdown";
import { isHugeMobile } from "@appserver/components/utils/device";
import DomHelpers from "@appserver/components/utils/domHelpers";
import Text from "@appserver/components/text";
import Button from "@appserver/components/button";
import DropDownItem from "@appserver/components/drop-down-item";
import Checkbox from "@appserver/components/checkbox";
const StyledStorageLocation = styled.div`
display: flex;
flex-direction: column;
.set_room_params-thirdparty {
display: flex;
flex-direction: row;
gap: 8px;
&-combobox {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 5px 7px;
background: #ffffff;
border-radius: 3px;
max-height: 32px;
border: ${(props) => `1px solid ${props.isOpen ? "#2DA7DB" : "#d0d5da"}`};
&:hover {
border: ${(props) =>
`1px solid ${props.isOpen ? "#2DA7DB" : "#a3a9ae"}`};
}
&-text {
font-weight: 400;
font-size: 13px;
line-height: 20px;
color: ${(props) => (props.isGrayLabel ? "#a3a9ae" : "#333333")};
}
&-expander {
display: flex;
align-items: center;
justify-content: center;
width: 6.35px;
svg {
transform: ${(props) =>
props.isOpen ? "rotate(180deg)" : "rotate(0)"};
width: 6.35px;
height: auto;
path {
fill: #a3a9ae;
}
}
}
}
&-checkbox {
margin-top: 8px;
.checkbox {
margin-right: 8px;
}
.checkbox-text {
font-weight: 400;
font-size: 13px;
line-height: 20px;
}
}
}
`;
const ThirpartyComboBox = ({
t,
roomParams,
setRoomParams,
setIsScrollLocked,
}) => {
const dropdownRef = useRef(null);
const [isGrayLabel, setIsGrayLabel] = useState(true);
const [isOpen, setIsOpen] = useState(false);
const toggleIsOpen = () => {
if (isOpen) setIsScrollLocked(false);
else {
setIsScrollLocked(true);
calculateDropdownDirection();
}
setIsOpen(!isOpen);
};
const [dropdownDirection, setDropdownDirection] = useState("bottom");
const setStorageLocaiton = (thirparty) => {
setIsGrayLabel(false);
setRoomParams({ ...roomParams, storageLocation: thirparty });
setIsOpen(false);
setIsScrollLocked(false);
};
const setRememberStorageLocation = () =>
setRoomParams({
...roomParams,
rememberStorageLocation: !roomParams.rememberStorageLocation,
});
const calculateDropdownDirection = () => {
const { top: offsetTop } = DomHelpers.getOffset(dropdownRef.current);
const offsetBottom = window.innerHeight - offsetTop;
const neededHeightDesktop = Math.min(thirparties.length * 32 + 16, 404);
const neededHeightMobile = Math.min(thirparties.length * 32 + 16, 180);
const neededheight = isHugeMobile()
? neededHeightMobile
: neededHeightDesktop;
setDropdownDirection(neededheight > offsetBottom ? "top" : "bottom");
};
return (
<StyledStorageLocation isGrayLabel={isGrayLabel} isOpen={isOpen}>
<div className="set_room_params-thirdparty">
<div
className="set_room_params-thirdparty-combobox"
onClick={toggleIsOpen}
>
<Text className="set_room_params-thirdparty-combobox-text" noSelect>
{roomParams.storageLocation?.title || "Select"}
</Text>
<ReactSVG
className="set_room_params-thirdparty-combobox-expander"
src={"/static/images/expander-down.react.svg"}
/>
</div>
<Button
className="set_room_params-thirdparty-connect"
size="small"
label={t("Common:Connect")}
/>
</div>
<StyledDropDownWrapper
className="dropdown-content-wrapper"
ref={dropdownRef}
>
<StyledDropDown
className="dropdown-content"
open={isOpen}
forwardedRef={dropdownRef}
clickOutsideAction={toggleIsOpen}
maxHeight={isHugeMobile() ? 158 : 382}
directionY={dropdownDirection}
marginTop={dropdownDirection === "bottom" ? "4px" : "-36px"}
>
{thirparties.map((thirdparty) => (
<DropDownItem
className="dropdown-item"
label={thirdparty.title}
key={thirdparty.id}
height={32}
heightTablet={32}
onClick={() => setStorageLocaiton(thirdparty)}
/>
))}
</StyledDropDown>
</StyledDropDownWrapper>
<Checkbox
className="set_room_params-thirdparty-checkbox"
label={t("StorageLocationRememberChoice")}
isChecked={roomParams.rememberStorageLocation}
onChange={setRememberStorageLocation}
/>
</StyledStorageLocation>
);
};
export default ThirpartyComboBox;

View File

@ -1,47 +0,0 @@
import React from "react";
import Text from "@appserver/components/text";
import Checkbox from "@appserver/components/checkbox";
import { StyledParam } from "../StyledParam";
import HelpButton from "@appserver/components/help-button";
import ThirpartyComboBox from "./ThirpartyComboBox";
const StorageLocation = ({
t,
roomParams,
setRoomParams,
setIsScrollLocked,
}) => {
return (
<StyledParam storageLocation>
<div className="set_room_params-info">
<div className="set_room_params-info-title">
<Text className="set_room_params-info-title-text">
{t("StorageLocationTitle")}
</Text>
<HelpButton
displayType="auto"
className="set_room_params-info-title-help"
iconName="/static/images/info.react.svg"
offsetRight={0}
tooltipContent={t("StorageLocationDescription")}
size={12}
/>
</div>
<div className="set_room_params-info-description">
{t("StorageLocationDescription")}
</div>
</div>
<ThirpartyComboBox
t={t}
roomParams={roomParams}
setRoomParams={setRoomParams}
setIsScrollLocked={setIsScrollLocked}
/>
</StyledParam>
);
};
export default StorageLocation;

View File

@ -1,57 +0,0 @@
import styled from "styled-components";
import { smallTablet } from "@appserver/components/utils/device";
import DropDown from "@appserver/components/drop-down";
const StyledDropDownWrapper = styled.div`
width: 100%;
position: relative;
`;
const StyledDropDown = styled(DropDown)`
margin-top: ${(props) => (props.marginTop ? props.marginTop : "4px")};
padding: 6px 0;
background: #ffffff;
border: 1px solid #d0d5da;
box-shadow: 0px 12px 40px rgba(4, 15, 27, 0.12);
border-radius: 3px;
overflow: hidden;
width: 446px;
max-width: 446px;
div {
max-width: 446px;
}
@media ${smallTablet} {
width: calc(100vw - 34px);
max-width: calc(100vw - 34px);
div {
max-width: calc(100vw - 34px);
}
}
.dropdown-item {
height: 32px !important;
max-height: 32px !important;
cursor: pointer;
box-sizing: border-box;
width: 100%;
padding: 6px 8px;
font-weight: 400;
font-size: 13px;
line-height: 20px;
color: #333333;
&:hover {
background: #f3f4f4;
}
&-separator {
height: 7px !important;
max-height: 7px !important;
}
}
`;
export { StyledDropDownWrapper, StyledDropDown };

View File

@ -1,66 +0,0 @@
import styled, { css } from "styled-components";
const StyledParam = styled.div`
box-sizing: border-box;
display: flex;
width: 100%;
${(props) =>
props.isPrivate
? css`
flex-direction: row;
justify-content: space-between;
`
: props.storageLocation
? css`
flex-direction: column;
gap: 12px;
`
: props.folderName
? css`
flex-direction: column;
gap: 4px;
`
: ""}
.set_room_params-info {
display: flex;
flex-direction: column;
gap: 4px;
.set_room_params-info-title {
display: flex;
flex-direction: row;
align-items: center;
gap: 6px;
.set_room_params-info-title-text {
font-weight: 600;
font-size: 13px;
line-height: 20px;
}
.set_room_params-info-title-help {
border-radius: 50%;
background-color: #a3a9ae;
circle,
rect {
fill: #ffffff;
}
}
}
.set_room_params-info-description {
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: #a3a9ae;
}
}
.set_room_params-toggle {
width: 28px;
height: 16px;
margin: 2px 0;
}
`;
export { StyledParam };

View File

@ -1,54 +0,0 @@
import Tag from "@appserver/components/tag";
import React from "react";
import styled from "styled-components";
const StyledTagList = styled.div`
margin-top: 2px;
display: flex;
flex-direction: row;
gap: 4px;
flex-wrap: wrap;
width: 100%;
.set_room_params-tag_input-tag {
padding: 6px 8px;
border-radius: 3px;
margin: 0;
.tag-icon {
margin-left: 10px;
}
}
`;
const TagList = ({ t, tagHandler }) => {
const { tags } = tagHandler;
return (
<StyledTagList className="set_room_params-tag_input-tag_list">
{tags.length ? (
tags.map((tag) => (
<Tag
key={tag.id}
className="set_room_params-tag_input-tag"
tag="script"
label={tag.name}
isNewTag
onDelete={() => {
tagHandler.deleteTag(tag.id);
}}
/>
))
) : (
<Tag
className="set_room_params-tag_input-tag"
tag="script"
label={t("Common:NoTags")}
isDisabled
/>
)}
</StyledTagList>
);
};
export default TagList;

View File

@ -1,161 +0,0 @@
import React, { useState, useRef } from "react";
import styled from "styled-components";
import Label from "@appserver/components/label";
import TextInput from "@appserver/components/text-input";
import TagList from "./TagList";
import DropDownItem from "@appserver/components/drop-down-item";
import { StyledDropDown, StyledDropDownWrapper } from "../StyledDropdown";
import { isMobile } from "@appserver/components/utils/device";
const StyledTagInput = styled.div`
.set_room_params-tag_input {
&-label_wrapper {
&-label {
cursor: pointer;
width: auto;
display: inline-block;
}
}
}
.dropdown-content-wrapper {
margin-bottom: -4px;
max-width: 100%;
position: relative;
}
`;
const TagInput = ({ t, tagHandler, setIsScrollLocked }) => {
const [tagInput, setTagInput] = useState("");
const [isOpen, setIsOpen] = useState(false);
const chosenTags = tagHandler.tags.map((tag) => tag.name);
const fetchedTags = tagHandler.fetchedTags;
const filteredFetchedTags = fetchedTags.filter((tag) =>
tag.toLowerCase().includes(tagInput.toLowerCase())
);
const tagsForDropdown = filteredFetchedTags.filter(
(tag) => !chosenTags.includes(tag)
);
const onTagInputChange = (e) => setTagInput(e.target.value);
const preventDefault = (e) => e.preventDefault();
const openDropdown = () => {
setIsScrollLocked(true);
setIsOpen(true);
};
const closeDropdown = () => {
setIsScrollLocked(false);
setIsOpen(false);
};
const tagsInputElement = document.getElementById("tags-input");
const onClickOutside = () => {
tagsInputElement.blur();
};
const addNewTag = () => {
tagHandler.addNewTag(tagInput);
setTagInput("");
tagsInputElement.blur();
};
const addFetchedTag = (name) => {
tagHandler.addTag(name);
setTagInput("");
tagsInputElement.blur();
};
const dropdownRef = useRef(null);
let dropdownItems = tagsForDropdown.map((tag, i) => (
<DropDownItem
className="dropdown-item"
height={32}
heightTablet={32}
key={i}
label={tag}
onClick={() => {
addFetchedTag(tag);
console.log(tag);
}}
/>
));
if (
tagInput &&
![...tagsForDropdown, ...chosenTags].find((tag) => tagInput === tag)
) {
const dropdownItemNewTag = (
<DropDownItem
key={-2}
className="dropdown-item"
onMouseDown={preventDefault}
onClick={addNewTag}
label={`${t("CreateTagOption")}${tagInput}`}
height={32}
heightTablet={32}
/>
);
//dropdownItems = [dropdownItemNewTag, ...dropdownItems];
if (tagsForDropdown.length > 0) {
dropdownItems = [
dropdownItemNewTag,
<DropDownItem height={7} heightTablet={7} key={-1} isSeparator />,
...dropdownItems,
];
} else {
dropdownItems = [dropdownItemNewTag, ...dropdownItems];
}
}
return (
<StyledTagInput className="set_room_params-input set_room_params-tag_input">
<div className="set_room_params-tag_input-label_wrapper">
<Label
className="set_room_params-tag_input-label_wrapper-label"
display="display"
htmlFor="tags-input"
text={`${t("Common:Tags")}:`}
title="Fill the first name field"
/>
</div>
<TextInput
id="tags-input"
value={tagInput}
onChange={onTagInputChange}
onFocus={openDropdown}
onBlur={closeDropdown}
scale
placeholder={t("TagsPlaceholder")}
tabIndex={2}
/>
<StyledDropDownWrapper
className="dropdown-content-wrapper"
ref={dropdownRef}
onMouseDown={preventDefault}
>
{dropdownItems.length > 0 && (
<StyledDropDown
className="dropdown-content"
open={isOpen}
forwardedRef={dropdownRef}
clickOutsideAction={onClickOutside}
maxHeight={isMobile() ? 158 : 382}
showDisabledItems={false}
>
{dropdownItems}
</StyledDropDown>
)}
</StyledDropDownWrapper>
<TagList t={t} tagHandler={tagHandler} />
</StyledTagInput>
);
};
export default TagInput;

View File

@ -1,25 +0,0 @@
import EmptyTrashDialog from "./EmptyTrashDialog";
import DeleteDialog from "./DeleteDialog";
import DownloadDialog from "./DownloadDialog";
import ConvertDialog from "./ConvertDialog";
import DeleteThirdPartyDialog from "./DeleteThirdPartyDialog";
import ConnectDialog from "./ConnectDialog";
import ThirdPartyMoveDialog from "./ThirdPartyMoveDialog";
import ThirdPartyDialog from "./ThirdPartyDialog";
import ConflictResolveDialog from "./ConflictResolveDialog";
import CreateRoomDialog from "./CreateEditRoomDialog/CreateRoomDialog";
import EditRoomDialog from "./CreateEditRoomDialog/EditRoomDialog";
export {
EmptyTrashDialog,
DeleteDialog,
DownloadDialog,
ConvertDialog,
DeleteThirdPartyDialog,
ConnectDialog,
ThirdPartyMoveDialog,
ThirdPartyDialog,
ConflictResolveDialog,
CreateRoomDialog,
EditRoomDialog,
};

View File

@ -1,140 +0,0 @@
import styled, { css } from "styled-components";
import { Base } from "@appserver/components/themes";
import {
mobile,
smallTablet,
tablet,
} from "@appserver/components/utils/device";
const StyledHistoryList = styled.div`
display: flex;
flex-direction: column;
`;
const StyledUserNameLink = styled.span`
white-space: normal;
margin: 1px 0;
.username {
font-size: 13px;
font-weight: 600;
display: inline-block;
text-underline-offset: 2px;
}
`;
const StyledHistoryBlock = styled.div`
width: 100%;
display: flex;
gap: 8px;
padding: 16px 0;
border-bottom: ${(props) => `solid 1px ${props.theme.infoPanel.borderColor}`};
.avatar {
min-width: 32px;
}
.info {
width: calc(100% - 40px);
max-width: calc(100% - 40px);
display: flex;
flex-direction: column;
gap: 2px;
.title {
display: flex;
flex-direction: row;
gap: 4px;
.name {
font-weight: 600;
font-size: 14px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.secondary-info {
white-space: nowrap;
font-weight: 400;
font-size: 14px;
color: #a3a9ae;
@media ${mobile} {
display: none;
}
}
.date {
white-space: nowrap;
display: inline-block;
margin-left: auto;
font-weight: 600;
font-size: 12px;
color: #a3a9ae;
}
}
.block-content {
.appointing {
.appointing-user {
font-weight: 600;
font-size: 13px;
}
}
.users {
.user-list {
.space {
width: 4px;
display: inline-block;
}
}
}
.files-list {
margin-top: 10px;
display: flex;
flex-direction: column;
padding: 8px 0;
background: ${(props) => props.theme.infoPanel.history.fileBlockBg};
border-radius: 3px;
.file {
padding: 4px 16px;
display: flex;
gap: 8px;
flex-direction: row;
align-items: center;
justify-content: start;
.icon {
min-width: 24px;
}
.file-title {
font-weight: 600;
font-size: 14px;
display: flex;
min-width: 0;
gap: 0;
.name {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.exst {
flex-shrink: 0;
color: #a3a9ae;
}
}
.location-btn {
margin-left: auto;
min-width: 16px;
}
}
}
}
}
`;
StyledHistoryBlock.defaultProps = { theme: Base };
export { StyledHistoryList, StyledUserNameLink, StyledHistoryBlock };

View File

@ -1,92 +0,0 @@
import styled, { css } from "styled-components";
import { Base } from "@appserver/components/themes";
const StyledUserTypeHeader = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 24px 0 16px;
.title {
font-weight: 600;
font-size: 13px;
line-height: 20px;
color: #a3a9ae;
}
.icon {
path,
rect {
fill: ${(props) => props.theme.infoPanel.members.iconColor};
}
}
`;
const StyledUserList = styled.div`
display: flex;
flex-direction: column;
`;
const StyledUser = styled.div`
display: flex;
align-items: center;
gap: 8px;
padding: 8px 0;
.avatar {
opacity: ${(props) => (props.isExpect ? 0.5 : 1)};
min-width: 32px;
min-height: 32px;
}
.name {
opacity: ${(props) => (props.isExpect ? 0.5 : 1)};
font-weight: 600;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.me-label {
font-weight: 600;
font-size: 14px;
color: #a3a9ae;
margin-left: -8px;
}
.role-wrapper {
padding-left: 8px;
margin-left: auto;
font-weight: 600;
font-size: 13px;
line-height: 20px;
white-space: nowrap;
.role {
a {
padding-right: ${(props) => (props.canEditRole ? "16px" : "0")};
margin-right: ${(props) => (props.canEditRole ? "-6px" : "0")};
span {
color: ${(props) => (props.canEditRole ? "#555f65" : "#A3A9AE")};
}
&:hover {
text-decoration: none;
}
svg {
${(props) => !props.canEditRole && "display: none"};
path {
fill: #a3a9ae;
}
}
}
}
}
`;
StyledUserTypeHeader.defaultProps = { theme: Base };
export { StyledUserTypeHeader, StyledUserList, StyledUser };

View File

@ -1,39 +0,0 @@
import React from "react";
import styled from "styled-components";
import { withTranslation } from "react-i18next";
const EmptyScreenContainer = styled.div`
margin: 80px auto;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 32px;
.empty-screen-text {
font-family: "Open Sans";
font-style: normal;
font-weight: 600;
font-size: 14px;
line-height: 16px;
text-align: center;
}
`;
const EmptyScreen = ({ t }) => {
return (
<EmptyScreenContainer>
<div className="no-thumbnail-img-wrapper">
<img
size="96px"
className="no-thumbnail-img"
src="images/empty_screen_info_panel.png"
/>
</div>
<div className="empty-screen-text">{t("EmptyScreenText")}</div>
</EmptyScreenContainer>
);
};
export default withTranslation(["InfoPanel"])(EmptyScreen);

View File

@ -1,32 +0,0 @@
import Text from "@docspace/components/text";
import React from "react";
import { withTranslation } from "react-i18next";
import { ReactSVG } from "react-svg";
import { StyledTitle } from "../../styles/styles.js";
const SeveralItems = (props) => {
const { t, selectedItems, getIcon, getFolderInfo } = props;
const itemsIcon = getIcon(24, ".file");
return (
<>
<StyledTitle>
<ReactSVG className="icon" src={itemsIcon} />
<Text className="text" fontWeight={600} fontSize="16px">
{`${t("ItemsSelected")}: ${selectedItems.length}`}
</Text>
</StyledTitle>
<div className="no-thumbnail-img-wrapper">
<img
size="96px"
className="no-thumbnail-img"
src="images/empty_screen.png"
/>
</div>
</>
);
};
export default withTranslation(["InfoPanel"])(SeveralItems);

View File

@ -1,88 +0,0 @@
import React from "react";
import EmptyScreen from "./EmptyScreen";
import SeveralItems from "./SeveralItems";
import SingleItem from "./SingleItem";
const Details = ({
t,
selectedItems,
selectedFolder,
getFolderInfo,
getIcon,
getFolderIcon,
getShareUsers,
onSelectItem,
setSharingPanelVisible,
createThumbnail,
personal,
culture,
isRootFolder,
isRecycleBinFolder,
isRecentFolder,
isFavoritesFolder,
isShareFolder,
isCommonFolder,
isPrivacyFolder,
}) => {
const singleItem = (item) => {
const dontShowLocation = isRootFolder;
const dontShowSize = item.isFolder && (isFavoritesFolder || isRecentFolder);
const dontShowAccess =
isRecycleBinFolder ||
isRootFolder ||
item.rootFolderId === 7 ||
(item.isFolder && item.pathParts && item.pathParts[0] === 7);
const dontShowOwner = isRootFolder && (isFavoritesFolder || isRecentFolder);
return (
<SingleItem
t={t}
selectedItem={item}
onSelectItem={onSelectItem}
setSharingPanelVisible={setSharingPanelVisible}
getFolderInfo={getFolderInfo}
getIcon={getIcon}
getFolderIcon={getFolderIcon}
getShareUsers={getShareUsers}
dontShowLocation={dontShowLocation}
dontShowSize={dontShowSize}
dontShowAccess={dontShowAccess}
dontShowOwner={dontShowOwner}
personal={personal}
culture={culture}
createThumbnail={createThumbnail}
/>
);
};
return (
<>
{selectedItems.length === 0 ? (
// Can get future changes, currently only "My documents" displays its info
isRootFolder &&
(isRecycleBinFolder ||
isRecentFolder ||
isFavoritesFolder ||
isShareFolder ||
isCommonFolder) ? (
<EmptyScreen />
) : (
singleItem({
...selectedFolder,
isFolder: true,
})
)
) : selectedItems.length === 1 ? (
singleItem(selectedItems[0])
) : (
<SeveralItems selectedItems={selectedItems} getIcon={getIcon} />
)}
</>
);
};
export default Details;

View File

@ -1,26 +0,0 @@
import React from "react";
import styled from "styled-components";
import Text from "@docspace/components/text";
import { withTranslation } from "react-i18next";
const StyledGalleryEmptyScreen = styled.div`
.info-panel_gallery-empty-screen-img {
display: block;
margin: 0 auto;
padding: 56px 0 48px 0;
}
`;
const GalleryEmptyScreen = ({ t }) => {
return (
<StyledGalleryEmptyScreen className="info-panel_gallery-empty-screen">
<img
className="info-panel_gallery-empty-screen-img"
src="images/form-gallery-search.react.svg"
alt="Empty Screen Gallery image"
/>
<Text textAlign="center">{t("GalleryEmptyScreenDescription")}</Text>
</StyledGalleryEmptyScreen>
);
};
export default withTranslation("FormGallery")(GalleryEmptyScreen);

View File

@ -1,89 +0,0 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { withTranslation, Trans } from "react-i18next";
import { LANGUAGE } from "@docspace/common/constants";
import Text from "@docspace/components/text";
import { ReactSVG } from "react-svg";
import {
StyledProperties,
StyledSubtitle,
StyledGalleryThumbnail,
StyledTitle,
} from "../../styles/styles.js";
import getCorrectDate from "@appserver/components/utils/getCorrectDate";
import getCorrectDate from "@docspace/components/utils/getCorrectDate";
import { getCookie } from "@docspace/common/utils/index";
const SingleItem = (props) => {
const { t, selectedItem, getIcon, culture, personal } = props;
const parseAndFormatDate = (date) => {
const locale = personal ? localStorage.getItem(LANGUAGE) : culture;
const correctDate = getCorrectDate(locale, date);
return correctDate;
};
const src = getIcon(32, ".docxf");
const thumbnailBlank = getIcon(96, ".docxf");
const thumbnailUrl =
selectedItem?.attributes?.template_image?.data.attributes?.formats?.small
?.url;
return (
<>
<StyledTitle>
<ReactSVG className="icon" src={src} />
<Text className="text">{selectedItem.attributes.name_form}</Text>
</StyledTitle>
{thumbnailUrl ? (
<StyledGalleryThumbnail>
<img className="info-panel_gallery-img" src={thumbnailUrl} alt="" />
</StyledGalleryThumbnail>
) : (
<div className="no-thumbnail-img-wrapper">
<ReactSVG className="no-thumbnail-img" src={thumbnailBlank} />
</div>
)}
<StyledSubtitle>
<Text fontWeight="600" fontSize="14px">
{t("SystemProperties")}
</Text>
</StyledSubtitle>
<StyledProperties>
<div className="property">
<Text className="property-title">{t("Home:ByLastModifiedDate")}</Text>
<Text className="property-content">
{parseAndFormatDate(selectedItem.attributes.updatedAt)}
</Text>
</div>
<div className="property">
<Text className="property-title">{t("Common:Size")}</Text>
<Text className="property-content">
{selectedItem.attributes.file_size}
</Text>
</div>
<div className="property">
<Text className="property-title">{t("Common:Pages")}</Text>
<Text className="property-content">
{selectedItem.attributes.file_pages}
</Text>
</div>
</StyledProperties>
</>
);
};
export default inject(({ settingsStore }) => {
const { getIcon, personal, culture } = settingsStore;
return {
getIcon,
};
})(withTranslation(["InfoPanel", "Common", "Files"])(observer(SingleItem)));

View File

@ -1,87 +0,0 @@
import React from "react";
import Text from "@appserver/components/text";
import Link from "@appserver/components/link";
import IconButton from "@appserver/components/icon-button";
import { ReactSVG } from "react-svg";
import { StyledUserNameLink } from "../../styles/VirtualRoom/history";
const HistoryBlockContent = ({ t, action, details }) => {
return (
<div className="block-content">
{action === "message" ? (
<Text>{details.message}</Text>
) : action === "appointing" ? (
<div className="appointing">
{`${t("appointed")}
${details.appointedRole} `}{" "}
<UserNameLink user={details.appointedUser} />
</div>
) : action === "users" ? (
<div className="users">
<div className="user-list">
added users{" "}
{details.users.map((user, i) => (
<UserNameLink
key={user.id}
user={user}
withComma={i + 1 !== details.users.length}
/>
))}
</div>
</div>
) : action === "files" ? (
<div className="files">
<Text>add new 2 files into the folder My project</Text>
<div className="files-list">
{details.files.map((file) => (
<div className="file" key={file.id}>
<ReactSVG className="icon" src={file.icon} />
<div className="file-title">
<span className="name">{file.title.split(".")[0]}</span>
<span className="exst">{file.fileExst}</span>
</div>
<IconButton
className="location-btn"
iconName="/static/images/folder-location.react.svg"
size="16"
isFill={true}
onClick={() => {}}
/>
</div>
))}
</div>
</div>
) : null}
</div>
);
};
const UserNameLink = ({ user, withComma }) => {
const username = user.displayName || user.email;
const space = <div className="space"></div>;
return (
<StyledUserNameLink className="user">
{user.profileUrl ? (
<Link
className="username link"
isHovered
type="action"
href={user.profileURl}
>
{username}
{withComma ? "," : ""}
{withComma && space}
</Link>
) : (
<div className="username text" key={user.id}>
{username}
{withComma ? "," : ""}
{withComma && space}
</div>
)}
</StyledUserNameLink>
);
};
export default HistoryBlockContent;

View File

@ -1,72 +0,0 @@
import Avatar from "@appserver/components/avatar";
import ContextMenuButton from "@appserver/components/context-menu-button";
import Text from "@appserver/components/text";
import React from "react";
import { StyledTitle } from "../../styles/styles";
import {
StyledHistoryBlock,
StyledHistoryList,
} from "../../styles/VirtualRoom/history";
import { fillingFormsVR } from "../mock_data";
import getCorrectDate from "@appserver/components/utils/getCorrectDate";
import HistoryBlockContent from "./historyBlockContent";
const History = ({ t, personal, culture }) => {
const data = fillingFormsVR;
const parseAndFormatDate = (date) => {
const locale = personal ? localStorage.getItem(LANGUAGE) : culture;
const correctDate = getCorrectDate(locale, date);
return correctDate;
};
return (
<>
<StyledTitle withBottomBorder>
<img className="icon" src={data.icon} alt="thumbnail-icon" />
<Text className="text">{data.title}</Text>
<ContextMenuButton getData={() => {}} className="context-menu-button" />
</StyledTitle>
<StyledHistoryList>
{data.history.map((operation) => (
<StyledHistoryBlock key={operation.id}>
<Avatar
role="user"
className="avatar"
size="min"
source={
operation.user.avatar ||
(operation.user.displayName
? ""
: operation.user.email && "/static/images/@.react.svg")
}
userName={operation.user.displayName}
/>
<div className="info">
<div className="title">
<Text className="name">{operation.user.displayName}</Text>
{operation.user.isOwner && (
<Text className="secondary-info">
{t("Common:Owner").toLowerCase()}
</Text>
)}
<Text className="date">
{parseAndFormatDate(operation.date)}
</Text>
</div>
<HistoryBlockContent
t={t}
action={operation.action}
details={operation.details}
/>
</div>
</StyledHistoryBlock>
))}
</StyledHistoryList>
</>
);
};
export default History;

View File

@ -1,78 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
import { StyledUser } from "../../styles/VirtualRoom/members";
import Avatar from "@appserver/components/avatar";
import LinkWithDropdown from "@appserver/components/link-with-dropdown";
const User = ({ t, user, selfId, isExpect }) => {
return (
<StyledUser
isExpect={isExpect}
key={user.id}
canEditRole={user.role !== "Owner"}
>
<Avatar
role="user"
className="avatar"
size="min"
source={
user.avatar ||
(user.displayName ? "" : user.email && "/static/images/@.react.svg")
}
userName={user.displayName}
/>
<div className="name">{user.displayName || user.email}</div>
{selfId === user.id && (
<div className="me-label">&nbsp;{`(${t("Common:MeLabel")})`}</div>
)}
<div className="role-wrapper">
<LinkWithDropdown
className="role"
containerMinWidth="fit-content"
directionX="right"
directionY="bottom"
fontSize="13px"
fontWeight={600}
hasScroll={true}
withBackdrop={false}
dropdownType="apparDashedAfterHover"
isDisabled={user.role === "Owner"}
data={[
{
key: "key1",
label: "Room manager",
onClick: () => {},
},
{
key: "key2",
label: "Co-worker",
onClick: function noRefCheck() {},
},
{
key: "key3",
label: "Viewer",
onClick: function noRefCheck() {},
},
{
isSeparator: true,
key: "key4",
},
{
key: "key5",
label: "Remove",
onClick: function noRefCheck() {},
},
]}
>
{user.role}
</LinkWithDropdown>
</div>
</StyledUser>
);
};
User.propTypes = { user: PropTypes.object };
export default User;

View File

@ -1,27 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
import User from "./User";
import { StyledUserList } from "../../styles/VirtualRoom/members";
const UserList = ({ t, users, selfId, isExpect }) => {
return (
<StyledUserList>
{users.map((user) => (
<User
t={t}
key={user.id}
selfId={selfId}
user={user}
isExpect={isExpect}
/>
))}
</StyledUserList>
);
};
UserList.propTypes = {
users: PropTypes.array,
};
export default UserList;

View File

@ -1,56 +0,0 @@
import ContextMenuButton from "@appserver/components/context-menu-button";
import IconButton from "@appserver/components/icon-button";
import Text from "@appserver/components/text";
import React from "react";
import { StyledTitle } from "../../styles/styles";
import { StyledUserTypeHeader } from "../../styles/VirtualRoom/members";
import { fillingFormsVR } from "../mock_data";
import UserList from "./UserList";
const Members = ({ t, selfId }) => {
const data = fillingFormsVR;
return (
<>
<StyledTitle withBottomBorder>
<img className="icon" src={data.icon} alt="thumbnail-icon" />
<Text className="text">{data.title}</Text>
<ContextMenuButton getData={() => {}} className="context-menu-button" />
</StyledTitle>
<StyledUserTypeHeader>
<Text className="title">
{t("Users in room")} : {data.members.inRoom.length}
</Text>
<IconButton
className={"icon"}
title={t("Common:AddUsers")}
iconName="/static/images/person+.react.svg"
isFill={true}
onClick={() => {}}
size={16}
color={"#316DAA"}
/>
</StyledUserTypeHeader>
<UserList t={t} users={data.members.inRoom} selfId={selfId} />
<StyledUserTypeHeader>
<Text className="title">{`${t("Expect people")}:`}</Text>
<IconButton
className={"icon"}
title={t("Repeat invitation")}
iconName="/static/images/e-mail+.react.svg"
isFill={true}
onClick={() => {}}
size={16}
color={"#316DAA"}
/>
</StyledUserTypeHeader>
<UserList t={t} users={data.members.expect} isExpect />
</>
);
};
export default Members;

View File

@ -1,123 +0,0 @@
const files = [
{
fileExst: ".png",
icon: "/static/images/icons/24/image.svg",
isFolder: false,
id: 34,
title: "Windows 12 Wallpaper Purple.png",
},
{
fileExst: ".pptx",
icon: "/static/images/icons/24/pptx.svg",
isFolder: false,
id: 3,
title: "ONLYOFFICE Sample Presentation With Long Name.pptx",
},
{
fileExst: ".docx",
icon: "/static/images/icons/24/docx.svg",
isFolder: false,
id: 5,
title: "курсач.docx",
},
];
const people = [
{
email: "nikita.mushka@onlyoffice.com",
avatar:
"http://192.168.0.102:8092/images/default_user_photo_size_82-82.png",
isOwner: true,
id: "66faa6e4-f133-11ea-b126-00ffeec8b4ef",
displayName: "Мушка Никита",
profileUrl: "http://192.168.9.102:8092/products/people/view/administrator",
role: "Owner",
},
{
email: "yoshiko05@rohan.biz",
avatar: "",
isOwner: false,
id: "1231234",
displayName: "Rebecca Holt",
profileUrl: "asdasd",
role: "Room manager",
},
{
email: "yoshiko05@rohan.biz",
avatar:
"https://images.unsplash.com/photo-1519699047748-de8e457a634e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=880&q=80",
isOwner: false,
id: "345970",
displayName: "Angela Garcia",
profileUrl: "",
role: "Viewer",
},
{
email: "kk@mail.ru",
avatar: "/images/default_user_photo_size_82-82.png",
isOwner: false,
id: "5db1213e-7f73-434e-9d6a-af699821d3c9",
displayName:
"Some random guy with a really long name, like i mean some dumb long one",
profileUrl: "http://localhost:8092/products/people/view/kk",
role: "Viewer",
},
{
email: "ycummerata@yahoo.com",
avatar: "",
isOwner: false,
id: "389457",
displayName: "",
profileUrl: "",
role: "Viewer",
},
];
const fillingFormsVR = {
title: "Filling forms room",
icon: "images/icons/32/folder.svg",
members: {
inRoom: [...people.slice(0, 3)],
expect: [...people.slice(3)],
},
history: [
{
id: 3,
user: people[0],
date: "2022-04-23T19:04:43.511Z",
action: "files",
details: { type: "delete", files: [...files] },
},
{
id: 2,
user: people[0],
date: "2022-04-23T18:39:43.511Z",
action: "appointing",
details: {
appointedUser: people[1],
appointedRole: "room administrator",
},
},
{
id: 1,
user: people[0],
date: "2022-04-23T18:35:43.511Z",
action: "users",
details: {
type: "add",
users: [...people.slice(1)],
},
},
{
id: 0,
user: people[0],
date: "2022-04-23T18:25:43.511Z",
action: "message",
details: { message: 'Created room "Filling forms room"' },
},
],
};
export { fillingFormsVR };

View File

@ -1,91 +0,0 @@
import React from "react";
import styled, { css } from "styled-components";
import { withTranslation } from "react-i18next";
import { inject, observer } from "mobx-react";
import { isMobile } from "react-device-detect";
import { default as Container } from "../../../../components/EmptyContainer/EmptyContainer";
import Link from "@appserver/components/link";
import IconButton from "@appserver/components/icon-button";
import { tablet } from "@appserver/components/utils/device";
import { Events } from "../../../../helpers/constants";
const StyledWrapper = styled.div`
.empty-folder_container {
grid-row-gap: 8px;
grid-column-gap: 40px;
height: 100px;
align-items: center;
grid-row-gap: 8px;
grid-column-gap: 40px;
height: 100px;
@media ${tablet} {
padding: 14px 0;
}
${isMobile &&
css`
padding: 14px 0;
`}
}
`;
const linkStyles = {
isHovered: true,
type: "action",
fontWeight: "600",
className: "empty-folder_link",
display: "flex",
};
const EmptyContainer = ({ theme, setCreateRoomDialogVisible }) => {
linkStyles.color = theme.filesEmptyContainer.linkColor;
const onCreateRoom = () => {
const event = new Event(Events.ROOM_CREATE);
window.dispatchEvent(event);
};
const buttons = (
<div className="empty-folder_container-links">
<IconButton
className="empty-folder_container-icon"
size="12"
iconName="images/plus.svg"
isFill
onClick={onCreateRoom}
/>
<Link onClick={onCreateRoom} {...linkStyles}>
Create room
</Link>
</div>
);
return (
<StyledWrapper>
<Container
headerText={"Welcome to virtual rooms!"}
descriptionText={"Please create the first room."}
imageSrc="images/empty_screen_corporate.png"
buttons={buttons}
/>
</StyledWrapper>
);
};
export default inject(({ auth, dialogsStore }) => {
const { theme } = auth.settingsStore;
const { setCreateRoomDialogVisible } = dialogsStore;
return {
theme,
setCreateRoomDialogVisible,
};
})(withTranslation(["Home", "Common"])(observer(EmptyContainer)));

View File

Before

Width:  |  Height:  |  Size: 896 B

After

Width:  |  Height:  |  Size: 896 B