mirror of
https://github.com/strapi/strapi.git
synced 2025-09-07 23:57:19 +00:00
Add new user EE for SSO
Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
parent
189740c92c
commit
3d2538d72e
@ -0,0 +1,47 @@
|
|||||||
|
// This component is a work in progress
|
||||||
|
// It's made to be used when the users API is ready
|
||||||
|
import React from 'react';
|
||||||
|
import { Flex, Text } from '@buffetjs/core';
|
||||||
|
import { Duplicate } from '@buffetjs/icons';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||||
|
import IconWrapper from './IconWrapper';
|
||||||
|
import Envelope from './Envelope';
|
||||||
|
import Wrapper from './Wrapper';
|
||||||
|
|
||||||
|
const LinkNotification = ({ link, description }) => {
|
||||||
|
const handleCopy = () => {
|
||||||
|
strapi.notification.toggle({ type: 'info', message: { id: 'notification.link-copied' } });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
<IconWrapper>
|
||||||
|
<Envelope />
|
||||||
|
</IconWrapper>
|
||||||
|
<Flex flexDirection="column" justifyContent="center">
|
||||||
|
<Text fontWeight="semiBold" color="black" fontSize="md" lineHeight="18px">
|
||||||
|
{link}
|
||||||
|
<CopyToClipboard onCopy={handleCopy} text={link}>
|
||||||
|
<Duplicate fill="#8B91A0" className="icon-duplicate" />
|
||||||
|
</CopyToClipboard>
|
||||||
|
</Text>
|
||||||
|
<Text fontWeight="regular" color="grey" fontSize="sm" lineHeight="18px">
|
||||||
|
{description}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkNotification.defaultProps = {
|
||||||
|
link: '',
|
||||||
|
description: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkNotification.propTypes = {
|
||||||
|
link: PropTypes.string,
|
||||||
|
description: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LinkNotification;
|
@ -0,0 +1,53 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import { Padded } from '@buffetjs/core';
|
||||||
|
import { Label, Description as BaseDescription } from '@buffetjs/styles';
|
||||||
|
import { Col } from 'reactstrap';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import SelectRoles from '../SelectRoles';
|
||||||
|
|
||||||
|
const Description = styled(BaseDescription)`
|
||||||
|
font-size: ${({ theme }) => theme.main.sizes.fonts.md};
|
||||||
|
line-height: normal;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const RolesSelectComponent = ({ isDisabled, value, error, onChange }) => {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Col xs="6">
|
||||||
|
<Padded bottom size="xs">
|
||||||
|
<Label style={{ display: 'block' }} htmlFor="roles">
|
||||||
|
{formatMessage({ id: 'app.components.Users.ModalCreateBody.block-title.roles' })}
|
||||||
|
</Label>
|
||||||
|
</Padded>
|
||||||
|
<SelectRoles
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
name="roles"
|
||||||
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
<Description>
|
||||||
|
{formatMessage({
|
||||||
|
id: 'app.components.Users.ModalCreateBody.block-title.roles.description',
|
||||||
|
})}
|
||||||
|
</Description>
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
RolesSelectComponent.defaultProps = {
|
||||||
|
value: null,
|
||||||
|
error: null,
|
||||||
|
};
|
||||||
|
RolesSelectComponent.propTypes = {
|
||||||
|
isDisabled: PropTypes.bool.isRequired,
|
||||||
|
value: PropTypes.array,
|
||||||
|
error: PropTypes.string,
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RolesSelectComponent;
|
@ -0,0 +1,74 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { ModalSection } from 'strapi-helper-plugin';
|
||||||
|
import { Padded } from '@buffetjs/core';
|
||||||
|
import { Row } from 'reactstrap';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import loginSettingsForm from 'ee_else_ce/components/Users/ModalCreateBody/utils/loginSettingsForm';
|
||||||
|
|
||||||
|
import Input from '../../SizedInput';
|
||||||
|
import Wrapper from '../ModalCreateBody/Wrapper';
|
||||||
|
|
||||||
|
const LoginModalSection = ({ isDisabled, modifiedData, onChange, formErrors }) => {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalSection>
|
||||||
|
<Wrapper>
|
||||||
|
<Padded top size="smd">
|
||||||
|
<Row>
|
||||||
|
{Object.keys(loginSettingsForm).map(inputName => {
|
||||||
|
if (loginSettingsForm[inputName].Component) {
|
||||||
|
const { Component } = loginSettingsForm[inputName];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
key={inputName}
|
||||||
|
value={modifiedData[inputName]}
|
||||||
|
onChange={onChange}
|
||||||
|
error={formErrors[inputName]}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
{...loginSettingsForm[inputName]}
|
||||||
|
key={inputName}
|
||||||
|
description={formatMessage({ id: loginSettingsForm[inputName].description })}
|
||||||
|
type={loginSettingsForm[inputName].type}
|
||||||
|
disabled={isDisabled}
|
||||||
|
name={inputName}
|
||||||
|
onChange={onChange}
|
||||||
|
value={modifiedData.useSSORegistration}
|
||||||
|
error={formErrors.useSSORegistration}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Row>
|
||||||
|
</Padded>
|
||||||
|
</Wrapper>
|
||||||
|
</ModalSection>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
LoginModalSection.defaultProps = {
|
||||||
|
isDisabled: false,
|
||||||
|
formErrors: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
LoginModalSection.propTypes = {
|
||||||
|
isDisabled: PropTypes.bool,
|
||||||
|
modifiedData: PropTypes.shape({
|
||||||
|
roles: PropTypes.array,
|
||||||
|
useSSORegistration: PropTypes.bool,
|
||||||
|
}).isRequired,
|
||||||
|
formErrors: PropTypes.shape({
|
||||||
|
roles: PropTypes.array,
|
||||||
|
useSSORegistration: PropTypes.bool,
|
||||||
|
}),
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoginModalSection;
|
@ -1,50 +1,22 @@
|
|||||||
// This component is a work in progress
|
|
||||||
// It's made to be used when the users API is ready
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Flex, Text } from '@buffetjs/core';
|
|
||||||
import { Duplicate } from '@buffetjs/icons';
|
|
||||||
import { useIntl } from 'react-intl';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
import LinkNotification from '../LinkNotification';
|
||||||
import basename from '../../../utils/basename';
|
import basename from '../../../utils/basename';
|
||||||
import IconWrapper from './IconWrapper';
|
|
||||||
import Envelope from './Envelope';
|
|
||||||
import Wrapper from './Wrapper';
|
|
||||||
|
|
||||||
const MagicLink = ({ registrationToken }) => {
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
const handleCopy = () => {
|
|
||||||
strapi.notification.toggle({ type: 'info', message: { id: 'notification.link-copied' } });
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const MagicLink = ({ registrationToken, description }) => {
|
||||||
const link = `${window.location.origin}${basename}auth/register?registrationToken=${registrationToken}`;
|
const link = `${window.location.origin}${basename}auth/register?registrationToken=${registrationToken}`;
|
||||||
|
|
||||||
return (
|
return <LinkNotification link={link} description={description} />;
|
||||||
<Wrapper>
|
|
||||||
<IconWrapper>
|
|
||||||
<Envelope />
|
|
||||||
</IconWrapper>
|
|
||||||
<Flex flexDirection="column" justifyContent="center">
|
|
||||||
<Text fontWeight="semiBold" color="black" fontSize="md" lineHeight="18px">
|
|
||||||
{link}
|
|
||||||
<CopyToClipboard onCopy={handleCopy} text={link}>
|
|
||||||
<Duplicate fill="#8B91A0" className="icon-duplicate" />
|
|
||||||
</CopyToClipboard>
|
|
||||||
</Text>
|
|
||||||
<Text fontWeight="regular" color="grey" fontSize="sm" lineHeight="18px">
|
|
||||||
{formatMessage({ id: 'app.components.Users.MagicLink.connect' })}
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MagicLink.defaultProps = {
|
MagicLink.defaultProps = {
|
||||||
registrationToken: '',
|
registrationToken: '',
|
||||||
|
description: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
MagicLink.propTypes = {
|
MagicLink.propTypes = {
|
||||||
registrationToken: PropTypes.string,
|
registrationToken: PropTypes.string,
|
||||||
|
description: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MagicLink;
|
export default MagicLink;
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
import React, { forwardRef, useReducer, useImperativeHandle, useRef } from 'react';
|
import React, { forwardRef, useReducer, useImperativeHandle, useRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { BaselineAlignment, ModalSection, request } from 'strapi-helper-plugin';
|
import { BaselineAlignment, ModalSection, request } from 'strapi-helper-plugin';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { Padded, Text } from '@buffetjs/core';
|
import { Padded, Text } from '@buffetjs/core';
|
||||||
import { Col, Row } from 'reactstrap';
|
import { Row } from 'reactstrap';
|
||||||
|
import MagicLink from 'ee_else_ce/components/Users/MagicLink';
|
||||||
|
|
||||||
import checkFormValidity from '../../../utils/checkFormValidity';
|
import checkFormValidity from '../../../utils/checkFormValidity';
|
||||||
import SelectRoles from '../SelectRoles';
|
|
||||||
import form from './utils/form';
|
import form from './utils/form';
|
||||||
import schema from './utils/schema';
|
import schema from './utils/schema';
|
||||||
import { initialState, reducer } from './reducer';
|
import { initialState, reducer } from './reducer';
|
||||||
import init from './init';
|
import init from './init';
|
||||||
import Input from '../../SizedInput';
|
import Input from '../../SizedInput';
|
||||||
import Wrapper from './Wrapper';
|
import Wrapper from './Wrapper';
|
||||||
import MagicLink from '../MagicLink';
|
import LoginModalSection from '../LoginModalSection';
|
||||||
|
|
||||||
// This component accepts a ref so we can have access to the submit handler.
|
// This component accepts a ref so we can have access to the submit handler.
|
||||||
const ModalCreateBody = forwardRef(
|
const ModalCreateBody = forwardRef(
|
||||||
@ -21,6 +22,7 @@ const ModalCreateBody = forwardRef(
|
|||||||
const [reducerState, dispatch] = useReducer(reducer, initialState, init);
|
const [reducerState, dispatch] = useReducer(reducer, initialState, init);
|
||||||
const { formErrors, modifiedData } = reducerState;
|
const { formErrors, modifiedData } = reducerState;
|
||||||
const buttonSubmitRef = useRef(null);
|
const buttonSubmitRef = useRef(null);
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
submit: () => {
|
submit: () => {
|
||||||
@ -86,15 +88,13 @@ const ModalCreateBody = forwardRef(
|
|||||||
<ModalSection>
|
<ModalSection>
|
||||||
<Padded top size="18px">
|
<Padded top size="18px">
|
||||||
<Text fontSize="xs" color="grey" fontWeight="bold" textTransform="uppercase">
|
<Text fontSize="xs" color="grey" fontWeight="bold" textTransform="uppercase">
|
||||||
<FormattedMessage id="app.components.Users.ModalCreateBody.block-title.details">
|
{formatMessage({ id: 'app.components.Users.ModalCreateBody.block-title.details' })}
|
||||||
{txt => txt}
|
|
||||||
</FormattedMessage>
|
|
||||||
</Text>
|
</Text>
|
||||||
</Padded>
|
</Padded>
|
||||||
</ModalSection>
|
</ModalSection>
|
||||||
<ModalSection>
|
<ModalSection>
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<Padded top size="20px">
|
<Padded top size="smd">
|
||||||
<Row>
|
<Row>
|
||||||
{Object.keys(form).map((inputName, i) => (
|
{Object.keys(form).map((inputName, i) => (
|
||||||
<Input
|
<Input
|
||||||
@ -115,29 +115,16 @@ const ModalCreateBody = forwardRef(
|
|||||||
<ModalSection>
|
<ModalSection>
|
||||||
<Padded top size="3px">
|
<Padded top size="3px">
|
||||||
<Text fontSize="xs" color="grey" fontWeight="bold" textTransform="uppercase">
|
<Text fontSize="xs" color="grey" fontWeight="bold" textTransform="uppercase">
|
||||||
<FormattedMessage id="app.components.Users.ModalCreateBody.block-title.roles">
|
{formatMessage({ id: 'app.components.Users.ModalCreateBody.block-title.login' })}
|
||||||
{txt => txt}
|
|
||||||
</FormattedMessage>
|
|
||||||
</Text>
|
</Text>
|
||||||
</Padded>
|
</Padded>
|
||||||
</ModalSection>
|
</ModalSection>
|
||||||
<ModalSection>
|
<LoginModalSection
|
||||||
<Wrapper>
|
modifiedData={modifiedData}
|
||||||
<Padded top size="12px">
|
onChange={handleChange}
|
||||||
<Row>
|
formErrors={formErrors}
|
||||||
<Col xs="6">
|
isDisabled={isDisabled}
|
||||||
<SelectRoles
|
/>
|
||||||
isDisabled={isDisabled}
|
|
||||||
name="roles"
|
|
||||||
onChange={handleChange}
|
|
||||||
value={modifiedData.roles}
|
|
||||||
error={formErrors.roles}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Padded>
|
|
||||||
</Wrapper>
|
|
||||||
</ModalSection>
|
|
||||||
<button type="submit" style={{ display: 'none' }} ref={buttonSubmitRef}>
|
<button type="submit" style={{ display: 'none' }} ref={buttonSubmitRef}>
|
||||||
hidden button to use the native form event
|
hidden button to use the native form event
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
/* eslint-disable consistent-return */
|
/* eslint-disable consistent-return */
|
||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import { set } from 'lodash';
|
import { set } from 'lodash';
|
||||||
|
import formDataModel from 'ee_else_ce/components/Users/ModalCreateBody/utils/formDataModel';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
formErrors: {},
|
formErrors: {},
|
||||||
modifiedData: {
|
modifiedData: formDataModel,
|
||||||
firstname: '',
|
|
||||||
lastname: '',
|
|
||||||
email: '',
|
|
||||||
roles: [],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const reducer = (state, action) =>
|
const reducer = (state = initialState, action) =>
|
||||||
produce(state, draftState => {
|
produce(state, draftState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'ON_CHANGE': {
|
case 'ON_CHANGE': {
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
const formDataModel = {
|
||||||
|
firstname: '',
|
||||||
|
lastname: '',
|
||||||
|
email: '',
|
||||||
|
roles: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default formDataModel;
|
@ -0,0 +1,10 @@
|
|||||||
|
import RolesSelectComponent from '../../LoginModalSection/RolesSelectComponent';
|
||||||
|
|
||||||
|
const loginSettingsForm = {
|
||||||
|
roles: {
|
||||||
|
label: 'Settings.permissions.users.form.firstname',
|
||||||
|
Component: RolesSelectComponent,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default loginSettingsForm;
|
@ -19,6 +19,7 @@ const SelectRoles = ({ error, isDisabled, name, onChange, value }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Select
|
<Select
|
||||||
|
name={name}
|
||||||
components={{
|
components={{
|
||||||
ClearIndicator,
|
ClearIndicator,
|
||||||
DropdownIndicator,
|
DropdownIndicator,
|
||||||
|
@ -32,15 +32,14 @@ const ModalForm = ({ isOpen, onClosed, onToggle }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleClosed = () => {
|
const handleClosed = () => {
|
||||||
setStep('create');
|
|
||||||
|
|
||||||
// Fetch data only if the user has submitted a new entry
|
// Fetch data only if the user has submitted a new entry
|
||||||
// We can use the registrationToken to know this
|
// We can use the registrationToken to know this
|
||||||
if (registrationToken) {
|
if (registrationToken || currentStep === 'magic-link') {
|
||||||
onClosed();
|
onClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the state so we know that the user has created a new entry when there is a registrationToken
|
// Reset the state so we know that the user has created a new entry when there is a registrationToken
|
||||||
|
setStep('create');
|
||||||
setShowBody(false);
|
setShowBody(false);
|
||||||
setRegistrationToken(null);
|
setRegistrationToken(null);
|
||||||
};
|
};
|
||||||
|
@ -100,6 +100,8 @@
|
|||||||
"Settings.permissions.users.form.email": "Email",
|
"Settings.permissions.users.form.email": "Email",
|
||||||
"Settings.permissions.users.form.firstname": "First name",
|
"Settings.permissions.users.form.firstname": "First name",
|
||||||
"Settings.permissions.users.form.lastname": "Last name",
|
"Settings.permissions.users.form.lastname": "Last name",
|
||||||
|
"Settings.permissions.users.form.sso": "Connect with SSO",
|
||||||
|
"Settings.permissions.users.form.sso.description": "When enabled (ON), users can login via SSO",
|
||||||
"Settings.permissions.users.listview.header.description.plural": "{number} users found",
|
"Settings.permissions.users.listview.header.description.plural": "{number} users found",
|
||||||
"Settings.permissions.users.listview.header.description.singular": "{number} user found",
|
"Settings.permissions.users.listview.header.description.singular": "{number} user found",
|
||||||
"Settings.permissions.users.listview.header.title": "Users",
|
"Settings.permissions.users.listview.header.title": "Users",
|
||||||
@ -240,8 +242,11 @@
|
|||||||
"app.components.UpgradePlanModal.text-power": "Unlock the full power",
|
"app.components.UpgradePlanModal.text-power": "Unlock the full power",
|
||||||
"app.components.UpgradePlanModal.text-strapi": "of Strapi by upgrading your plan to the",
|
"app.components.UpgradePlanModal.text-strapi": "of Strapi by upgrading your plan to the",
|
||||||
"app.components.Users.MagicLink.connect": "Send this link to the user for them to connect.",
|
"app.components.Users.MagicLink.connect": "Send this link to the user for them to connect.",
|
||||||
|
"app.components.Users.MagicLink.connect.sso": "Send this link to the user, the first login can be mage via a SSO provider",
|
||||||
"app.components.Users.ModalCreateBody.block-title.details": "Details",
|
"app.components.Users.ModalCreateBody.block-title.details": "Details",
|
||||||
"app.components.Users.ModalCreateBody.block-title.roles": "User's roles",
|
"app.components.Users.ModalCreateBody.block-title.roles": "User's roles",
|
||||||
|
"app.components.Users.ModalCreateBody.block-title.roles.description": "Your user can have one or several roles",
|
||||||
|
"app.components.Users.ModalCreateBody.block-title.login": "Login settings",
|
||||||
"app.components.Users.SortPicker.button-label": "Sort by",
|
"app.components.Users.SortPicker.button-label": "Sort by",
|
||||||
"app.components.Users.SortPicker.sortby.email_asc": "Email (A to Z)",
|
"app.components.Users.SortPicker.sortby.email_asc": "Email (A to Z)",
|
||||||
"app.components.Users.SortPicker.sortby.email_desc": "Email (Z to A)",
|
"app.components.Users.SortPicker.sortby.email_desc": "Email (Z to A)",
|
||||||
@ -313,7 +318,7 @@
|
|||||||
"components.Input.error.validation.unique": "This value is already used.",
|
"components.Input.error.validation.unique": "This value is already used.",
|
||||||
"components.InputSelect.option.placeholder": "Choose here",
|
"components.InputSelect.option.placeholder": "Choose here",
|
||||||
"components.ListRow.empty": "There is no data to be shown.",
|
"components.ListRow.empty": "There is no data to be shown.",
|
||||||
"components.NotAllowedInput.text":"No permissions to see this field",
|
"components.NotAllowedInput.text": "No permissions to see this field",
|
||||||
"components.OverlayBlocker.description": "You're using a feature that needs the server to restart. Please wait until the server is up.",
|
"components.OverlayBlocker.description": "You're using a feature that needs the server to restart. Please wait until the server is up.",
|
||||||
"components.OverlayBlocker.description.serverError": "The server should have restarted, please check your logs in the terminal.",
|
"components.OverlayBlocker.description.serverError": "The server should have restarted, please check your logs in the terminal.",
|
||||||
"components.OverlayBlocker.title": "Waiting for restart...",
|
"components.OverlayBlocker.title": "Waiting for restart...",
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import LinkNotification from '../../../../../admin/src/components/Users/LinkNotification';
|
||||||
|
import basename from '../../../../../admin/src/utils/basename';
|
||||||
|
|
||||||
|
const MagicLink = ({ registrationToken }) => {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
|
if (registrationToken) {
|
||||||
|
return (
|
||||||
|
<LinkNotification
|
||||||
|
link={`${window.location.origin}${basename}auth/register?registrationToken=${registrationToken}`}
|
||||||
|
description={formatMessage({ id: 'app.components.Users.MagicLink.connect' })}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LinkNotification
|
||||||
|
link={`${window.location.origin}${basename}`}
|
||||||
|
description={formatMessage({ id: 'app.components.Users.MagicLink.connect.sso' })}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MagicLink.defaultProps = {
|
||||||
|
registrationToken: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
MagicLink.propTypes = {
|
||||||
|
registrationToken: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MagicLink;
|
@ -0,0 +1,14 @@
|
|||||||
|
import baseModel from '../../../../../../admin/src/components/Users/ModalCreateBody/utils/formDataModel';
|
||||||
|
|
||||||
|
const ssoInputsModel = ENABLED_EE_FEATURES.includes('sso')
|
||||||
|
? {
|
||||||
|
useSSORegistration: true,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
const formDataModel = {
|
||||||
|
...baseModel,
|
||||||
|
...ssoInputsModel,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default formDataModel;
|
@ -0,0 +1,21 @@
|
|||||||
|
import baseForm from '../../../../../../admin/src/components/Users/ModalCreateBody/utils/loginSettingsForm';
|
||||||
|
|
||||||
|
const ssoInputs = ENABLED_EE_FEATURES.includes('sso')
|
||||||
|
? {
|
||||||
|
useSSORegistration: {
|
||||||
|
label: 'Settings.permissions.users.form.sso',
|
||||||
|
type: 'bool',
|
||||||
|
validations: {
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
description: 'Settings.permissions.users.form.sso.description',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
const form = {
|
||||||
|
...baseForm,
|
||||||
|
...ssoInputs,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default form;
|
@ -15,7 +15,7 @@ module.exports = () => {
|
|||||||
const options = {
|
const options = {
|
||||||
backend: 'http://localhost:1337',
|
backend: 'http://localhost:1337',
|
||||||
publicPath: '/admin/',
|
publicPath: '/admin/',
|
||||||
features: process.env.ENABLED_EE_FEATURES || [],
|
features: process.env.ENABLED_EE_FEATURES || ['sso'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const args = {
|
const args = {
|
||||||
|
35
yarn.lock
35
yarn.lock
@ -4727,11 +4727,6 @@ base64-js@^1.0.2, base64-js@^1.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
|
||||||
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
|
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
|
||||||
|
|
||||||
base64url@3.x.x:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d"
|
|
||||||
integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==
|
|
||||||
|
|
||||||
base@^0.11.1:
|
base@^0.11.1:
|
||||||
version "0.11.2"
|
version "0.11.2"
|
||||||
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
|
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
|
||||||
@ -13928,11 +13923,6 @@ oauth-sign@^0.9.0, oauth-sign@~0.9.0:
|
|||||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||||
|
|
||||||
oauth@0.9.x:
|
|
||||||
version "0.9.15"
|
|
||||||
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
|
|
||||||
integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE=
|
|
||||||
|
|
||||||
object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
@ -14556,13 +14546,6 @@ pascalcase@^0.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
|
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
|
||||||
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
|
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
|
||||||
|
|
||||||
passport-google-oauth2@0.2.0:
|
|
||||||
version "0.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/passport-google-oauth2/-/passport-google-oauth2-0.2.0.tgz#fc9ea59e7091f02e24fd16d6be9257ea982ebbc3"
|
|
||||||
integrity sha512-62EdPtbfVdc55nIXi0p1WOa/fFMM8v/M8uQGnbcXA4OexZWCnfsEi3wo2buag+Is5oqpuHzOtI64JpHk0Xi5RQ==
|
|
||||||
dependencies:
|
|
||||||
passport-oauth2 "^1.1.2"
|
|
||||||
|
|
||||||
passport-local@1.0.0:
|
passport-local@1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee"
|
resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee"
|
||||||
@ -14570,17 +14553,6 @@ passport-local@1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
passport-strategy "1.x.x"
|
passport-strategy "1.x.x"
|
||||||
|
|
||||||
passport-oauth2@^1.1.2:
|
|
||||||
version "1.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108"
|
|
||||||
integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ==
|
|
||||||
dependencies:
|
|
||||||
base64url "3.x.x"
|
|
||||||
oauth "0.9.x"
|
|
||||||
passport-strategy "1.x.x"
|
|
||||||
uid2 "0.0.x"
|
|
||||||
utils-merge "1.x.x"
|
|
||||||
|
|
||||||
passport-strategy@1.x.x:
|
passport-strategy@1.x.x:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
|
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
|
||||||
@ -19561,11 +19533,6 @@ uid-number@0.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
|
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
|
||||||
integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=
|
integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=
|
||||||
|
|
||||||
uid2@0.0.x:
|
|
||||||
version "0.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82"
|
|
||||||
integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=
|
|
||||||
|
|
||||||
umask@^1.1.0:
|
umask@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d"
|
resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d"
|
||||||
@ -19904,7 +19871,7 @@ utila@^0.4.0, utila@~0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
|
resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
|
||||||
integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=
|
integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=
|
||||||
|
|
||||||
utils-merge@1.0.1, utils-merge@1.x.x:
|
utils-merge@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||||
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user