passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
303 lines (282 loc) • 10.2 kB
JavaScript
/**
* Passbolt ~ Open source password manager for teams
* Copyright (c) Passbolt SA (https://www.passbolt.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
* @since 5.11.0
*/
import React, { PureComponent } from "react";
import PropTypes from "prop-types";
import { Trans, withTranslation } from "react-i18next";
import { withAdminSso } from "../../../../contexts/AdminSsoContext";
import { withAppContext } from "../../../../../shared/context/AppContext/AppContext";
import PingOneSsoSettingsEntity from "../../../../../shared/models/entity/ssoSettings/PingOneSsoSettingsEntity";
import Select from "../../../Common/Select/Select";
import Password from "../../../../../shared/components/Password/Password";
import PingOneSsoSettingsFormEntity from "../../../../../shared/models/entity/ssoSettings/PingOneSsoSettingsFormEntity";
/**
* This component displays the PingOne SSO settings form
*/
class PingOneSsoProviderForm extends PureComponent {
/**
* Constructor
* @param {Object} props
*/
constructor(props) {
super(props);
this.bindCallbacks();
this.createRefs();
}
/**
* Bind callbacks
*/
bindCallbacks() {
this.handleInputChange = this.handleInputChange.bind(this);
}
/**
* Create input refs
*/
createRefs() {
this.inputRefs = {
url: React.createRef(),
environment_id: React.createRef(),
client_id: React.createRef(),
client_secret: React.createRef(),
email_claim: React.createRef(),
};
}
/**
* Focus the first available field in error
*/
componentDidUpdate() {
if (!this.props.adminSsoContext.consumeFocusOnError()) {
return;
}
const errors = this.props.adminSsoContext.getErrors();
const fieldToFocus = this.getFirstFieldInError(
errors,
Object.keys(PingOneSsoSettingsEntity.getSchema().properties),
);
this.inputRefs[fieldToFocus]?.current?.focus();
}
/**
* Returns the first field with an error (first in the given list)
* @param {EntityValidationError} errors
* @param {Array<string>} fieldPriority the ordered list of field to check
* @returns {string|undefined}
*/
getFirstFieldInError(errors, fieldPriority) {
return fieldPriority.find((fieldName) => errors.hasError(fieldName));
}
/**
* Handle form input changes.
* @params {ReactEvent} The react event
* @returns {void}
*/
handleInputChange(event) {
const target = event.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = target.name;
this.props.adminSsoContext.setValue(name, value);
}
/**
* Should input be disabled? True if state is loading or processing
* @returns {boolean}
*/
hasAllInputDisabled() {
return this.props.adminSsoContext.isProcessing();
}
/**
* Returns an array of string from the errors so React can display them.
* @param {Object} errors
* @returns {Array<string>}
*/
displayErrors(errors) {
return Object.values(errors);
}
/**
* Get the URL select items
* @returns {Array<{value: string, label: string}>}
*/
get urlSelectItems() {
return PingOneSsoSettingsEntity.SUPPORTED_URLS.map((url) => ({
value: url,
label: url,
}));
}
/**
* Get the translate function
* @returns {function(...[*]=)}
*/
get translate() {
return this.props.t;
}
/**
* Render the component
* @returns {JSX}
*/
render() {
const ssoContext = this.props.adminSsoContext;
const ssoConfig = ssoContext.getSsoConfiguration();
const errors = ssoContext.getErrors();
return (
<>
<div className={`select-wrapper input required ${this.hasAllInputDisabled() ? "disabled" : ""}`}>
<label htmlFor="sso-pingone-url-input">
<Trans>URL</Trans>
</label>
<Select
id="sso-pingone-url-input"
name="url"
items={this.urlSelectItems}
value={ssoConfig.url}
onChange={this.handleInputChange}
disabled={this.hasAllInputDisabled()}
/>
{errors?.hasError("url") && <div className="error-message">{this.displayErrors(errors.getError("url"))}</div>}
<p>
<Trans>The PingOne authentication URL for your region.</Trans>
</p>
</div>
<div className={`input text required ${this.hasAllInputDisabled() ? "disabled" : ""}`}>
<label htmlFor="sso-pingone-environment-id-input">
<Trans>Environment ID</Trans>
</label>
<input
id="sso-pingone-environment-id-input"
type="text"
className="fluid form-element"
name="environment_id"
ref={this.inputRefs.environment_id}
value={ssoConfig.environment_id}
onChange={this.handleInputChange}
placeholder={this.translate("Environment ID")}
disabled={this.hasAllInputDisabled()}
/>
{errors?.hasError("environment_id") && (
<div className="error-message">{this.displayErrors(errors.getError("environment_id"))}</div>
)}
<p>
<Trans>The public identifier for the PingOne application.</Trans>{" "}
<a
href="https://docs.pingidentity.com/pingone/applications/p1_edit_application_oidc.html"
rel="noopener noreferrer"
target="_blank"
>
<Trans>Where to find it?</Trans>
</a>
</p>
</div>
<div className={`input text required ${this.hasAllInputDisabled() ? "disabled" : ""}`}>
<label htmlFor="sso-pingone-client-id-input">
<Trans>Application (client) ID</Trans>
</label>
<input
id="sso-pingone-client-id-input"
type="text"
className="fluid form-element"
name="client_id"
ref={this.inputRefs.client_id}
value={ssoConfig.client_id}
onChange={this.handleInputChange}
placeholder={this.translate("Application (client) ID")}
disabled={this.hasAllInputDisabled()}
/>
{errors?.hasError("client_id") && (
<div className="error-message">{this.displayErrors(errors.getError("client_id"))}</div>
)}
<p>
<Trans>The public identifier for the app in PingOne in UUID format.</Trans>{" "}
<a
href="https://docs.pingidentity.com/pingone/applications/p1_edit_application_oidc.html"
rel="noopener noreferrer"
target="_blank"
>
<Trans>Where to find it?</Trans>
</a>
</p>
</div>
<div className={`input text required ${this.hasAllInputDisabled() ? "disabled" : ""}`}>
<label htmlFor="sso-pingone-secret-input">
<Trans>Secret</Trans>
</label>
<Password
id="sso-pingone-secret-input"
className="fluid form-element"
onChange={this.handleInputChange}
autoComplete="off"
name="client_secret"
placeholder={this.translate("Secret")}
disabled={this.hasAllInputDisabled()}
value={ssoConfig.client_secret}
preview={true}
inputRef={this.inputRefs.client_secret}
/>
{errors?.hasError("client_secret") && (
<div className="error-message">{this.displayErrors(errors.getError("client_secret"))}</div>
)}
<p>
<Trans>Allows PingOne and Passbolt API to securely share information.</Trans>{" "}
<a
href="https://docs.pingidentity.com/pingone/applications/p1_edit_application_oidc.html"
rel="noopener noreferrer"
target="_blank"
>
<Trans>Where to find it?</Trans>
</a>
</p>
</div>
<div className="input text required disabled">
<label htmlFor="sso-pingone-scope-input">
<Trans>Scope</Trans>
</label>
<input
id="sso-pingone-scope-input"
type="text"
className="fluid form-element"
name="scope"
value={PingOneSsoSettingsFormEntity.SCOPE}
disabled
/>
<p>
<Trans>Defines which PingOne field needs to be used as Passbolt username.</Trans>
</p>
</div>
<div className={`input text required ${this.hasAllInputDisabled() ? "disabled" : ""}`}>
<label htmlFor="sso-pingone-email-claim-input">
<Trans>Email claim</Trans>
</label>
<input
id="sso-pingone-email-claim-input"
type="text"
className="fluid form-element"
name="email_claim"
ref={this.inputRefs.email_claim}
value={ssoConfig.email_claim}
onChange={this.handleInputChange}
placeholder={this.translate("Email claim")}
disabled={this.hasAllInputDisabled()}
/>
{errors?.hasError("email_claim") && (
<div className="error-message">{this.displayErrors(errors.getError("email_claim"))}</div>
)}
<p>
<Trans>Defines which PingOne field needs to be used as Passbolt username.</Trans>
</p>
</div>
</>
);
}
}
PingOneSsoProviderForm.propTypes = {
adminSsoContext: PropTypes.object, // The administration sso configuration context
context: PropTypes.any, // The application context
t: PropTypes.func, // The translation function
};
export default withAppContext(withAdminSso(withTranslation("common")(PingOneSsoProviderForm)));