Merge pull request #1313 from ONLYOFFICE/feature/new-quota-bars

Feature/new quota bars
This commit is contained in:
Alexey Safronov 2023-03-22 15:42:46 +04:00 committed by GitHub
commit 993a7e66c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 299 additions and 145 deletions

View File

@ -1,10 +1,14 @@
{
"ClickHere": "click here",
"ClickHere": "Click here",
"ConfirmEmailDescription": "Use the link provided in the activation email. Haven't received an email with the activation link?",
"ConfirmEmailHeader": "Please activate your email to get access to the DocSpace features.",
"RequestActivation": "Request activation once again",
"RoomQuotaDescription": "You can archive the unnecessary rooms or <1>{{clickHere}}</1> to find a more suitable pricing plan for your DocSpace.",
"RoomQuotaHeader": "Rooms is about to be exceeded: {{currentValue}} / {{maxValue}}",
"StorageQuotaDescription": "You can remove the unnecessary files or <1>{{clickHere}}</1> to find a more suitable pricing plan for your DocSpace.",
"StorageQuotaHeader": "Storage space amount is about to be exceeded: {{currentValue}} / {{maxValue}}"
"StorageQuotaHeader": "Storage space amount is about to be exceeded: {{currentValue}} / {{maxValue}}",
"UserQuotaDescription": "<1>{{clickHere}}</1> to find a better pricing plan for your portal.",
"UserQuotaHeader": "The number of admins/power users is about to be exceed: {{currentValue}} / {{maxValue}}",
"StorageAndUserHeader": "Storage and admins/power users limits are about to be exceeded.",
"StorageAndRoomHeader": "Storage and rooms limits are about to be exceeded."
}

View File

@ -41,7 +41,7 @@
"OwnerChange": "Change owner",
"Presentations": "Presentations",
"Remove": "Remove",
"RoleCollaboratorDescription": "Collaborators can create and edit files in the room, but can't create rooms, manage users, or access settings.",
"RolePowerUserDescription": "Power users can create and edit files in the room, but can't create rooms, manage users, or access settings.",
"RoleCommentator": "Commentator",
"RoleCommentatorDescription": "Operations with existing files: viewing, commenting.",
"RoleDocSpaceAdminDescription": "DocSpace admins can access DocSpace settings, manage and archive rooms, invite new users and assign roles below their level. All admins have access to the Personal section.",

View File

@ -1,10 +1,14 @@
{
"ClickHere": "кликните сюда",
"ClickHere": "Кликните сюда",
"ConfirmEmailDescription": "Используйте ссылку, указанную в письме активации. Не получили письмо со ссылкой для активации?",
"ConfirmEmailHeader": "Пожалуйста, активируйте свою электронную почту, чтобы получить доступ ко всем функциям DocSpace.",
"RequestActivation": "Запросить активацию еще раз",
"RoomQuotaDescription": "Вы можете заархивировать ненужные комнаты или <1>{{clickHere}}</1> , чтобы найти лучший тарифный план для DocSpace.",
"RoomQuotaHeader": "Количество комнат скоро будет превышено: {{currentValue}} / {{maxValue}}",
"StorageQuotaDescription": "Вы можете удалить ненужные файлы или <1>{{clickHere}}</1> , чтобы найти лучший тарифный план для DocSpace.",
"StorageQuotaHeader": "Объем дискового пространства скоро будет превышен: {{currentValue}} / {{maxValue}}"
"StorageQuotaHeader": "Объем дискового пространства скоро будет превышен: {{currentValue}} / {{maxValue}}",
"UserQuotaDescription": "<1>{{clickHere}}</1> чтобы найти лучший тарифный план для DocSpace.",
"UserQuotaHeader": "Количество администраторов/опытных пользователей скоро будет превышено: {{currentValue}} / {{maxValue}}",
"StorageAndUserHeader": "Объем дискового пространства и количество администраторов/опытных пользователей скоро будет превышено ",
"StorageAndRoomHeader": "Объем дискового пространства и количество комнат скоро будет превышено"
}

