diff --git a/i18next/client.babel b/i18next/client.babel index 0b92949171..d9db8a8af7 100644 --- a/i18next/client.babel +++ b/i18next/client.babel @@ -95638,6 +95638,138 @@ + + LdapQuotaInfo + + + + + + ar-SA + false + + + az-Latn-AZ + false + + + bg-BG + false + + + cs-CZ + false + + + de-DE + false + + + el-GR + false + + + en-US + false + + + es-ES + false + + + fi-FI + false + + + fr-FR + false + + + hy-AM + false + + + it-IT + false + + + ja-JP + false + + + ko-KR + false + + + lo-LA + false + + + lv-LV + false + + + nl-NL + false + + + pl-PL + false + + + pt-BR + false + + + pt-PT + false + + + ro-RO + false + + + ru-RU + false + + + si-SI + false + + + sk-SK + false + + + sl-SI + false + + + sr-Cyrl-RS + false + + + sr-Latn-RS + false + + + tr-TR + false + + + uk-UA + false + + + vi-VN + false + + + zh-CN + false + + + LdapSecondName diff --git a/packages/client/public/locales/en/Ldap.json b/packages/client/public/locales/en/Ldap.json index 6d492fca57..f8eb100cce 100644 --- a/packages/client/public/locales/en/Ldap.json +++ b/packages/client/public/locales/en/Ldap.json @@ -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", "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.", diff --git a/packages/client/public/locales/en/MainBar.json b/packages/client/public/locales/en/MainBar.json index f3696b5d83..8c76a500aa 100644 --- a/packages/client/public/locales/en/MainBar.json +++ b/packages/client/public/locales/en/MainBar.json @@ -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.", - "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 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.", diff --git a/packages/client/src/components/MainBar/QuotasBar.js b/packages/client/src/components/MainBar/QuotasBar.js index e1ce941974..7586344647 100644 --- a/packages/client/src/components/MainBar/QuotasBar.js +++ b/packages/client/src/components/MainBar/QuotasBar.js @@ -149,7 +149,10 @@ const QuotasBar = ({ }; const getPersonalQuotaDescription = () => { - if (!isAdmin) return t("PersonalUserQuotaDescription"); + if (!isAdmin) + return t("PersonalUserQuotaDescription", { + productName: t("Common:ProductName"), + }); return ( { 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, diff --git a/packages/client/src/components/panels/InvitePanel/StyledInvitePanel.js b/packages/client/src/components/panels/InvitePanel/StyledInvitePanel.js index c47db34fb1..22e59aa6f5 100644 --- a/packages/client/src/components/panels/InvitePanel/StyledInvitePanel.js +++ b/packages/client/src/components/panels/InvitePanel/StyledInvitePanel.js @@ -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}; diff --git a/packages/client/src/pages/Confirm/sub-components/auth.js b/packages/client/src/pages/Confirm/sub-components/auth.js index 34997a89db..8c50e80aff 100644 --- a/packages/client/src/pages/Confirm/sub-components/auth.js +++ b/packages/client/src/pages/Confirm/sub-components/auth.js @@ -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({ diff --git a/packages/client/src/pages/Home/Section/AccountsBody/EmptyScreen.js b/packages/client/src/pages/Home/Section/AccountsBody/EmptyScreen.js index d5a86b17cf..9394d1ecb4 100644 --- a/packages/client/src/pages/Home/Section/AccountsBody/EmptyScreen.js +++ b/packages/client/src/pages/Home/Section/AccountsBody/EmptyScreen.js @@ -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 ( + + ); + } + return ( <> { useViewEffect({ view: accountsViewAs, @@ -113,7 +114,7 @@ const PeopleRowContainer = ({ ))} ) : ( - + ); }; @@ -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)); diff --git a/packages/client/src/pages/Home/Section/AccountsBody/InsideGroup/TableView/TableContainer.js b/packages/client/src/pages/Home/Section/AccountsBody/InsideGroup/TableView/TableContainer.js index bf403b0dce..7dcc3257c4 100644 --- a/packages/client/src/pages/Home/Section/AccountsBody/InsideGroup/TableView/TableContainer.js +++ b/packages/client/src/pages/Home/Section/AccountsBody/InsideGroup/TableView/TableContainer.js @@ -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 ? ( - + ) : ( { 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, }; }, diff --git a/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/AttributeMapping.js b/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/AttributeMapping.js index 3505190b34..4254f9f825 100644 --- a/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/AttributeMapping.js +++ b/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/AttributeMapping.js @@ -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 ( <>
@@ -202,9 +213,32 @@ const AttributeMapping = (props) => { onChange={onChangeValue} value={userQuotaLimit} scale - isDisabled={!isLdapEnabled || isUIDisabled} + isDisabled={ + !isDefaultUsersQuotaSet || !isLdapEnabled || isUIDisabled + } tabIndex={11} /> + {!isDefaultUsersQuotaSet && ( + + , + ]} + /> + + )} @@ -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)); diff --git a/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/AuthenticationContainer.js b/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/AuthenticationContainer.js index 7466f19375..180b7ff02b 100644 --- a/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/AuthenticationContainer.js +++ b/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/AuthenticationContainer.js @@ -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 > diff --git a/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/LdapFieldComponent.js b/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/LdapFieldComponent.js index 7e09c9a9a6..ccb0ff1dc1 100644 --- a/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/LdapFieldComponent.js +++ b/packages/client/src/pages/PortalSettings/categories/integration/LDAP/sub-components/LdapFieldComponent.js @@ -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