diff --git a/app/localization/translated/be.json b/app/localization/translated/be.json index 798e2d64af..5b44f35486 100644 --- a/app/localization/translated/be.json +++ b/app/localization/translated/be.json @@ -647,7 +647,8 @@ "EditWidgetModal.editWidgetSuccess": "Віджэт абноўлены!", "EditWidgetModal.headerText": "Рэдагаваць віджэт", "EmailFormFields.authLabel": "Аўтарызацыя", - "EmailFormFields.fromLabel": "Імя адпраўніка па змаўчанні", + "EmailFormFields.fromEmailLabel": "From Email", + "EmailFormFields.fromNameLabel": "From name", "EmailFormFields.hostLabel": "Хост", "EmailFormFields.passwordLabel": "Пароль", "EmailFormFields.portFieldHint": "Магчымы толькі лічбы ад '1' да '65535'", @@ -1839,6 +1840,10 @@ "SortingControl.sortByFailedItems": "Няўдалыя пункты", "SortingControl.sortByPassingRate": "Прахадны бал", "SortingControl.sortByTotal": "Агульная колькасць", + "SsoUsersForm.formHeader": "Instance Invitations", + "SsoUsersForm.manualInvitesDescription": "Карыстальнікі могуць адпраўляць запрашэнні іншым карыстальнікам. Калі ўключана, новыя карыстальнікі могуць быць ствараны толькі праз SSO.", + "SsoUsersForm.ssoOnlyDescription": "Новыя карыстальнікі могуць быць створаны толькі праз SSO.", + "SsoUsersForm.switcherLabel": "Толькі SSO карыстальнікі", "StackTrace.jumpTo": "Перайсці", "StackTrace.linkText": "Адкрыць логі", "StackTrace.loadLabel": "Загрузіць яшчэ", diff --git a/app/localization/translated/es.json b/app/localization/translated/es.json index a94647513c..986849dd33 100644 --- a/app/localization/translated/es.json +++ b/app/localization/translated/es.json @@ -647,7 +647,8 @@ "EditWidgetModal.editWidgetSuccess": "¡Widget actualizado!", "EditWidgetModal.headerText": "Editar widget", "EmailFormFields.authLabel": "Autorización", - "EmailFormFields.fromLabel": "Nombre del remitente predeterminado", + "EmailFormFields.fromEmailLabel": "From Email", + "EmailFormFields.fromNameLabel": "From name", "EmailFormFields.hostLabel": "Host", "EmailFormFields.passwordLabel": "Contraseña", "EmailFormFields.portFieldHint": "Solo se permiten números del '1' al '65535'", @@ -1839,6 +1840,10 @@ "SortingControl.sortByFailedItems": "Elementos fallidos", "SortingControl.sortByPassingRate": "Porcentaje de aprobados", "SortingControl.sortByTotal": "Cantidad total", + "SsoUsersForm.formHeader": "Instance Invitations", + "SsoUsersForm.manualInvitesDescription": "Users can manually send invitations for other users. If enabled new users can be created via SSO only.", + "SsoUsersForm.ssoOnlyDescription": "New users can be created via SSO only.", + "SsoUsersForm.switcherLabel": "SSO users only", "StackTrace.jumpTo": "Ir a", "StackTrace.linkText": "Abrir registros", "StackTrace.loadLabel": "Cargar más", diff --git a/app/localization/translated/ru.json b/app/localization/translated/ru.json index 22a9fd9425..daa7dd0749 100644 --- a/app/localization/translated/ru.json +++ b/app/localization/translated/ru.json @@ -647,7 +647,8 @@ "EditWidgetModal.editWidgetSuccess": "Виджет обновлен!", "EditWidgetModal.headerText": "Редактировать виджет", "EmailFormFields.authLabel": "Авторизация", - "EmailFormFields.fromLabel": "Имя отправителя по умолчанию", + "EmailFormFields.fromEmailLabel": "From Email", + "EmailFormFields.fromNameLabel": "From name", "EmailFormFields.hostLabel": "Хост", "EmailFormFields.passwordLabel": "Пароль", "EmailFormFields.portFieldHint": "Возможны только цифры от '1' до '65535'", @@ -1839,6 +1840,10 @@ "SortingControl.sortByFailedItems": "Неудачные пункты", "SortingControl.sortByPassingRate": "Проходной балл", "SortingControl.sortByTotal": "Общее количество", + "SsoUsersForm.formHeader": "Instance Invitations", + "SsoUsersForm.manualInvitesDescription": "Пользователи могут вручную отправлять приглашения другим пользователям. Если включено, новых пользователей можно создавать только через SSO.", + "SsoUsersForm.ssoOnlyDescription": "Новых пользователей можно создавать только через SSO.", + "SsoUsersForm.switcherLabel": "Только SSO пользователи", "StackTrace.jumpTo": "Перейти", "StackTrace.linkText": "Открыть логи", "StackTrace.loadLabel": "Загрузить еще", diff --git a/app/localization/translated/uk.json b/app/localization/translated/uk.json index c645efe9dd..d34ca3e9da 100644 --- a/app/localization/translated/uk.json +++ b/app/localization/translated/uk.json @@ -647,7 +647,8 @@ "EditWidgetModal.editWidgetSuccess": "Оновлений Віджет!", "EditWidgetModal.headerText": "Віджет Редагувати", "EmailFormFields.authLabel": "Авторизація", - "EmailFormFields.fromLabel": "Ім’я відправника за замовчуванням", + "EmailFormFields.fromEmailLabel": "From Email", + "EmailFormFields.fromNameLabel": "From name", "EmailFormFields.hostLabel": "Хост", "EmailFormFields.passwordLabel": "Пароль", "EmailFormFields.portFieldHint": "Можливі тільки цифри від '1' до '65535'", @@ -1839,6 +1840,10 @@ "SortingControl.sortByFailedItems": "Невдалі пункти", "SortingControl.sortByPassingRate": "Прохідний бал", "SortingControl.sortByTotal": "Загальна кількість", + "SsoUsersForm.formHeader": "Instance Invitations", + "SsoUsersForm.manualInvitesDescription": "Користувачі можуть самостійно надсилати запрошення іншим користувачам. Якщо ввімкнено, нові користувачі створюються виключно через SSO.", + "SsoUsersForm.ssoOnlyDescription": "Користувачі створюються виключно через SSO.", + "SsoUsersForm.switcherLabel": "SSO users only", "StackTrace.jumpTo": "Перейти", "StackTrace.linkText": "Логи Відкрити", "StackTrace.loadLabel": "Завантажити", diff --git a/app/localization/translated/zh.json b/app/localization/translated/zh.json index 2ba04d183e..71b13c1360 100644 --- a/app/localization/translated/zh.json +++ b/app/localization/translated/zh.json @@ -647,7 +647,8 @@ "EditWidgetModal.editWidgetSuccess": "小部件已更新", "EditWidgetModal.headerText": "编辑小部件", "EmailFormFields.authLabel": "授权", - "EmailFormFields.fromLabel": "默认发件人姓名", + "EmailFormFields.fromEmailLabel": "From Email", + "EmailFormFields.fromNameLabel": "From name", "EmailFormFields.hostLabel": "服务器(Host)", "EmailFormFields.passwordLabel": "密码", "EmailFormFields.portFieldHint": "只允许输入从“1”到“65535”的数字", @@ -1839,6 +1840,10 @@ "SortingControl.sortByFailedItems": "失败的测试项", "SortingControl.sortByPassingRate": "通过率", "SortingControl.sortByTotal": "全部", + "SsoUsersForm.formHeader": "Instance Invitations", + "SsoUsersForm.manualInvitesDescription": "Users can manually send invitations for other users. If enabled new users can be created via SSO only.", + "SsoUsersForm.ssoOnlyDescription": "New users can be created via SSO only.", + "SsoUsersForm.switcherLabel": "SSO users only", "StackTrace.jumpTo": "跳转至", "StackTrace.linkText": "在日志视图中打开", "StackTrace.loadLabel": "加载更多", diff --git a/app/src/controllers/appInfo/constants.js b/app/src/controllers/appInfo/constants.js index cbd0668eda..8f77bdbc71 100644 --- a/app/src/controllers/appInfo/constants.js +++ b/app/src/controllers/appInfo/constants.js @@ -17,6 +17,7 @@ export const APP_INFO_NAMESPACE = 'appInfo'; export const ANALYTICS_INSTANCE_KEY = 'server.details.instance'; export const ANALYTICS_ALL_KEY = 'server.analytics.all'; +export const SSO_USERS_ONLY_KEY = 'server.users.sso'; export const OLD_HISTORY_KEY = 'history_old'; export const GA_MEASUREMENT_ID = 'ga_measurement_id'; export const INSTANCE_TYPE = 'instance_type'; diff --git a/app/src/controllers/appInfo/index.js b/app/src/controllers/appInfo/index.js index 13b135d71c..76722080b9 100644 --- a/app/src/controllers/appInfo/index.js +++ b/app/src/controllers/appInfo/index.js @@ -29,5 +29,6 @@ export { isDemoInstanceSelector, areUserSuggestionsAllowedSelector, baseEventParametersSelector, + ssoUsersOnlySelector, } from './selectors'; export { ANALYTICS_ALL_KEY } from './constants'; diff --git a/app/src/controllers/appInfo/selectors.js b/app/src/controllers/appInfo/selectors.js index e19a3c4ad7..2cce1ff98d 100644 --- a/app/src/controllers/appInfo/selectors.js +++ b/app/src/controllers/appInfo/selectors.js @@ -31,6 +31,7 @@ import { NOT_PROVIDED, ALLOW_DELETE_ACCOUNT, USER_SUGGESTIONS, + SSO_USERS_ONLY_KEY, } from './constants'; export const appInfoSelector = (state) => state.appInfo || {}; @@ -57,6 +58,8 @@ export const analyticsEnabledSelector = (state) => extensionsConfigSelector(state)[ANALYTICS_ALL_KEY] === 'true'; export const analyzerExtensionsSelector = (state) => extensionsSelector(state).analyzers || []; export const authExtensionsSelector = (state) => uatInfoSelector(state).authExtensions || {}; +export const ssoUsersOnlySelector = (state) => + extensionsConfigSelector(state)[SSO_USERS_ONLY_KEY] === 'true'; export const isOldHistorySelector = (state) => environmentSelector(state)[OLD_HISTORY_KEY] === 'true'; export const isDemoInstanceSelector = (state) => !!apiJobsSelector(state).flushingDataTrigger; diff --git a/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/authConfigurationTab.jsx b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/authConfigurationTab.jsx index d19f22b93e..ae0d996bb0 100644 --- a/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/authConfigurationTab.jsx +++ b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/authConfigurationTab.jsx @@ -16,6 +16,7 @@ import classNames from 'classnames/bind'; import { GithubAuthForm } from './forms'; +import { SsoUsersForm } from './forms/ssoUsersForm'; import styles from './authConfigurationTab.scss'; const cx = classNames.bind(styles); @@ -23,5 +24,6 @@ const cx = classNames.bind(styles); export const AuthConfigurationTab = () => (
+
); diff --git a/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/githubAuthForm/githubAuthForm.scss b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/githubAuthForm/githubAuthForm.scss index b4cb423e6f..61cbacd31f 100644 --- a/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/githubAuthForm/githubAuthForm.scss +++ b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/githubAuthForm/githubAuthForm.scss @@ -16,5 +16,5 @@ .github-auth-form { position: relative; - margin-bottom: 20px; + margin-bottom: 30px; } diff --git a/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/index.js b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/index.js index 74c592c333..f8cf40deb8 100644 --- a/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/index.js +++ b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/index.js @@ -15,3 +15,4 @@ */ export { GithubAuthForm } from './githubAuthForm'; +export { SsoUsersForm } from './ssoUsersForm'; diff --git a/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/ssoUsersForm/index.js b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/ssoUsersForm/index.js new file mode 100644 index 0000000000..ad04edbd75 --- /dev/null +++ b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/ssoUsersForm/index.js @@ -0,0 +1,17 @@ +/* + * Copyright 2024 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { SsoUsersForm } from './ssoUsersForm'; diff --git a/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/ssoUsersForm/ssoUsersForm.jsx b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/ssoUsersForm/ssoUsersForm.jsx new file mode 100644 index 0000000000..88c9e9318d --- /dev/null +++ b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/ssoUsersForm/ssoUsersForm.jsx @@ -0,0 +1,119 @@ +/* + * Copyright 2024 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { defineMessages, useIntl } from 'react-intl'; +import classNames from 'classnames/bind'; +import { connect } from 'react-redux'; +import { InputBigSwitcher } from 'components/inputs/inputBigSwitcher'; +import { SectionHeader } from 'components/main/sectionHeader'; +import { ADMIN_SERVER_SETTINGS_PAGE_EVENTS } from 'components/main/analytics/events'; +import { ssoUsersOnlySelector, fetchAppInfoAction } from 'controllers/appInfo'; +import formStyles from 'pages/admin/serverSettingsPage/common/formController/formController.scss'; +import styles from './ssoUsersForm.scss'; + +const formCx = classNames.bind(formStyles); +const cx = classNames.bind(styles); + +const messages = defineMessages({ + switcherLabel: { + id: 'SsoUsersForm.switcherLabel', + defaultMessage: 'SSO users only', + }, + formHeader: { + id: 'SsoUsersForm.formHeader', + defaultMessage: 'Instance Invitations', + }, + ssoOnlyDescription: { + id: 'SsoUsersForm.ssoOnlyDescription', + defaultMessage: 'New users can be created via SSO only.', + }, + manualInvitesDescription: { + id: 'SsoUsersForm.manualInvitesDescription', + defaultMessage: + 'Users can manually send invitations for other users. If enabled new users can be created via SSO only.', + }, +}); + +const SsoUsersFormComponent = ({ enabled: enabledFromStore, fetchAppInfo }) => { + const { formatMessage } = useIntl(); + const [enabled, setEnabled] = useState(enabledFromStore); + const inputId = 'ssoUsersToggle'; + + useEffect(() => { + fetchAppInfo(); + }, [fetchAppInfo]); + + useEffect(() => { + setEnabled(enabledFromStore); + }, [enabledFromStore]); + + const getDescription = () => + formatMessage(enabled ? messages.ssoOnlyDescription : messages.manualInvitesDescription); + + const handleToggle = (value) => { + setEnabled(value); + }; + + return ( +
+
+ +
+
+
+ +
+
+ +
+ {getDescription()} +
+
+
+
+
+
+ ); +}; + +SsoUsersFormComponent.propTypes = { + enabled: PropTypes.bool, + fetchAppInfo: PropTypes.func.isRequired, +}; + +SsoUsersFormComponent.defaultProps = { + enabled: false, +}; + +const mapStateToProps = (state) => ({ + enabled: ssoUsersOnlySelector(state), +}); + +const mapDispatchToProps = { + fetchAppInfo: fetchAppInfoAction, +}; + +export const SsoUsersForm = connect(mapStateToProps, mapDispatchToProps)(SsoUsersFormComponent); diff --git a/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/ssoUsersForm/ssoUsersForm.scss b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/ssoUsersForm/ssoUsersForm.scss new file mode 100644 index 0000000000..72a77cfd68 --- /dev/null +++ b/app/src/pages/admin/serverSettingsPage/serverSettingsTabs/authConfigurationTab/forms/ssoUsersForm/ssoUsersForm.scss @@ -0,0 +1,81 @@ +/* + * Copyright 2024 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +.form-group { + display: flex; + justify-content: flex-start; + align-items: center; + width: 100%; + margin-bottom: 25px; + + @media (max-width: $SCREEN_XS_MAX) { + flex-direction: column; + align-items: flex-start; + margin-bottom: 15px; + } +} + +.form-group-label { + min-width: 210px; + width: 210px; + padding-right: 4px; + text-align: right; + font-size: 13px; + line-height: 13px; + color: $COLOR--charcoal-grey; + box-sizing: border-box; + + @media (max-width: $SCREEN_SM_MAX) { + min-width: 150px; + width: 150px; + } + @media (max-width: $SCREEN_XS_MAX) { + width: 100%; + margin-bottom: 8px; + padding: 0; + text-align: left; + } +} + +.form-group-content { + flex: 1; + padding: 0 15px; + + @media (max-width: $SCREEN_XS_MAX) { + padding: 0; + width: 100%; + } +} + +.input-container { + display: flex; + align-items: center; + gap: 15px; + min-height: 36px; + + @media (max-width: $SCREEN_XS_MAX) { + flex-direction: column; + align-items: flex-start; + } +} + +.description { + width: 300px; + font-size: 12px; + line-height: 1.5; + color: $COLOR--gray-60; +} \ No newline at end of file