View File

@ -41,7 +41,7 @@
"OwnerChange": "Сменить владельца",
"Presentations": "Презентации",
"Remove": "Удалить",
"RoleCollaboratorDescription": "Сотрудники могут создавать и редактировать файлы в комнате, но не могут создавать комнаты, управлять пользователями или получать доступ к настройкам.",
"RolePowerUserDescription": "Опытные пользователи могут создавать и редактировать файлы в комнате, но не могут создавать комнаты, управлять пользователями или получать доступ к настройкам.",
"RoleCommentator": "Комментатор",
"RoleCommentatorDescription": "Операции с существующими файлами: просмотр, комментирование.",
"RoleDocSpaceAdminDescription": "Администраторы DocSpace могут получить доступ к настройкам DocSpace, управлять и архивировать комнаты, приглашать новых пользователей и назначать роли ниже своего уровня. Все администраторы имеют доступ к Личному разделу.",

View File

@ -322,7 +322,7 @@ const ArticleMainButtonContent = (props) => {
id: "invite_room-collaborator",
className: "main-button_drop-down",
icon: PersonReactSvgUrl,
label: t("Common:Collaborator"),
label: t("Common:PowerUser"),
onClick: onInvite,
action: EmployeeType.Collaborator,
key: "collaborator",

View File

@ -102,7 +102,7 @@ const ChangeUserTypeEvent = ({
case "manager":
return t("Common:RoomAdmin");
case "collaborator":
return t("Common:Collaborator");
return t("Common:PowerUser");
case "user":
default:
return t("Common:User");

View File

@ -10,14 +10,11 @@ import { getConvertedSize } from "@docspace/common/utils";
import { getBannerAttribute } from "@docspace/components/utils/banner";
import SnackBar from "@docspace/components/snackbar";
import { QuotaBarTypes } from "SRC_DIR/helpers/constants";
import QuotasBar from "./QuotasBar";
import ConfirmEmailBar from "./ConfirmEmailBar";
const CONFIRM_EMAIL = "confirm-email";
const ROOM_QUOTA = "room-quota";
const STORAGE_QUOTA = "storage-quota";
const Bar = (props) => {
const {
t,
@ -37,18 +34,24 @@ const Bar = (props) => {
maxTotalSizeByQuota,
usedTotalStorageSizeCount,
maxCountManagersByQuota,
addedManagersCount,
showRoomQuotaBar,
showStorageQuotaBar,
showUserQuotaBar,
currentColorScheme,
setMainBarVisible,
mainBarVisible,
} = props;
const [barVisible, setBarVisible] = useState({
roomQuota: false,
storageQuota: false,
userQuota: false,
storageAndUserQuota: false,
storageAndRoomQuota: false,
confirmEmail: false,
});
@ -75,21 +78,31 @@ const Bar = (props) => {
}
if (closed) {
if (!closed.includes(ROOM_QUOTA) && isAdmin) {
setBarVisible((value) => ({ ...value, roomQuota: true }));
if (isAdmin) {
setBarVisible((value) => ({
...value,
roomQuota: !closed.includes(QuotaBarTypes.RoomQuota),
storageQuota: !closed.includes(QuotaBarTypes.StorageQuota),
userQuota: !closed.includes(QuotaBarTypes.UserQuota),
storageAndRoomQuota: !closed.includes(
QuotaBarTypes.UserAndStorageQuota
),
storageAndUserQuota: !closed.includes(
QuotaBarTypes.RoomAndStorageQuota
),
}));
}
if (!closed.includes(STORAGE_QUOTA) && isAdmin) {
setBarVisible((value) => ({ ...value, storageQuota: true }));
}
if (!closed.includes(CONFIRM_EMAIL)) {
if (!closed.includes(QuotaBarTypes.ConfirmEmail)) {
setBarVisible((value) => ({ ...value, confirmEmail: true }));
}
} else {
setBarVisible({
roomQuota: isAdmin,
storageQuota: isAdmin,
userQuota: isAdmin,
storageAndUserQuota: isAdmin,
storageAndRoomQuota: isAdmin,
confirmEmail: true,
});
}
@ -124,7 +137,9 @@ const Bar = (props) => {
const closeItems = JSON.parse(localStorage.getItem("barClose")) || [];
const closed =
closeItems.length > 0 ? [...closeItems, CONFIRM_EMAIL] : [CONFIRM_EMAIL];
closeItems.length > 0
? [...closeItems, QuotaBarTypes.ConfirmEmail]
: [QuotaBarTypes.ConfirmEmail];
localStorage.setItem("barClose", JSON.stringify(closed));
@ -138,8 +153,7 @@ const Bar = (props) => {
onCloseQuota(isRoomQuota);
};
const onCloseQuota = (isRoomQuota) => {
const currentBar = isRoomQuota ? ROOM_QUOTA : STORAGE_QUOTA;
const onCloseQuota = (currentBar) => {
const closeItems = JSON.parse(localStorage.getItem("barClose")) || [];
const closed =
@ -147,11 +161,24 @@ const Bar = (props) => {
localStorage.setItem("barClose", JSON.stringify(closed));
setBarVisible((value) =>
isRoomQuota
? { ...value, roomQuota: false }
: { ...value, storageQuota: false }
);
switch (currentBar) {
case QuotaBarTypes.RoomQuota:
setBarVisible((value) => ({ ...value, roomQuota: false }));
break;
case QuotaBarTypes.StorageQuota:
setBarVisible((value) => ({ ...value, storageQuota: false }));
break;
case QuotaBarTypes.UserQuota:
setBarVisible((value) => ({ ...value, userQuota: false }));
break;
case QuotaBarTypes.UserAndStorageQuota:
setBarVisible((value) => ({ ...value, storageAndUserQuota: false }));
break;
case QuotaBarTypes.RoomAndStorageQuota:
setBarVisible((value) => ({ ...value, storageAndRoomQuota: false }));
break;
}
setMaintenanceExist(false);
};
@ -168,21 +195,61 @@ const Bar = (props) => {
setMaintenanceExist(true);
};
const isRoomQuota = showRoomQuotaBar && barVisible.roomQuota;
const isStorageQuota = showStorageQuotaBar && barVisible.storageQuota;
const quotasValue = {
maxValue: isRoomQuota
? maxCountRoomsByQuota
: getConvertedSize(t, maxTotalSizeByQuota),
currentValue: isRoomQuota
? usedRoomsCount
: getConvertedSize(t, usedTotalStorageSizeCount),
const getCurrentBar = () => {
if (
showRoomQuotaBar &&
showStorageQuotaBar &&
barVisible.storageAndRoomQuota
) {
return {
type: QuotaBarTypes.RoomAndStorageQuota,
maxValue: null,
currentValue: null,
};
}
if (
showUserQuotaBar &&
showStorageQuotaBar &&
barVisible.storageAndUserQuota
) {
return {
type: QuotaBarTypes.UserAndStorageQuota,
maxValue: null,
currentValue: null,
};
}
if (showRoomQuotaBar && barVisible.roomQuota) {
return {
type: QuotaBarTypes.RoomQuota,
maxValue: maxCountRoomsByQuota,
currentValue: usedRoomsCount,
};
}
if (showStorageQuotaBar && barVisible.storageQuota) {
return {
type: QuotaBarTypes.StorageQuota,
maxValue: getConvertedSize(t, maxTotalSizeByQuota),
currentValue: getConvertedSize(t, usedTotalStorageSizeCount),
};
}
if (showUserQuotaBar && barVisible.userQuota) {
return {
type: QuotaBarTypes.UserQuota,
maxValue: maxCountManagersByQuota,
currentValue: addedManagersCount,
};
}
return null;
};
const currentBar = getCurrentBar();
const showQuotasBar = !!currentBar && tReady;
React.useEffect(() => {
const newValue =
((isRoomQuota || isStorageQuota) && tReady) ||
showQuotasBar ||
(withActivationBar && barVisible.confirmEmail && tReady) ||
(htmlLink && !firstLoad && tReady);
@ -192,21 +259,18 @@ const Bar = (props) => {
setMainBarVisible(false);
};
}, [
isRoomQuota,
isStorageQuota,
tReady,
showQuotasBar,
withActivationBar,
barVisible.confirmEmail,
!!htmlLink,
tReady,
htmlLink,
firstLoad,
mainBarVisible,
]);
return (isRoomQuota || isStorageQuota) && tReady ? (
return showQuotasBar ? (
<QuotasBar
currentColorScheme={currentColorScheme}
isRoomQuota={isRoomQuota}
{...quotasValue}
{...currentBar}
onClick={onClickQuota}
onClose={onCloseQuota}
onLoad={onLoad}
@ -240,15 +304,15 @@ export default inject(({ auth, profileActionsStore }) => {
maxTotalSizeByQuota,
usedTotalStorageSizeCount,
maxCountManagersByQuota,
addedManagersCount,
showRoomQuotaBar,
showStorageQuotaBar,
showUserQuotaBar,
} = auth.currentQuotaStore;
const {
currentColorScheme,
setMainBarVisible,
mainBarVisible,
} = auth.settingsStore;
const { currentColorScheme, setMainBarVisible } = auth.settingsStore;
return {
isAdmin: user?.isAdmin,
@ -263,11 +327,14 @@ export default inject(({ auth, profileActionsStore }) => {
maxTotalSizeByQuota,
usedTotalStorageSizeCount,
maxCountManagersByQuota,
addedManagersCount,
showRoomQuotaBar,
showStorageQuotaBar,
showUserQuotaBar,
currentColorScheme,
setMainBarVisible,
mainBarVisible,
};
})(withTranslation(["Profile", "Common"])(withRouter(observer(Bar))));

View File

@ -6,14 +6,6 @@ import SnackBar from "@docspace/components/snackbar";
import Link from "@docspace/components/link";
const StyledLink = styled(Link)`
font-size: 12px;
line-height: 16px;
font-weight: 400;
color: ${(props) => props.currentColorScheme.main.accent};
`;
const ConfirmEmailBar = ({
t,
tReady,
@ -29,12 +21,14 @@ const ConfirmEmailBar = ({
text={
<>
{t("ConfirmEmailDescription")}{" "}
<StyledLink
currentColorScheme={currentColorScheme}
<Link
fontSize="12px"
fontWeight="400"
color={currentColorScheme?.main?.accent}
onClick={onClick}
>
{t("RequestActivation")}
</StyledLink>
</Link>
</>
}
isCampaigns={false}

View File

@ -5,19 +5,12 @@ import styled, { css } from "styled-components";
import SnackBar from "@docspace/components/snackbar";
import Link from "@docspace/components/link";
const StyledLink = styled(Link)`
font-size: 12px;
line-height: 16px;
font-weight: 400;
color: ${(props) => props.currentColorScheme.main.accent};
`;
import { QuotaBarTypes } from "SRC_DIR/helpers/constants";
const QuotasBar = ({
t,
tReady,
isRoomQuota,
type,
currentValue,
maxValue,
onClick,
@ -26,65 +19,122 @@ const QuotasBar = ({
currentColorScheme,
}) => {
const onClickAction = () => {
onClick && onClick(isRoomQuota);
onClick && onClick(type);
};
const onCloseAction = () => {
onClose && onClose(isRoomQuota);
onClose && onClose(type);
};
const roomQuota = {
const getQuotaInfo = () => {
switch (type) {
case QuotaBarTypes.RoomQuota:
return {
header: t("RoomQuotaHeader", { currentValue, maxValue }),
description: (
<Trans i18nKey="RoomQuotaDescription" t={t}>
You can archived the unnecessary rooms or
<StyledLink
currentColorScheme={currentColorScheme}
<Link
fontSize="12px"
fontWeight="400"
color={currentColorScheme?.main?.accent}
onClick={onClickAction}
>
{{ clickHere: t("ClickHere") }}
</StyledLink>{" "}
{{ clickHere: t("ClickHere").toLowerCase() }}
</Link>{" "}
to find a better pricing plan for your portal.
</Trans>
),
};
const storageQuota = {
case QuotaBarTypes.StorageQuota:
return {
header: t("StorageQuotaHeader", { currentValue, maxValue }),
description: (
<Trans i18nKey="StorageQuotaDescription" t={t}>
You can remove the unnecessary files or
<StyledLink
currentColorScheme={currentColorScheme}
<Link
fontSize="12px"
fontWeight="400"
color={currentColorScheme?.main?.accent}
onClick={onClickAction}
>
{{ clickHere: t("ClickHere").toLowerCase() }}
</Link>{" "}
to find a better pricing plan for your portal.
</Trans>
),
};
case QuotaBarTypes.UserQuota:
return {
header: t("UserQuotaHeader", { currentValue, maxValue }),
description: (
<Trans i18nKey="UserQuotaDescription" t={t}>
{""}
<Link
fontSize="12px"
fontWeight="400"
color={currentColorScheme?.main?.accent}
onClick={onClickAction}
>
{{ clickHere: t("ClickHere") }}
</StyledLink>{" "}
</Link>{" "}
to find a better pricing plan for your portal.
</Trans>
),
};
case QuotaBarTypes.UserAndStorageQuota:
return {
header: t("StorageAndUserHeader", { currentValue, maxValue }),
description: (
<Trans i18nKey="UserQuotaDescription" t={t}>
{""}
<Link
fontSize="12px"
fontWeight="400"
color={currentColorScheme?.main?.accent}
onClick={onClickAction}
>
{{ clickHere: t("ClickHere") }}
</Link>{" "}
to find a better pricing plan for your portal.
</Trans>
),
};
case QuotaBarTypes.RoomAndStorageQuota:
return {
header: t("StorageAndRoomHeader", { currentValue, maxValue }),
description: (
<Trans i18nKey="UserQuotaDescription" t={t}>
{""}
<Link
fontSize="12px"
fontWeight="400"
color={currentColorScheme?.main?.accent}
onClick={onClickAction}
>
{{ clickHere: t("ClickHere") }}
</Link>{" "}
to find a better pricing plan for your portal.
</Trans>
),
};
return tReady ? (
isRoomQuota ? (
default:
return null;
}
};
const quotaInfo = getQuotaInfo();
return tReady && quotaInfo ? (
<SnackBar
headerText={roomQuota.header}
text={roomQuota.description}
headerText={quotaInfo.header}
text={quotaInfo.description}
isCampaigns={false}
opacity={1}
onLoad={onLoad}
clickAction={onCloseAction}
/>
) : (
<SnackBar
headerText={storageQuota.header}
text={storageQuota.description}
isCampaigns={false}
opacity={1}
onLoad={onLoad}
clickAction={onCloseAction}
/>
)
) : (
<></>
);

View File

@ -33,8 +33,8 @@ export const getAccessOptions = (
},
collaborator: {
key: "collaborator",
label: t("Common:Collaborator"),
description: t("Translations:RoleCollaboratorDescription"),
label: t("Common:PowerUser"),
description: t("Translations:RolePowerUserDescription"),
quota: t("Common:Paid"),
color: "#EDC409",
access:

View File

@ -66,6 +66,19 @@ export const TableVersions = Object.freeze({
Trash: "4",
});
/**
* Enum for quotas bar
* @readonly
*/
export const QuotaBarTypes = Object.freeze({
ConfirmEmail: "confirm-email",
RoomQuota: "room-quota",
StorageQuota: "storage-quota",
UserQuota: "user-quota",
UserAndStorageQuota: "user-storage-quota",
RoomAndStorageQuota: "room-storage-quota",
});
export const BINDING_POST = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
export const BINDING_REDIRECT =
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect";

View File

@ -61,7 +61,7 @@ const UserContent = ({
: role === "admin"
? t("Common:DocSpaceAdmin")
: isCollaborator
? t("Common:Collaborator")
? t("Common:PowerUser")
: isVisitor
? t("Common:User")
: t("Common:RoomAdmin");

View File

@ -171,8 +171,8 @@ const PeopleTableRow = (props) => {
};
const collaboratorOption = {
key: "collaborator",
title: t("Common:Collaborator"),
label: t("Common:Collaborator"),
title: t("Common:PowerUser"),
label: t("Common:PowerUser"),
action: "collaborator",
};
const userOption = {
@ -237,7 +237,7 @@ const PeopleTableRow = (props) => {
case "manager":
return t("Common:RoomAdmin");
case "collaborator":
return t("Common:Collaborator");
return t("Common:PowerUser");
case "user":
return t("Common:User");
}

View File

@ -183,7 +183,7 @@ const SectionFilterContent = ({
id: "filter_type-room-admin",
key: EmployeeType.Collaborator,
group: "filter-type",
label: t("Common:Collaborator"),
label: t("Common:PowerUser"),
},
{
id: "filter_type-user",
@ -326,7 +326,7 @@ const SectionFilterContent = ({
label = t("Common:RoomAdmin");
break;
case EmployeeType.Collaborator:
label = t("Common:Collaborator");
label = t("Common:PowerUser");
break;
case EmployeeType.Guest:
label = t("Common:User");

View File

@ -268,7 +268,7 @@ const SectionHeaderContent = (props) => {
id: "accounts-add_collaborator",
className: "main-button_drop-down",
icon: PersonReactSvgUrl,
label: t("Common:Collaborator"),
label: t("Common:PowerUser"),
onClick: onInvite,
"data-type": EmployeeType.Collaborator,
key: "collaborator",

View File

@ -23,7 +23,7 @@ class MembersHelper {
},
collaborator: {
key: "collaborator",
label: this.t("Common:Collaborator"),
label: this.t("Common:PowerUser"),
access: ShareAccessRights.Collaborator,
},
viewer: {

View File

@ -51,7 +51,7 @@ const Accounts = ({
case "manager":
return t("Common:RoomAdmin");
case "collaborator":
return t("Common:Collaborator");
return t("Common:PowerUser");
case "user":
return t("Common:User");
}
@ -77,8 +77,8 @@ const Accounts = ({
const collaboratorOption = {
id: "info-account-type_collaborator",
key: "collaborator",
title: t("Common:Collaborator"),
label: t("Common:Collaborator"),
title: t("Common:PowerUser"),
label: t("Common:PowerUser"),
action: "collaborator",
};
const userOption = {

View File

@ -137,6 +137,7 @@ const User = ({
userName={isExpect ? "" : user.displayName}
withTooltip={withTooltip}
tooltipContent={tooltipContent}
hideRoleIcon={!withTooltip}
/>
<div className="name">

View File

@ -10,6 +10,10 @@ const FILE_SIZE = "file_size";
const ROOM = "room";
const USERS = "users";
const USERS_IN_ROOM = "usersInRoom";
const COUNT_FOR_SHOWING_BAR = 2;
const PERCENTAGE_FOR_SHOWING_BAR = 90;
class QuotasStore {
currentPortalQuota = {};
currentPortalQuotaFeatures = [];
@ -164,14 +168,26 @@ class QuotasStore {
get showRoomQuotaBar() {
return (
(this.usedRoomsCount / this.maxCountRoomsByQuota) * 100 >= 90 ||
this.maxCountRoomsByQuota - this.usedRoomsCount === 1
this.maxCountRoomsByQuota - this.usedRoomsCount <=
COUNT_FOR_SHOWING_BAR &&
this.maxCountRoomsByQuota > 0 &&
this.maxCountRoomsByQuota >= this.usedRoomsCount
);
}
get showStorageQuotaBar() {
return (
(this.usedTotalStorageSizeCount / this.maxTotalSizeByQuota) * 100 >= 90
(this.usedTotalStorageSizeCount / this.maxTotalSizeByQuota) * 100 >=
PERCENTAGE_FOR_SHOWING_BAR
);
}
get showUserQuotaBar() {
return (
this.addedManagersCount > 1 &&
this.maxCountManagersByQuota - this.addedManagersCount <=
COUNT_FOR_SHOWING_BAR &&
this.maxCountManagersByQuota >= this.addedManagersCount
);
}

View File

@ -93,6 +93,8 @@ const Avatar = (props) => {
const roleIcon = getRoleIcon(role);
const uniqueTooltipId = withTooltip ? `roleTooltip_${Math.random()}` : "";
return (
<StyledAvatar {...props}>
<AvatarWrapper source={source} userName={userName}>
@ -113,14 +115,14 @@ const Avatar = (props) => {
<>
<RoleWrapper
size={size}
data-for="roleTooltip"
data-for={uniqueTooltipId}
data-tip={tooltipContent}
>
{roleIcon}
</RoleWrapper>
{withTooltip && (
<Tooltip
id="roleTooltip"
id={uniqueTooltipId}
getContent={(dataTip) => (
<Text fontSize="12px">{dataTip}</Text>
)}

View File

@ -32,10 +32,12 @@ Link.propTypes = {
className: PropTypes.string,
/** Color of link */
color: PropTypes.string,
/** ont size of link */
/** Font size of link */
fontSize: PropTypes.string,
/** Font weight of link */
fontWeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** Line height of link */
lineHeight: PropTypes.string,
/** Used as HTML `href` property */
href: PropTypes.string,
/** Accepts id */

View File

@ -32,7 +32,8 @@ const StyledText = styled(PureText)`
cursor: ${(props) => props.theme.link.cursor};
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
opacity: ${(props) => props.isSemitransparent && props.theme.link.opacity};
line-height: ${(props) => props.theme.link.lineHeight};
line-height: ${(props) =>
props.lineHeight ? props.lineHeight : props.theme.link.lineHeight};
${colorCss};

View File

@ -29,7 +29,6 @@
"ClearAll": "Clear all",
"ClearFilter": "Clear filter",
"CloseButton": "Close",
"Collaborator": "Collaborator",
"Color": "Color",
"ComingSoon": "Coming soon",
"Comments": "Comments",
@ -173,6 +172,7 @@
"Petabyte": "PB",
"Phone": "Phone",
"Plugin": "Plugin",
"PowerUser": "Power user",
"PreparationPortalTitle": "Portal restoring is underway",
"Preview": "Preview",
"Previous": "Previous",

View File

@ -29,7 +29,6 @@
"ClearAll": "Очистить все",
"ClearFilter": "Очистить фильтр",
"CloseButton": "Закрыть",
"Collaborator": "Сотрудник",
"Color": "Цвет",
"ComingSoon": "Скоро появится",
"Comments": "Комментарии",
@ -173,6 +172,7 @@
"Petabyte": "Пб",
"Phone": "Телефон",
"Plugin": "Плагин",
"PowerUser": "Опытный пользователь",
"PreparationPortalTitle": "Выполняется восстановление портала",
"Preview": "Просмотр",
"Previous": "Предыдущая",