mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 21:47:20 +00:00
relates to #21559 This adds the ability for end users to enrol their own device in fleet mdm. > NOTE: this new byod HTML page is a separate HTML asset that contains all styles and scripts needed for the page to work. We do not send the fleet UI assets and this drastically cuts down the response time to the users who will be visiting this page on mobile devices There are two sides included in this: **Adding a new add host modal ios and iPad section for IT admins**  **delivering a new byod HTML page to end users that will allow end users to download the config profile to enrol into fleet mdm**  <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [ ] Added/updated tests - [x] Manual QA for all new/changed functionality
263 lines
6.6 KiB
JavaScript
263 lines
6.6 KiB
JavaScript
import React, { Component } from "react";
|
|
import PropTypes from "prop-types";
|
|
import classnames from "classnames";
|
|
import { noop, pick } from "lodash";
|
|
|
|
import { stringToClipboard } from "utilities/copy_text";
|
|
|
|
import FormField from "components/forms/FormField";
|
|
import Button from "components/buttons/Button";
|
|
import Icon from "components/Icon";
|
|
|
|
const baseClass = "input-field";
|
|
|
|
class InputField extends Component {
|
|
static propTypes = {
|
|
autofocus: PropTypes.bool,
|
|
/** readOnly displays a non-editable field */
|
|
readOnly: PropTypes.bool,
|
|
/** disabled displays a greyed out non-editable field */
|
|
disabled: PropTypes.bool,
|
|
error: PropTypes.string,
|
|
inputClassName: PropTypes.string, // eslint-disable-line react/forbid-prop-types
|
|
inputWrapperClass: PropTypes.string,
|
|
inputOptions: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
|
name: PropTypes.string,
|
|
onChange: PropTypes.func,
|
|
onBlur: PropTypes.func,
|
|
onFocus: PropTypes.func,
|
|
placeholder: PropTypes.string,
|
|
type: PropTypes.string,
|
|
blockAutoComplete: PropTypes.bool,
|
|
value: PropTypes.oneOfType([
|
|
PropTypes.bool,
|
|
PropTypes.string,
|
|
PropTypes.number,
|
|
]).isRequired,
|
|
parseTarget: PropTypes.bool,
|
|
tooltip: PropTypes.string,
|
|
labelTooltipPosition: PropTypes.string,
|
|
helpText: PropTypes.oneOfType([
|
|
PropTypes.string,
|
|
PropTypes.arrayOf(PropTypes.string),
|
|
PropTypes.object,
|
|
]),
|
|
enableCopy: PropTypes.bool,
|
|
copyButtonPosition: PropTypes.oneOfType(["inside", "outside"]),
|
|
ignore1password: PropTypes.bool,
|
|
};
|
|
|
|
static defaultProps = {
|
|
autofocus: false,
|
|
inputWrapperClass: "",
|
|
inputOptions: {},
|
|
label: null,
|
|
labelClassName: "",
|
|
onFocus: noop,
|
|
onBlur: noop,
|
|
type: "text",
|
|
blockAutoComplete: false,
|
|
value: "",
|
|
parseTarget: false,
|
|
tooltip: "",
|
|
labelTooltipPosition: undefined,
|
|
helpText: "",
|
|
enableCopy: false,
|
|
copyButtonPosition: "outside",
|
|
ignore1password: false,
|
|
};
|
|
|
|
constructor() {
|
|
super();
|
|
this.state = {
|
|
copied: false,
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
const { autofocus } = this.props;
|
|
const { input } = this;
|
|
|
|
if (autofocus) {
|
|
input.focus();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
onInputChange = (evt) => {
|
|
evt.preventDefault();
|
|
|
|
const { value, name } = evt.target;
|
|
const { onChange, parseTarget } = this.props;
|
|
|
|
if (parseTarget) {
|
|
// Returns both name and value
|
|
return onChange({ value, name });
|
|
}
|
|
|
|
return onChange(value);
|
|
};
|
|
|
|
renderCopyButton = () => {
|
|
const { value, copyButtonPosition } = this.props;
|
|
|
|
const copyValue = (e) => {
|
|
e.preventDefault();
|
|
stringToClipboard(value).then(() => {
|
|
this.setState({ copied: true });
|
|
setTimeout(() => {
|
|
this.setState({ copied: false });
|
|
}, 2000);
|
|
});
|
|
};
|
|
|
|
const copyButtonValue =
|
|
copyButtonPosition === "outside" ? (
|
|
<>
|
|
<Icon name="copy" />
|
|
<span>Copy</span>
|
|
</>
|
|
) : (
|
|
<Icon name="copy" />
|
|
);
|
|
|
|
const wrapperClasses = classnames(
|
|
`${baseClass}__copy-wrapper`,
|
|
copyButtonPosition === "outside"
|
|
? `${baseClass}__copy-wrapper-outside`
|
|
: `${baseClass}__copy-wrapper-inside`
|
|
);
|
|
|
|
const copiedConfirmationClasses = classnames(
|
|
`${baseClass}__copied-confirmation`,
|
|
copyButtonPosition === "outside"
|
|
? `${baseClass}__copied-confirmation-outside`
|
|
: `${baseClass}__copied-confirmation-inside`
|
|
);
|
|
|
|
return (
|
|
<div className={wrapperClasses}>
|
|
<Button
|
|
variant="text-icon"
|
|
onClick={copyValue}
|
|
className={`${baseClass}__copy-value-button`}
|
|
>
|
|
{copyButtonValue}
|
|
</Button>
|
|
{this.state.copied && (
|
|
<span className={copiedConfirmationClasses}>Copied!</span>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
readOnly,
|
|
disabled,
|
|
error,
|
|
inputClassName,
|
|
inputOptions,
|
|
inputWrapperClass,
|
|
name,
|
|
onFocus,
|
|
onBlur,
|
|
placeholder,
|
|
type,
|
|
blockAutoComplete,
|
|
value,
|
|
ignore1password,
|
|
enableCopy,
|
|
copyButtonPosition,
|
|
} = this.props;
|
|
|
|
const { onInputChange } = this;
|
|
const shouldShowPasswordClass = type === "password";
|
|
const inputClasses = classnames(baseClass, inputClassName, {
|
|
[`${baseClass}--password`]: shouldShowPasswordClass,
|
|
[`${baseClass}--read-only`]: readOnly || disabled,
|
|
[`${baseClass}--disabled`]: disabled,
|
|
[`${baseClass}--error`]: error,
|
|
[`${baseClass}__textarea`]: type === "textarea",
|
|
});
|
|
|
|
const inputWrapperClasses = classnames(inputWrapperClass, {
|
|
[`input-field--read-only`]: readOnly || disabled,
|
|
[`input-field--disabled`]: disabled,
|
|
});
|
|
|
|
const formFieldProps = pick(this.props, [
|
|
"helpText",
|
|
"label",
|
|
"error",
|
|
"name",
|
|
"tooltip",
|
|
"labelTooltipPosition",
|
|
]);
|
|
|
|
if (type === "textarea") {
|
|
return (
|
|
<FormField
|
|
{...formFieldProps}
|
|
type="textarea"
|
|
className={inputWrapperClasses}
|
|
>
|
|
<textarea
|
|
name={name}
|
|
id={name}
|
|
onChange={onInputChange}
|
|
className={inputClasses}
|
|
disabled={readOnly || disabled}
|
|
placeholder={placeholder}
|
|
ref={(r) => {
|
|
this.input = r;
|
|
}}
|
|
type={type}
|
|
{...inputOptions}
|
|
value={value}
|
|
/>
|
|
</FormField>
|
|
);
|
|
}
|
|
|
|
const inputContainerClasses = classnames(`${baseClass}__input-container`, {
|
|
"copy-enabled": enableCopy,
|
|
"copy-outside": enableCopy && copyButtonPosition === "outside",
|
|
"copy-inside": enableCopy && copyButtonPosition === "inside",
|
|
});
|
|
|
|
return (
|
|
<FormField
|
|
{...formFieldProps}
|
|
type="input"
|
|
className={inputWrapperClasses}
|
|
>
|
|
<div className={inputContainerClasses}>
|
|
<input
|
|
disabled={readOnly || disabled}
|
|
name={name}
|
|
id={name}
|
|
onChange={onInputChange}
|
|
onFocus={onFocus}
|
|
onBlur={onBlur}
|
|
className={inputClasses}
|
|
placeholder={placeholder}
|
|
ref={(r) => {
|
|
this.input = r;
|
|
}}
|
|
type={type}
|
|
{...inputOptions}
|
|
value={value}
|
|
autoComplete={blockAutoComplete ? "new-password" : ""}
|
|
data-1p-ignore={ignore1password}
|
|
/>
|
|
|
|
{enableCopy && this.renderCopyButton()}
|
|
</div>
|
|
</FormField>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default InputField;
|