Merge branch 'hotfix/v2.6.1' of github.com:ONLYOFFICE/DocSpace-client into hotfix/v2.6.1

This commit is contained in:
Akmal Isomadinov 2024-08-19 19:03:29 +05:00
commit e0be272856
19 changed files with 327 additions and 47 deletions

View File

@ -95638,6 +95638,138 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>LdapQuotaInfo</name>
<description/>
<comment/>
<default_text/>
<translations>
<translation>
<language>ar-SA</language>
<approved>false</approved>
</translation>
<translation>
<language>az-Latn-AZ</language>
<approved>false</approved>
</translation>
<translation>
<language>bg-BG</language>
<approved>false</approved>
</translation>
<translation>
<language>cs-CZ</language>
<approved>false</approved>
</translation>
<translation>
<language>de-DE</language>
<approved>false</approved>
</translation>
<translation>
<language>el-GR</language>
<approved>false</approved>
</translation>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-ES</language>
<approved>false</approved>
</translation>
<translation>
<language>fi-FI</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-FR</language>
<approved>false</approved>
</translation>
<translation>
<language>hy-AM</language>
<approved>false</approved>
</translation>
<translation>
<language>it-IT</language>
<approved>false</approved>
</translation>
<translation>
<language>ja-JP</language>
<approved>false</approved>
</translation>
<translation>
<language>ko-KR</language>
<approved>false</approved>
</translation>
<translation>
<language>lo-LA</language>
<approved>false</approved>
</translation>
<translation>
<language>lv-LV</language>
<approved>false</approved>
</translation>
<translation>
<language>nl-NL</language>
<approved>false</approved>
</translation>
<translation>
<language>pl-PL</language>
<approved>false</approved>
</translation>
<translation>
<language>pt-BR</language>
<approved>false</approved>
</translation>
<translation>
<language>pt-PT</language>
<approved>false</approved>
</translation>
<translation>
<language>ro-RO</language>
<approved>false</approved>
</translation>
<translation>
<language>ru-RU</language>
<approved>false</approved>
</translation>
<translation>
<language>si-SI</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>sl-SI</language>
<approved>false</approved>
</translation>
<translation>
<language>sr-Cyrl-RS</language>
<approved>false</approved>
</translation>
<translation>
<language>sr-Latn-RS</language>
<approved>false</approved>
</translation>
<translation>
<language>tr-TR</language>
<approved>false</approved>
</translation>
<translation>
<language>uk-UA</language>
<approved>false</approved>
</translation>
<translation>
<language>vi-VN</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CN</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>LdapSecondName</name>
<description/>

View File

@ -36,6 +36,7 @@
"LdapPortNumber": "Port Number",
"LdapPortNumberTooltip": "Enter the port number for your LDAP server/Active Directory.",
"LdapQuota": "User quota",
"LdapQuotaInfo": "To be able to use this attribute, enable user quota in the <0>Storage management settings</0>",
"LdapSecondName": "Second name",
"LdapSendWelcomeLetter": "Send welcome letter",
"LdapSendWelcomeLetterTooltip": "If checked all new users will receive welcome letter. Available only when Mail Attribute is mapped to LDAP.",

View File

@ -7,7 +7,7 @@
"PersonalQuotaHeader": "Your personal storage quota exceeded",
"PersonalQuotaHeaderForAdmins": "Storage quota per user exceeded",
"PersonalUserQuotaAdminsDescription": "To upload and create new files and folders, please free up disk space, or manage quota per user in the <1>Storage management settings.</1>",
"PersonalUserQuotaDescription": "To upload and create new files and folders, please free up disk space, or contact the administrator to increase the storage quota.",
"PersonalUserQuotaDescription": "To upload and create new files and folders, please free up disk space, or contact the {{productName}} administrator to increase the storage quota.",
"RemoveFilesOrClickToUpgrade": "Remove the unnecessary files or <1>click here</1> to upgrade your tariff plan.",
"RemoveFilesOrContactToUpgrade": "Remove the unnecessary files or contact the {{productName}} administrator to upgrade the tariff plan.",
"RemoveFilesOrContactToUpgradeQuota": "Remove the unnecessary files or contact the {{productName}} administrator to increase the storage quota.",

View File

