diff --git a/frontend/components/forms/fields/Dropdown/_styles.scss b/frontend/components/forms/fields/Dropdown/_styles.scss
index d97972eaca..c7915e4067 100644
--- a/frontend/components/forms/fields/Dropdown/_styles.scss
+++ b/frontend/components/forms/fields/Dropdown/_styles.scss
@@ -89,7 +89,6 @@
.Select-value-label {
font-size: $x-small;
- font-weight: $bold;
color: $core-dark-blue-grey;
line-height: 28px;
}
diff --git a/frontend/components/forms/fields/InputFieldWithIcon/InputFieldWithIcon.jsx b/frontend/components/forms/fields/InputFieldWithIcon/InputFieldWithIcon.jsx
index d813ac1a0f..9f097fefbf 100644
--- a/frontend/components/forms/fields/InputFieldWithIcon/InputFieldWithIcon.jsx
+++ b/frontend/components/forms/fields/InputFieldWithIcon/InputFieldWithIcon.jsx
@@ -19,6 +19,7 @@ class InputFieldWithIcon extends InputField {
tabIndex: PropTypes.number,
type: PropTypes.string,
className: PropTypes.string,
+ disabled: PropTypes.bool,
};
renderHeading = () => {
@@ -57,6 +58,7 @@ class InputFieldWithIcon extends InputField {
tabIndex,
type,
value,
+ disabled,
} = this.props;
const { onInputChange, renderHint } = this;
@@ -89,6 +91,7 @@ class InputFieldWithIcon extends InputField {
tabIndex={tabIndex}
type={type}
value={value}
+ disabled={disabled}
/>
{iconName && }
{renderHint()}
diff --git a/frontend/components/forms/fields/InputFieldWithIcon/_styles.scss b/frontend/components/forms/fields/InputFieldWithIcon/_styles.scss
index ae943b6e6a..7c50d19c3d 100644
--- a/frontend/components/forms/fields/InputFieldWithIcon/_styles.scss
+++ b/frontend/components/forms/fields/InputFieldWithIcon/_styles.scss
@@ -42,6 +42,11 @@
outline: none;
}
+ &:disabled {
+ color: $ui-fleet-black-50;
+ cursor: not-allowed;
+ }
+
&--error {
color: $core-vibrant-red;
border: 1px solid $core-vibrant-red;
diff --git a/frontend/pages/UserSettingsPage/UserSettingsPage.jsx b/frontend/pages/UserSettingsPage/UserSettingsPage.jsx
index 9306a70505..0640cc71bc 100644
--- a/frontend/pages/UserSettingsPage/UserSettingsPage.jsx
+++ b/frontend/pages/UserSettingsPage/UserSettingsPage.jsx
@@ -318,7 +318,7 @@ export class UserSettingsPage extends Component {
renderPasswordModal,
renderApiTokenModal,
} = this;
- const { version, errors, user } = this.props;
+ const { version, errors, user, config } = this.props;
const { pendingEmail } = this.state;
if (!user) {
@@ -339,6 +339,7 @@ export class UserSettingsPage extends Component {
onCancel={onCancel}
pendingEmail={pendingEmail}
serverErrors={errors}
+ smtpConfigured={config.configured}
/>
diff --git a/frontend/pages/UserSettingsPage/UserSettingsPage.tests.jsx b/frontend/pages/UserSettingsPage/UserSettingsPage.tests.jsx
index f50de36f8a..2e454c06a9 100644
--- a/frontend/pages/UserSettingsPage/UserSettingsPage.tests.jsx
+++ b/frontend/pages/UserSettingsPage/UserSettingsPage.tests.jsx
@@ -29,10 +29,10 @@ describe("UserSettingsPage - component", () => {
it("contains expected text", () => {
const admin = { ...userStub, admin: true };
const pageWithUser = mount(
-
+
);
const pageWithAdmin = mount(
-
+
);
expect(pageWithUser.find(".user-settings__role").text()).toContain("User");
@@ -51,7 +51,7 @@ describe("UserSettingsPage - component", () => {
jest.spyOn(authActions, "updateUser");
const dispatch = () => Promise.resolve();
- const props = { dispatch, user: userStub };
+ const props = { dispatch, user: userStub, config: configStub };
const pageNode = mount(
).instance();
const updatedAttrs = { name: "Updated Name" };
const updatedUser = { ...userStub, ...updatedAttrs };
@@ -101,7 +101,7 @@ describe("UserSettingsPage - component", () => {
});
it("displays pending email text when the user is pending an email change", () => {
- const props = { dispatch: noop, user: userStub };
+ const props = { dispatch: noop, user: userStub, config: configStub };
const Page = mount(
);
const UserSettingsForm = () => Page.find("UserSettingsForm");
const emailHint = () =>
diff --git a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPagePage/MembersPage.tsx b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPagePage/MembersPage.tsx
index b1d99823b8..b7e16ab64e 100644
--- a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPagePage/MembersPage.tsx
+++ b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPagePage/MembersPage.tsx
@@ -95,6 +95,10 @@ const MembersPage = (props: IMembersPageProps): JSX.Element => {
return member.id;
});
+ const smtpConfigured = useSelector((state: IRootState) => {
+ return state.app.config.configured;
+ });
+
const [showAddMemberModal, setShowAddMemberModal] = useState(false);
const [showRemoveMemberModal, setShowRemoveMemberModal] = useState(false);
const [showEditUserModal, setShowEditUserModal] = useState(false);
@@ -265,6 +269,7 @@ const MembersPage = (props: IMembersPageProps): JSX.Element => {
availableTeams={teams}
validationErrors={[]}
isBasicTier={isBasicTier}
+ smtpConfigured={smtpConfigured}
/>
) : null}
{showRemoveMemberModal ? (
diff --git a/frontend/pages/admin/UserManagementPage/UserManagementPage.jsx b/frontend/pages/admin/UserManagementPage/UserManagementPage.jsx
index 79c7f29e83..cff67d860f 100644
--- a/frontend/pages/admin/UserManagementPage/UserManagementPage.jsx
+++ b/frontend/pages/admin/UserManagementPage/UserManagementPage.jsx
@@ -417,6 +417,7 @@ export class UserManagementPage extends Component {
availableTeams={teams}
submitText={"Save"}
isBasicTier={isBasicTier}
+ smtpConfigured={config.configured}
/>
);
@@ -452,6 +453,7 @@ export class UserManagementPage extends Component {
defaultTeams={[]}
submitText={"Create"}
isBasicTier={isBasicTier}
+ smtpConfigured={config.configured}
/>
);
diff --git a/frontend/pages/admin/UserManagementPage/components/EditUserModal/EditUserModal.tsx b/frontend/pages/admin/UserManagementPage/components/EditUserModal/EditUserModal.tsx
index 47b588c62b..91283ed273 100644
--- a/frontend/pages/admin/UserManagementPage/components/EditUserModal/EditUserModal.tsx
+++ b/frontend/pages/admin/UserManagementPage/components/EditUserModal/EditUserModal.tsx
@@ -16,6 +16,7 @@ interface IEditUserModalProps {
availableTeams: ITeam[];
validationErrors: any[];
isBasicTier: boolean;
+ smtpConfigured: boolean;
}
const baseClass = "edit-user-modal";
@@ -32,6 +33,7 @@ const EditUserModal = (props: IEditUserModalProps): JSX.Element => {
availableTeams,
isBasicTier,
validationErrors,
+ smtpConfigured,
} = props;
return (
@@ -52,6 +54,7 @@ const EditUserModal = (props: IEditUserModalProps): JSX.Element => {
availableTeams={availableTeams}
submitText={"Save"}
isBasicTier={isBasicTier}
+ smtpConfigured={smtpConfigured}
/>
);
diff --git a/frontend/pages/admin/UserManagementPage/components/SelectedTeamsForm/SelectedTeamsForm.tsx b/frontend/pages/admin/UserManagementPage/components/SelectedTeamsForm/SelectedTeamsForm.tsx
index 98beb097c6..f51da07eb9 100644
--- a/frontend/pages/admin/UserManagementPage/components/SelectedTeamsForm/SelectedTeamsForm.tsx
+++ b/frontend/pages/admin/UserManagementPage/components/SelectedTeamsForm/SelectedTeamsForm.tsx
@@ -22,12 +22,12 @@ const baseClass = "selected-teams-form";
const roles = [
{
disabled: false,
- label: "observer",
+ label: "Observer",
value: "observer",
},
{
disabled: false,
- label: "maintainer",
+ label: "Maintainer",
value: "maintainer",
},
];
diff --git a/frontend/pages/admin/UserManagementPage/components/UserForm/UserForm.tsx b/frontend/pages/admin/UserManagementPage/components/UserForm/UserForm.tsx
index ae4973258b..75d0207626 100644
--- a/frontend/pages/admin/UserManagementPage/components/UserForm/UserForm.tsx
+++ b/frontend/pages/admin/UserManagementPage/components/UserForm/UserForm.tsx
@@ -1,4 +1,5 @@
import React, { Component, FormEvent } from "react";
+import ReactTooltip from "react-tooltip";
import { ITeam } from "interfaces/team";
import Button from "components/buttons/Button";
@@ -65,6 +66,7 @@ interface ICreateUserFormProps {
defaultTeams?: ITeam[];
isBasicTier: boolean;
validationErrors: any[]; // TODO: proper interface for validationErrors
+ smtpConfigured: boolean;
}
interface ICreateUserFormState {
@@ -263,7 +265,7 @@ class UserForm extends Component
{
Users can be members of multiple teams and can only manage or
- observe team-sepcific users, entities, and settings in Fleet.
+ observe team-specific users, entities, and settings in Fleet.
{
formData: { email, name, sso_enabled },
isGlobalUser,
} = this.state;
- const { onCancel, submitText, isBasicTier } = this.props;
+ const { onCancel, submitText, isBasicTier, smtpConfigured } = this.props;
const {
onFormSubmit,
onInputChange,
@@ -317,13 +319,38 @@ class UserForm extends Component {
placeholder="Full name"
value={name}
/>
-
+
+
+
+
+
+ Editing an email address requires that SMTP is
+ configured in order to send a validation email.
+
+ Users with Admin role can configure SMTP in
+
+ Settings > Organization settings.
+
+