Merge branch 'develop' into feature/public-room

This commit is contained in:
Nikita Gopienko 2023-05-26 12:51:30 +03:00
commit 797df5b076
22 changed files with 518 additions and 54 deletions

View File

@ -11,7 +11,7 @@ import getCorrectDate from "@docspace/components/utils/getCorrectDate";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
//import EditingWrapperComponent from "../components/EditingWrapperComponent";
import { getTitleWithoutExst } from "../helpers/files-helpers";
import { getTitleWithoutExtension } from "SRC_DIR/helpers/filesUtils";
//import { getDefaultFileName } from "@docspace/client/src/helpers/filesUtils";
//import ItemIcon from "../components/ItemIcon";
import { getCookie } from "@docspace/common/utils";
@ -125,20 +125,13 @@ export default function withContent(WrappedContent) {
} = filesStore;
const { clearActiveOperations, fileCopyAs } = uploadDataStore;
const {
isRecycleBinFolder,
isPrivacyFolder,
isArchiveFolder,
} = treeFoldersStore;
const { isRecycleBinFolder, isPrivacyFolder, isArchiveFolder } =
treeFoldersStore;
const { replaceFileStream, setEncryptionAccess } = auth;
const {
culture,
personal,
folderFormValidation,
isDesktopClient,
} = auth.settingsStore;
const { culture, personal, folderFormValidation, isDesktopClient } =
auth.settingsStore;
const {
setConvertPasswordDialogVisible,
@ -146,7 +139,7 @@ export default function withContent(WrappedContent) {
setFormCreationInfo,
} = dialogsStore;
const titleWithoutExt = getTitleWithoutExst(item, false);
const titleWithoutExt = getTitleWithoutExtension(item, false);
return {
createFile,

View File

@ -8,7 +8,7 @@ import { combineUrl } from "@docspace/common/utils";
import config from "PACKAGE_FILE";
import { getTitleWithoutExst } from "../../helpers/files-helpers";
import { getTitleWithoutExtension } from "SRC_DIR/helpers/filesUtils";
import { getDefaultFileName } from "@docspace/client/src/helpers/filesUtils";
import Dialog from "./sub-components/Dialog";
@ -71,7 +71,7 @@ const CreateEvent = ({
if (title) {
const item = { fileExst: extension, title: title };
setStartValue(getTitleWithoutExst(item, fromTemplate));
setStartValue(getTitleWithoutExtension(item, fromTemplate));
} else {
setStartValue(defaultName);
}
@ -105,7 +105,7 @@ const CreateEvent = ({
newValue =
templateId === null
? getDefaultFileName(extension)
: getTitleWithoutExst({ fileExst: extension });
: getTitleWithoutExtension({ fileExst: extension });
setStartValue(newValue);
}
@ -322,11 +322,8 @@ export default inject(
const { id: parentId } = selectedFolderStore;
const {
replaceFileStream,
setEncryptionAccess,
currentTariffStatusStore,
} = auth;
const { replaceFileStream, setEncryptionAccess, currentTariffStatusStore } =
auth;
const { isDesktopClient } = auth.settingsStore;

View File

@ -1,12 +1,9 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";
import toastr from "@docspace/components/toast/toastr";
import { getTitleWithoutExst } from "../../helpers/files-helpers";
import Dialog from "./sub-components/Dialog";
import { getTitleWithoutExtension } from "SRC_DIR/helpers/filesUtils";
const RenameEvent = ({
type,
@ -34,13 +31,13 @@ const RenameEvent = ({
const { t } = useTranslation(["Files"]);
React.useEffect(() => {
setStartValue(getTitleWithoutExst(item, false));
setStartValue(getTitleWithoutExtension(item, false));
setEventDialogVisible(true);
}, [item]);
const onUpdate = React.useCallback((e, value) => {
const originalTitle = getTitleWithoutExst(item);
const originalTitle = getTitleWithoutExtension(item);
let timerId;
@ -138,12 +135,8 @@ export default inject(
uploadDataStore,
dialogsStore,
}) => {
const {
setIsLoading,
addActiveItems,
updateFile,
renameFolder,
} = filesStore;
const { setIsLoading, addActiveItems, updateFile, renameFolder } =
filesStore;
const { id, setSelectedFolder } = selectedFolderStore;

View File

@ -39,13 +39,6 @@ export const getAccessIcon = (access) => {
}
};
export const getTitleWithoutExst = (item, fromTemplate) => {
const titleWithoutExst = item.title.split(".").slice(0, -1).join(".");
return titleWithoutExst && item.fileExst && !fromTemplate
? titleWithoutExst
: item.title;
};
export const checkProtocol = (fileId, withRedirect) =>
new Promise((resolve, reject) => {
const onBlur = () => {

View File

@ -265,3 +265,10 @@ export const connectedCloudsTypeIcon = (key) => {
default:
}
};
export const getTitleWithoutExtension = (item, fromTemplate) => {
const titleWithoutExst = item.title.split(".").slice(0, -1).join(".");
return titleWithoutExst && item.fileExst && !fromTemplate
? titleWithoutExst
: item.title;
};

View File

@ -190,6 +190,11 @@ const StyledProperties = styled.div`
}
.property-content {
white-space: pre-wrap;
display: -webkit-box;
display: -moz-box;
display: -ms-box;
word-break: break-word;
overflow: hidden;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;

View File

@ -202,7 +202,11 @@ const StyledVersionRow = styled(Row)`
margin-top: 5px;
}
display: ${(props) => props.showEditPanel && "none"};
word-break: break-word;
display: ${(props) => (props.showEditPanel ? "none" : "-webkit-box")};
display: ${(props) => (props.showEditPanel ? "none" : "-moz-box")};
display: ${(props) => (props.showEditPanel ? "none" : "-ms-box")};
text-overflow: ellipsis;
overflow: hidden;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;

View File

@ -191,9 +191,7 @@ const VersionRow = (props) => {
</>
)}
<Text className="version_text" truncate={true}>
{info.comment}
</Text>
<Text className="version_text">{info.comment}</Text>
</>
</Box>
{showEditPanel && (

View File

@ -1114,6 +1114,7 @@ class FilesStore {
window.DocSpace.location.pathname.includes("accounts/filter"),
fromSettings: window.DocSpace.location.pathname.includes("settings"),
},
replace: !location.search,
});
};
@ -2793,8 +2794,12 @@ class FilesStore {
}
get cbMenuItems() {
const { isDocument, isPresentation, isSpreadsheet, isArchive } =
this.filesSettingsStore;
const {
isDocument,
isPresentation,
isSpreadsheet,
isArchive,
} = this.filesSettingsStore;
let cbMenu = ["all"];
const filesItems = [...this.files, ...this.folders];

View File

@ -984,6 +984,16 @@ export function getSharedUsers(fileId) {
return request(options);
}
export function getProtectUsers(fileId) {
const options = {
method: "get",
url: `/files/file/${fileId}/protectusers`,
};
return request(options);
}
export function sendEditorNotify(fileId, actionLink, emails, message) {
return request({
method: "post",

View File

@ -0,0 +1,27 @@
# FillingRoleSelector
### Usage
```js
import FillingRoleSelector from "@docspace/components/filling-role-selector";
```
```jsx
<FillingRoleSelector
style={{ width: "480px", padding: "16px" }}
></FillingRoleSelector>
```
### Properties
| Props | Type | Required | Values | Default | Description |
| --------------------- | :------------: | :------: | :----: | :-----: | --------------------------------------- |
| `className` | `string` | - | - | - | Accepts class |
| `descriptionEveryone` | `string` | - | - | - | Role description text Everyone |
| `descriptionTooltip` | `string` | - | - | - | Tooltip text |
| `id` | `string` | - | - | - | Accepts id |
| `onAddUser` | `func` | - | - | - | The function of adding a user to a role |
| `onRemoveUser` | `func` | - | - | - | Function to remove a user from a role |
| `roles` | `array` | - | - | - | Array of roles |
| `style` | `obj`, `array` | - | - | - | Accepts css style |
| `users` | `array` | - | - | - | Array of assigned users per role |

View File

@ -0,0 +1,105 @@
import React, { useState } from "react";
import FillingRoleSelector from ".";
export default {
title: "Components/FillingRoleSelector",
component: FillingRoleSelector,
argTypes: {
onAddUser: { action: "onAddUser" },
onRemoveUser: { action: "onRemoveUser" },
},
};
const mockRoles = [
{ id: 3, name: "Director", order: 3, color: "#BB85E7" },
{ id: 2, name: "Accountant", order: 2, color: "#70D3B0" },
{
id: 1,
name: "Employee",
order: 1,
color: "#FBCC86",
everyone: "@Everyone",
},
];
const mockUsers = [
{
id: 1,
displayName: "Makenna Lipshutz",
role: "Accountant",
avatar: "/images/user.avatar.example.react.svg",
hasAvatar: true,
},
{
id: 2,
displayName: "Randy Korsgaard",
role: "Director",
hasAvatar: false,
},
];
//TODO: Fix translations to correct ones when they appear on layouts
const textRoleEveryone =
"The form is available for filling out by all participants of this room.";
const textTooltip =
"Each form filled out by users from the first role will go in turn to the next users listed below.";
const Template = ({ onAddUser, ...args }) => {
const onAddUserHandler = () => {
onAddUser();
};
return (
<FillingRoleSelector
{...args}
style={{ width: "480px", padding: "16px" }}
onAddUser={onAddUserHandler}
/>
);
};
export const Default = Template.bind({});
Default.args = {
roles: mockRoles,
descriptionEveryone: textRoleEveryone,
descriptionTooltip: textTooltip,
};
const TemplateRolesFilledUsers = ({
users,
onAddUser,
onRemoveUser,
...args
}) => {
const [usersAssigned, setUsersAssigned] = useState(mockUsers);
const onRemoveUserHandler = (id) => {
const newUsersAssigned = usersAssigned.filter((item) => item.id !== id);
setUsersAssigned(newUsersAssigned);
onRemoveUser();
};
const onAddUserHandler = () => {
onAddUser();
};
return (
<FillingRoleSelector
{...args}
style={{ width: "480px", padding: "16px" }}
users={usersAssigned}
onRemoveUser={onRemoveUserHandler}
onAddUser={onAddUserHandler}
/>
);
};
export const rolesFilledUsers = TemplateRolesFilledUsers.bind({});
rolesFilledUsers.args = {
roles: mockRoles,
users: mockUsers,
descriptionEveryone: textRoleEveryone,
descriptionTooltip: textTooltip,
};

View File

@ -0,0 +1,117 @@
import React from "react";
import PropTypes from "prop-types";
import { ReactSVG } from "react-svg";
import {
StyledFillingRoleSelector,
StyledRow,
StyledNumber,
StyledAddRoleButton,
StyledEveryoneRoleIcon,
StyledRole,
StyledEveryoneRoleContainer,
StyledTooltip,
StyledAssignedRole,
StyledAvatar,
StyledUserRow,
} from "./styled-filling-role-selector";
import AvatarBaseReactSvgUrl from "PUBLIC_DIR/images/avatar.base.react.svg?url";
import RemoveSvgUrl from "PUBLIC_DIR/images/remove.session.svg?url";
const FillingRoleSelector = (props) => {
const {
roles,
users,
onAddUser,
onRemoveUser,
descriptionEveryone,
descriptionTooltip,
} = props;
//If the roles in the roles array come out of order
const cloneRoles = JSON.parse(JSON.stringify(roles));
const sortedInOrderRoles = cloneRoles.sort((a, b) =>
a.order > b.order ? 1 : -1
);
const everyoneRole = roles.find((item) => item.everyone);
const everyoneRoleNode = (
<>
<StyledRow>
<StyledNumber>{everyoneRole.order}</StyledNumber>
<StyledEveryoneRoleIcon />
<StyledEveryoneRoleContainer>
<div className="title">
<StyledRole>{everyoneRole.name}</StyledRole>
<StyledAssignedRole>{everyoneRole.everyone}</StyledAssignedRole>
</div>
<div className="role-description">{descriptionEveryone}</div>
</StyledEveryoneRoleContainer>
</StyledRow>
<StyledTooltip>{descriptionTooltip}</StyledTooltip>
</>
);
return (
<StyledFillingRoleSelector {...props}>
{everyoneRole && everyoneRoleNode}
{sortedInOrderRoles.map((role, index) => {
if (role.everyone) return;
const roleWithUser = users?.find((user) => user.role === role.name);
return roleWithUser ? (
<StyledUserRow key={index}>
<div className="content">
<StyledNumber>{role.order}</StyledNumber>
<StyledAvatar
src={
roleWithUser.hasAvatar
? roleWithUser.avatar
: AvatarBaseReactSvgUrl
}
/>
<div className="user-with-role">
<StyledRole>{roleWithUser.displayName}</StyledRole>
<StyledAssignedRole>{roleWithUser.role}</StyledAssignedRole>
</div>
</div>
<ReactSVG
src={RemoveSvgUrl}
onClick={() => onRemoveUser(roleWithUser.id)}
/>
</StyledUserRow>
) : (
<StyledRow key={index}>
<StyledNumber>{role.order}</StyledNumber>
<StyledAddRoleButton onClick={onAddUser} color={role.color} />
<StyledRole>{role.name}</StyledRole>
</StyledRow>
);
})}
</StyledFillingRoleSelector>
);
};
FillingRoleSelector.propTypes = {
/** Accepts class */
className: PropTypes.string,
/** Role description text Everyone */
descriptionEveryone: PropTypes.string,
/** Tooltip text */
descriptionTooltip: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** The function of adding a user to a role */
onAddUser: PropTypes.func,
/** Function to remove a user from a role */
onRemoveUser: PropTypes.func,
/** Array of roles */
roles: PropTypes.array,
/** Accepts CSS style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
/** Array of assigned users per role */
users: PropTypes.array,
};
export default FillingRoleSelector;

View File

@ -0,0 +1,126 @@
import styled from "styled-components";
import Base from "../themes/base";
import { AddRoleButton, EveryoneRoleIcon } from "./svg";
const StyledFillingRoleSelector = styled.div`
display: flex;
flex-direction: column;
gap: 4px;
`;
const StyledRow = styled.div`
height: 48px;
display: flex;
align-items: center;
gap: 8px;
`;
const StyledUserRow = styled.div`
height: 48px;
display: flex;
align-items: center;
justify-content: space-between;
.content {
display: flex;
align-items: center;
gap: 8px;
}
.user-with-role {
display: flex;
}
`;
const StyledNumber = styled.div`
font-weight: 600;
font-size: 14px;
line-height: 16px;
color: #a3a9ae;
`;
const StyledAvatar = styled.img`
height: 32px;
width: 32px;
border-radius: 50%;
`;
const StyledAddRoleButton = styled(AddRoleButton)`
width: 32px;
height: 32px;
path {
fill: ${(props) => props.color};
}
rect {
stroke: ${(props) => props.color};
}
`;
const StyledEveryoneRoleIcon = styled(EveryoneRoleIcon)`
width: 32px;
height: 32px;
`;
const StyledRole = styled.div`
font-weight: 600;
font-size: 14px;
line-height: 16px;
`;
const StyledAssignedRole = styled.div`
padding-left: 4px;
color: rgba(170, 170, 170, 1);
::before {
content: "(";
}
::after {
content: ")";
}
`;
const StyledEveryoneRoleContainer = styled.div`
display: flex;
flex-direction: column;
.title {
display: flex;
}
.role-description {
font-weight: 400;
font-size: 10px;
line-height: 14px;
color: #657077;
}
`;
const StyledTooltip = styled.div`
background: #f8f7bf;
border-radius: 6px;
font-weight: 400;
font-size: 12px;
line-height: 16px;
padding: 8px 12px;
height: 48px;
box-sizing: border-box;
margin: 8px 0;
`;
StyledFillingRoleSelector.defaultProps = { theme: Base };
export {
StyledFillingRoleSelector,
StyledRow,
StyledNumber,
StyledAddRoleButton,
StyledEveryoneRoleIcon,
StyledRole,
StyledEveryoneRoleContainer,
StyledTooltip,
StyledAssignedRole,
StyledAvatar,
StyledUserRow,
};

View File

@ -0,0 +1,2 @@
export { default as AddRoleButton } from "PUBLIC_DIR/images/add.role.button.react.svg";
export { default as EveryoneRoleIcon } from "PUBLIC_DIR/images/everyone.role.button.react.svg";

View File

@ -14,6 +14,7 @@ import {
convertFile,
getReferenceData,
getSharedUsers,
getProtectUsers,
sendEditorNotify,
} from "@docspace/common/api/files";
import { EditorWrapper } from "../components/StyledEditor";
@ -503,22 +504,26 @@ function Editor({
}
};
const onSDKRequestUsers = async () => {
const onSDKRequestUsers = async (event) => {
try {
const res = await getSharedUsers(fileInfo.id);
const c = event?.data?.c;
const users = await (c == "protect"
? getProtectUsers(fileInfo.id)
: getSharedUsers(fileInfo.id));
res.map((item) => {
return usersInRoom.push({
if (c !== "protect") {
usersInRoom = users.map((item) => ({
email: item.email,
name: item.name,
});
});
}));
}
docEditor.setUsers({
users: usersInRoom,
c,
users,
});
} catch (e) {
console.error(e);
docEditor.showMessage(e?.message || "Connection is lost");
}
};

View File

@ -3273,6 +3273,58 @@ public class FileStorageService //: IFileStorageService
}
}
public async Task<List<MentionWrapper>> ProtectUsersAsync<T>(T fileId)
{
if (!_authContext.IsAuthenticated || _coreBaseSettings.Personal)
{
return null;
}
var fileDao = GetFileDao<T>();
var file = await fileDao.GetFileAsync(fileId);
ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);
var users = new List<MentionWrapper>();
if (file.RootFolderType == FolderType.BUNCH)
{
//todo: request project team
return new List<MentionWrapper>(users);
}
var acesForObject = await _fileSharing.GetSharedInfoAsync(file);
var usersInfo = new List<UserInfo>();
foreach (var ace in acesForObject)
{
if (ace.Access == FileShare.Restrict || ace.Id.Equals(FileConstant.ShareLinkId))
{
continue;
}
if (ace.SubjectGroup)
{
usersInfo.AddRange(_userManager.GetUsersByGroup(ace.Id));
}
else
{
usersInfo.Add(_userManager.GetUsers(ace.Id));
}
}
users = usersInfo.Distinct()
.Where(user => !user.Id.Equals(_authContext.CurrentAccount.ID)
&& !user.Id.Equals(Constants.LostUser.Id))
.Select(user => new MentionWrapper(user, _displayUserSettingsHelper))
.ToList();
users = users
.OrderBy(user => user.User, UserInfoComparer.Default)
.ToList();
return new List<MentionWrapper>(users);
}
public string GetHelpCenter()
{
return string.Empty; //TODO: Studio.UserControls.Common.HelpCenter.HelpCenter.RenderControlToString();

View File

@ -255,6 +255,12 @@ public abstract class EditorController<T> : ApiControllerBase
return _fileStorageService.GetReferenceDataAsync(inDto.FileKey, inDto.InstanceId, inDto.SourceFileId, inDto.Path);
}
[HttpGet("file/{fileId}/protectusers")]
public async Task<List<MentionWrapper>> ProtectUsers(T fileId)
{
return await _fileStorageService.ProtectUsersAsync(fileId);
}
}
public class EditorController : ApiControllerBase

View File

@ -0,0 +1,4 @@
<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M18 16V10H16V16H10V18H16V24H18V18H24V16H18Z" fill="#FBCC86"/>
<rect x="1" y="1" width="32" height="32" rx="16" stroke="#FBCC86" stroke-width="2" stroke-linecap="round" stroke-dasharray="3 4"/>
</svg>

After

Width:  |  Height:  |  Size: 345 B

View File

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.0136 10.0186C12.9822 8.33891 14.3539 7 16.0011 7C17.6483 7 19.0201 8.33904 18.9885 10.0189C18.9622 11.4109 18.8797 12.699 18.5276 13.6523C18.344 14.1496 18.0618 14.6296 17.6099 14.9817C17.1449 15.344 16.5912 15.5 16.0001 15.5C15.4089 15.5 14.8552 15.3439 14.3902 14.9814C13.9384 14.6292 13.6565 14.1489 13.4731 13.6516C13.1215 12.6983 13.0395 11.4102 13.0136 10.0186ZM16.0011 9C15.4401 9 15.0034 9.45322 15.0132 9.9813C15.0398 11.4049 15.131 12.3669 15.3496 12.9597C15.4513 13.2355 15.5537 13.3525 15.6199 13.4041C15.673 13.4455 15.7711 13.5 16.0001 13.5C16.2291 13.5 16.3275 13.4455 16.3808 13.404C16.4472 13.3522 16.5497 13.2352 16.6515 12.9595C16.8703 12.3668 16.962 11.4049 16.9888 9.98123C16.9988 9.45328 16.5621 9 16.0011 9ZM13.0334 18.2724L13.0319 18.2741C12.7919 18.5425 12.5514 18.9867 12.335 19.5975C12.1233 20.1954 11.9573 20.8874 11.8311 21.5936C11.5778 23.0098 11.5001 24.3913 11.5001 25H9.50007C9.50007 24.2823 9.58673 22.7825 9.86228 21.2416C10.0004 20.4692 10.1899 19.6636 10.4498 18.9299C10.705 18.2091 11.0522 17.4875 11.541 16.9409C12.1267 16.286 12.9016 16.1561 13.554 16.2391C14.1759 16.3182 14.7633 16.5918 15.2147 16.8626C15.6981 17.1526 16.302 17.1526 16.7854 16.8626C17.2368 16.5918 17.8242 16.3182 18.4462 16.2391C19.0986 16.1561 19.8735 16.286 20.4592 16.9409C20.9479 17.4875 21.2951 18.2091 21.5504 18.9299C21.8102 19.6636 21.9998 20.4692 22.1379 21.2416C22.4134 22.7825 22.5001 24.2823 22.5001 25H20.5001C20.5001 24.3913 20.4223 23.0098 20.1691 21.5936C20.0428 20.8874 19.8768 20.1954 19.6651 19.5975C19.4488 18.9867 19.2083 18.5425 18.9683 18.2741L18.9668 18.2724C18.9419 18.2444 18.9 18.1975 18.6986 18.2231C18.4626 18.2531 18.1483 18.3772 17.8144 18.5776C16.6977 19.2476 15.3025 19.2476 14.1857 18.5776C13.8518 18.3772 13.5376 18.2531 13.3015 18.2231C13.1001 18.1975 13.0583 18.2444 13.0334 18.2724ZM12.0137 10.0372C12.0121 9.95035 12.0133 9.86416 12.0172 9.77875C11.7156 9.60078 11.3654 9.5 10.9997 9.5C9.91388 9.5 8.96835 10.3866 9.01547 11.5405C9.03897 12.1161 9.09937 12.8451 9.28148 13.4556C9.37171 13.758 9.51449 14.1118 9.76072 14.4072C10.0292 14.7292 10.443 15 10.9879 15C11.5318 15 11.945 14.7303 12.2139 14.4112C12.3374 14.2646 12.4355 14.1034 12.5144 13.9411C12.1143 12.816 12.039 11.3901 12.0137 10.0372ZM19.9883 10.0378C19.9626 11.4005 19.8859 12.8368 19.4779 13.9655C19.553 14.118 19.6455 14.269 19.7607 14.4072C20.0292 14.7292 20.4429 15 20.9879 15C21.5318 15 21.945 14.7303 22.2139 14.4112C22.4613 14.1177 22.6068 13.7654 22.6996 13.4629C22.8868 12.8524 22.9528 12.1234 22.9798 11.546C23.0339 10.3873 22.0848 9.5 20.9997 9.5C20.6348 9.5 20.2857 9.60015 19.9848 9.77695C19.9887 9.86313 19.9899 9.95011 19.9883 10.0378ZM21.309 16.4945C21.7092 17.0127 22.0303 17.6139 22.2892 18.2406C22.4164 18.1734 22.5396 18.0956 22.6574 18.0072C22.7535 17.9352 22.8494 17.88 22.9354 17.8434C22.9901 17.8201 23.0341 17.807 23.0667 17.8C23.4283 18.4071 23.7693 19.4621 23.9206 20.5002H22.9803C23.03 20.7241 23.0741 20.9421 23.1132 21.1513C23.1996 21.6124 23.2686 22.0675 23.323 22.5002H24.0001C25.071 22.5002 26.0819 21.6015 25.9221 20.3742C25.7549 19.09 25.3209 17.6292 24.7275 16.6825C24.3028 16.0049 23.6233 15.7543 22.9789 15.7975C22.3966 15.8366 21.8609 16.1046 21.4574 16.4072C21.4106 16.4423 21.3608 16.4714 21.309 16.4945ZM8.88691 21.1513C8.92608 20.9421 8.9701 20.7241 9.01984 20.5002H8.07973C8.23063 19.4645 8.56974 18.4105 8.92901 17.8015C8.96101 17.8084 9.00405 17.8211 9.05745 17.8436C9.14309 17.8798 9.2388 17.9344 9.33493 18.006C9.45509 18.0956 9.58068 18.1743 9.71037 18.242C9.9693 17.6149 10.2905 17.0133 10.6909 16.4949C10.6348 16.471 10.5809 16.4403 10.5304 16.4027C10.126 16.1011 9.58924 15.8348 9.00651 15.7983C8.36127 15.758 7.68409 16.013 7.26316 16.6915C6.67665 17.6368 6.24518 19.0924 6.07827 20.3739C5.91841 21.6011 6.92908 22.5002 8.00039 22.5002H8.67714C8.73156 22.0675 8.80058 21.6124 8.88691 21.1513Z" fill="#FBCC86"/>
<rect x="1" y="1" width="30" height="30" rx="15" stroke="#FBCC86" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -78,6 +78,8 @@
"Culture_zh-CN": "中文(简体,中国)",
"Date": "Date",
"Delete": "Delete",
"DescriptionOfTheEveryoneRole": "The form is available for filling out by all participants of this room.",
"DescriptionOfTheRoleQueue": "Each form filled out by users from the first role will go in turn to the next users listed below.",
"Disconnect": "Disconnect",
"DocSpaceAdmin": "DocSpace admin",
"DocSpaceOwner": "DocSpace owner",