@ -149,7 +149,10 @@ const QuotasBar = ({
};
const getPersonalQuotaDescription = () => {
if (!isAdmin) return t("PersonalUserQuotaDescription");
if (!isAdmin)
return t("PersonalUserQuotaDescription", {
productName: t("Common:ProductName"),
});
return (
<Trans

View File

@ -26,16 +26,18 @@
import React from "react";
import PropTypes from "prop-types";
import { matchPath } from "react-router";
import { withTranslation } from "react-i18next";
import { Button } from "@docspace/shared/components/button";
import { toastr } from "@docspace/shared/components/toast";
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
import { withTranslation } from "react-i18next";
import { mobileMore } from "@docspace/shared/utils";
import api from "@docspace/shared/api";
import ModalDialogContainer from "../ModalDialogContainer";
import { inject, observer } from "mobx-react";
import styled, { css } from "styled-components";
import { mobileMore } from "@docspace/shared/utils";
import BodyComponent from "./sub-components/BodyComponent";
const { deleteUser } = api.people;
@ -108,6 +110,7 @@ const DeleteProfileEverDialogComponent = (props) => {
removeUser,
userIds,
filter,
refreshInsideGroup,
setSelected,
deleteWithoutReassign,
onlyOneUser,
@ -123,15 +126,22 @@ const DeleteProfileEverDialogComponent = (props) => {
const areUsersOnly = usersToDelete.every((user) => user.isVisitor);
const isInsideGroup = matchPath(
"/accounts/groups/:groupId/filter",
location.pathname,
);
const onDeleteUser = (id) => {
setIsRequestRunning(true);
deleteUser(id)
.then(() => {
return isInsideGroup
? refreshInsideGroup()
: getUsersList(filter, true);
})
.then(() => {
toastr.success(t("SuccessfullyDeleteUserInfoMessage"));
getUsersList(filter, true);
return;
})
.catch((error) => toastr.error(error))
.finally(() => {
@ -142,7 +152,7 @@ const DeleteProfileEverDialogComponent = (props) => {
};
const onDeleteUsers = (ids) => {
setIsRequestRunning(true);
removeUser(ids, filter)
removeUser(ids, filter, isInsideGroup)
.then(() => {
toastr.success(t("DeleteGroupUsersSuccessMessage"));
})
@ -239,6 +249,7 @@ DeleteProfileEverDialog.propTypes = {
export default inject(({ peopleStore }, { users }) => {
const { dialogStore, selectionStore, filterStore, usersStore } = peopleStore;
const { refreshInsideGroup } = peopleStore.groupsStore;
const { getUsersList, needResetUserSelection } = peopleStore.usersStore;
@ -272,6 +283,7 @@ export default inject(({ peopleStore }, { users }) => {
removeUser: usersStore.removeUser,
needResetUserSelection,
filter: filterStore.filter,
refreshInsideGroup,
getUsersList,
deleteWithoutReassign,
onlyOneUser,

View File

@ -204,7 +204,7 @@ const StyledRow = styled.div`
}
.combo-button-label {
color: ${(props) => props.theme.text.disableColor};
color: ${(props) => props.theme.accessRightSelect.descriptionColor};
}
.combo-buttons_expander-icon path {
fill: ${(props) => props.theme.text.disableColor};

View File

@ -41,9 +41,12 @@ const Auth = (props) => {
const { linkData } = props;
let [searchParams, setSearchParams] = useSearchParams();
const { t } = useTranslation(["Common"]);
let referenceUrl = searchParams.get("referenceUrl");
const isFileHandler = referenceUrl.indexOf("filehandler.ashx") !== -1;
const isExternalDownloading = referenceUrl.indexOf("action=download") !== -1;
const referenceUrl = searchParams.get("referenceUrl");
const isFileHandler =
referenceUrl && referenceUrl.indexOf("filehandler.ashx") !== -1;
const isExternalDownloading =
referenceUrl && referenceUrl.indexOf("action=download") !== -1;
useEffect(() => {
loginWithConfirmKey({

View File

@ -42,6 +42,7 @@ const EmptyScreen = ({
resetInsideGroupFilter,
setIsLoading,
theme,
isEmptyGroup = false,
}) => {
const { t } = useTranslation(["People", "Common"]);
const isPeopleAccounts = window.location.pathname.includes("accounts/people");
@ -57,6 +58,17 @@ const EmptyScreen = ({
const imageSrc = theme.isBase
? EmptyScreenPersonSvgUrl
: EmptyScreenPersonSvgDarkUrl;
if (isEmptyGroup) {
return (
<EmptyScreenContainer
imageSrc={imageSrc}
imageAlt="Empty Screen Filter image"
headerText={title}
/>
);
}
return (
<>
<EmptyScreenContainer

View File

@ -85,6 +85,7 @@ const PeopleRowContainer = ({
infoPanelVisible,
withPaging,
currentDeviceType,
insideGroupIsFiltered,
}) => {
useViewEffect({
view: accountsViewAs,
@ -113,7 +114,7 @@ const PeopleRowContainer = ({
))}
</StyledRowContainer>
) : (
<EmptyScreen />
<EmptyScreen isEmptyGroup={!insideGroupIsFiltered} />
);
};
@ -126,7 +127,7 @@ export default inject(({ peopleStore, filesStore, settingsStore }) => {
} = peopleStore;
const { theme, withPaging, currentDeviceType } = settingsStore;
const { isVisible: infoPanelVisible } = infoPanelStore;
const { currentGroup } = peopleStore.groupsStore;
const { currentGroup, insideGroupIsFiltered } = peopleStore.groupsStore;
const { peopleList } = usersStore;
return {
@ -138,5 +139,6 @@ export default inject(({ peopleStore, filesStore, settingsStore }) => {
infoPanelVisible,
withPaging,
currentDeviceType,
insideGroupIsFiltered,
};
})(observer(PeopleRowContainer));

View File

@ -157,6 +157,7 @@ const Table = ({
insideGroupIsLoading,
fetchMoreInsideGroupUsers,
insideGroupFilterTotal,
insideGroupIsFiltered,
hasMoreInsideGroupUsers,
}) => {
const ref = useRef(null);
@ -177,7 +178,7 @@ const Table = ({
const isEmptyPage = !insideGroupIsLoading && peopleList.length === 0;
return isEmptyPage ? (
<EmptyScreen />
<EmptyScreen isEmptyGroup={!insideGroupIsFiltered} />
) : (
<StyledTableContainer useReactWindow={!withPaging} forwardedRef={ref}>
<TableHeader
@ -261,6 +262,7 @@ export default inject(
const {
insideGroupIsLoading,
insideGroupFilterTotal,
insideGroupIsFiltered,
hasMoreInsideGroupUsers,
fetchMoreInsideGroupUsers,
} = peopleStore.groupsStore;
@ -286,6 +288,7 @@ export default inject(
insideGroupIsLoading,
fetchMoreInsideGroupUsers,
insideGroupFilterTotal,
insideGroupIsFiltered,
hasMoreInsideGroupUsers,
};
},

View File

@ -160,6 +160,7 @@ const PureHome = (props) => {
getFolderModel,
scrollToTop,
isEmptyGroups,
isCurrentGroupEmpty,
wsCreatedPDFForm,
disableUploadPanelOpen,
} = props;
@ -176,7 +177,11 @@ const PureHome = (props) => {
const isPeopleAccounts = location.pathname.includes("accounts/people");
const isGroupsAccounts =
location.pathname.includes("accounts/groups") && !groupId;
const isAccountsEmptyFilter = isGroupsAccounts && isEmptyGroups;
const isInsideGroup =
location.pathname.includes("accounts/groups") && groupId;
const isAccountsEmptyFilter =
(isGroupsAccounts && isEmptyGroups) ||
(isInsideGroup && isCurrentGroupEmpty);
const { onDrop } = useFiles({
t,
@ -574,6 +579,7 @@ export default inject(
fetchGroup,
groups,
groupsIsFiltered,
isCurrentGroupEmpty,
} = groupsStore;
const isEmptyGroups =
!groupsIsFiltered &&
@ -692,6 +698,7 @@ export default inject(
getFolderModel,
scrollToTop,
isEmptyGroups,
isCurrentGroupEmpty,
wsCreatedPDFForm,
};
},

View File

@ -26,7 +26,8 @@
import React, { useRef } from "react";
import { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { Box } from "@docspace/shared/components/box";
import { TextInput } from "@docspace/shared/components/text-input";
@ -39,6 +40,8 @@ import { FieldContainer } from "@docspace/shared/components/field-container";
import AccessSelector from "SRC_DIR/components/AccessSelector";
import { isMobile } from "@docspace/shared/utils";
import LdapFieldComponent from "./LdapFieldComponent";
import { Link } from "@docspace/shared/components/link";
import { globalColors } from "@docspace/shared/themes";
const FIRST_NAME = "firstName",
SECOND_NAME = "secondName",
@ -68,10 +71,14 @@ const AttributeMapping = (props) => {
isLdapEnabled,
isUIDisabled,
isDefaultUsersQuotaSet,
} = props;
const { t } = useTranslation("Ldap");
const navigate = useNavigate();
const inputsRef = useRef();
const onChangeValue = (e) => {
@ -100,6 +107,10 @@ const AttributeMapping = (props) => {
setUserType(option.access);
};
const goToStarageManagement = () => {
navigate("/portal-settings/management/disk-space");
};
return (
<>
<div className="ldap_attribute-mapping-text">
@ -202,9 +213,32 @@ const AttributeMapping = (props) => {
onChange={onChangeValue}
value={userQuotaLimit}
scale
isDisabled={!isLdapEnabled || isUIDisabled}
isDisabled={
!isDefaultUsersQuotaSet || !isLdapEnabled || isUIDisabled
}
tabIndex={11}
/>
{!isDefaultUsersQuotaSet && (
<Text
as={"span"}
fontWeight={400}
fontSize="12px"
lineHeight="16px"
>
<Trans
t={t}
i18nKey="LdapQuotaInfo"
ns="Ldap"
components={[
<Link
type="action"
color={globalColors.link}
onClick={goToStarageManagement}
/>,
]}
/>
</Text>
)}
</FieldContainer>
</Box>
<Box marginProp="24px 0 24px 0">
@ -250,7 +284,7 @@ const AttributeMapping = (props) => {
);
};
export default inject(({ ldapStore }) => {
export default inject(({ ldapStore, currentQuotaStore }) => {
const {
setMail,
setFirstName,
@ -274,6 +308,8 @@ export default inject(({ ldapStore }) => {
userType,
} = requiredSettings;
const { isDefaultUsersQuotaSet } = currentQuotaStore;
return {
setFirstName,
setSecondName,
@ -292,5 +328,7 @@ export default inject(({ ldapStore }) => {
errors,
isLdapEnabled,
isUIDisabled,
isDefaultUsersQuotaSet,
};
})(observer(AttributeMapping));

View File

@ -32,6 +32,7 @@ import { HelpButton } from "@docspace/shared/components/help-button";
import { FieldContainer } from "@docspace/shared/components/field-container";
import { ToggleButton } from "@docspace/shared/components/toggle-button";
import LdapFieldComponent from "./LdapFieldComponent";
import { InputSize, InputType } from "@docspace/shared/components/text-input";
const LOGIN = "login",
PASSWORD = "password";
@ -109,6 +110,7 @@ const AuthenticationContainer = ({
isRequired
>
<LdapFieldComponent
isPassword
name={PASSWORD}
type="password"
hasError={errors.password}
@ -117,6 +119,11 @@ const AuthenticationContainer = ({
isDisabled={!isLdapEnabled || isUIDisabled || !authentication}
scale
tabIndex={19}
simpleView
size={InputSize.small}
autoComplete="current-password"
inputType={InputType.password}
isDisableTooltip
/>
</FieldContainer>
</Box>

View File

@ -28,6 +28,7 @@ import React from "react";
import { inject, observer } from "mobx-react";
import { TextInput } from "@docspace/shared/components/text-input";
import { Textarea } from "@docspace/shared/components/textarea";
import { PasswordInput } from "@docspace/shared/components/password-input";
const LdapFieldComponent = (props) => {
const {
@ -37,6 +38,7 @@ const LdapFieldComponent = (props) => {
setErrorField,
name,
onChange,
isPassword,
...prop
} = props;
@ -68,6 +70,17 @@ const LdapFieldComponent = (props) => {
if (isTextArea)
return <Textarea name={name} onChange={onChangeFn} {...prop} />;
if (isPassword)
return (
<PasswordInput
name={name}
onBlur={onBlur}
onFocus={onFocus}
onChange={onChangeFn}
{...prop}
/>
);
return (
<TextInput
name={name}

View File

@ -41,13 +41,11 @@ const SubmitResetButtons = (props) => {
resetForm,
confirmationResetModal,
isSubmitLoading,
hasErrors,
hasChanges,
isLoadingXml,
enableSso,
isSSOAvailable,
closeResetModal,
confirmReset,
isDisabledSaveButton,
} = props;
return (
@ -62,9 +60,7 @@ const SubmitResetButtons = (props) => {
displaySettings={true}
hasScroll={true}
isSaving={isSubmitLoading}
saveButtonDisabled={
!enableSso || hasErrors || !hasChanges || isLoadingXml
}
saveButtonDisabled={isDisabledSaveButton}
disableRestoreToDefault={
isSubmitLoading || isLoadingXml || !isSSOAvailable
}
@ -90,12 +86,10 @@ export default inject(({ ssoStore, currentQuotaStore }) => {
resetForm,
confirmationResetModal,
isSubmitLoading,
hasErrors,
hasChanges,
isLoadingXml,
enableSso,
closeResetModal,
confirmReset,
isDisabledSaveButton,
} = ssoStore;
const { isSSOAvailable } = currentQuotaStore;
@ -106,12 +100,10 @@ export default inject(({ ssoStore, currentQuotaStore }) => {
resetForm,
confirmationResetModal,
isSubmitLoading,
hasErrors,
hasChanges,
isLoadingXml,
enableSso,
isSSOAvailable,
closeResetModal,
confirmReset,
isDisabledSaveButton,
};
})(observer(SubmitResetButtons));

View File

@ -51,16 +51,6 @@ const StyledSsoPage = styled.div`
margin-bottom: 4px;
}
.field-label {
display: flex;
align-items: center;
height: auto;
font-weight: 600;
line-height: 20px;
overflow: visible;
white-space: normal;
}
.xml-input {
.field-label-icon {
margin-bottom: 8px;

View File

@ -152,6 +152,24 @@ class GroupsStore {
return false;
}
get insideGroupIsFiltered() {
return (
this.insideGroupFilter.activationStatus ||
this.insideGroupFilter.employeeStatus ||
this.insideGroupFilter.payments ||
this.insideGroupFilter.search ||
this.insideGroupFilter.role ||
this.insideGroupFilter.accountLoginType
);
}
get isCurrentGroupEmpty() {
return (
!this.insideGroupIsFiltered &&
this.peopleStore.usersStore.peopleList.length === 0
);
}
// Inside Group Filter
setInsideGroupFilter = (filter) => {
@ -282,6 +300,7 @@ class GroupsStore {
filter,
updateFilter = false,
withFilterLocalStorage = false,
updateCurrentGroup = false,
) => {
this.setInsideGroupLoading(true);
@ -309,7 +328,7 @@ class GroupsStore {
requests.push(api.people.getUserList(filterData));
if (groupId !== this.currentGroup?.id) {
if (updateCurrentGroup || groupId !== this.currentGroup?.id) {
requests.push(groupsApi.getGroupById(groupId));
}
@ -329,6 +348,18 @@ class GroupsStore {
return Promise.resolve(filteredMembersRes.items);
};
refreshInsideGroup = async () => {
if (!this.currentGroup) return;
await this.fetchGroup(
this.currentGroup.id,
this.insideGroupFilter,
true,
false,
true,
);
};
get hasMoreInsideGroupUsers() {
return (
this.peopleStore.usersStore.users.length < this.insideGroupFilter.total
@ -662,10 +693,12 @@ class GroupsStore {
}
if (getIsInsideGroup() && this.currentGroup?.id === groupId) {
const filter = this.insideGroupFilter.clone();
this.setCurrentGroup(res);
const members = await api.people.getUserList(
this.insideGroupFilter.clone(),
);
const members = await api.people.getUserList(filter);
filter.total = members.total;
this.setInsideGroupFilter(filter);
this.peopleStore.usersStore.setUsers(members.items);
this.setInsideGroupTempTitle(res.name);
}

View File

@ -946,6 +946,33 @@ class SsoFormStore {
);
}
get isDisabledSaveButton() {
return (
!this.enableSso ||
this.hasErrors ||
!this.hasChanges ||
this.isLoadingXml ||
this.isRequiredFieldsEmpty
);
}
get isRequiredFieldsEmpty() {
return (
this.entityId.trim().length === 0 ||
(this.ssoBinding === BINDING_POST &&
this.ssoUrlPost.trim().length === 0) ||
(this.sloBinding === BINDING_POST &&
this.sloUrlPost.trim().length === 0) ||
(this.ssoBinding === BINDING_REDIRECT &&
this.ssoUrlRedirect.trim().length === 0) ||
(this.sloBinding === BINDING_REDIRECT &&
this.sloUrlRedirect.trim().length === 0) ||
this.firstName.trim().length === 0 ||
this.lastName.trim().length === 0 ||
this.email.trim().length === 0
);
}
scrollToField = () => {
for (let key in this) {
if (key.includes("HasError") && this[key] !== false) {

View File

@ -149,9 +149,14 @@ class UsersStore {
return Promise.resolve(result);
};
removeUser = async (userId, filter) => {
removeUser = async (userId, filter, isInsideGroup) => {
const { refreshInsideGroup } = this.peopleStore.groupsStore;
await api.people.deleteUsers(userId);
await this.getUsersList(filter, true);
isInsideGroup
? await refreshInsideGroup()
: await this.getUsersList(filter, true);
};
get needResetUserSelection() {