box-ui-elements
Version:
Box UI Elements
449 lines (444 loc) • 19.8 kB
JavaScript
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
import * as React from 'react';
import noop from 'lodash/noop';
import { FormattedMessage, injectIntl } from 'react-intl';
import PlainButton from '../../components/plain-button';
import Button from '../../components/button';
import GuideTooltip from '../../components/guide-tooltip';
import TextInputWithCopyButton from '../../components/text-input-with-copy-button';
import Toggle from '../../components/toggle/Toggle';
import Tooltip from '../../components/tooltip';
import { convertToMs } from '../../utils/datetime';
import IconMail from '../../icons/general/IconMail';
import IconClock from '../../icons/general/IconClock';
import IconGlobe from '../../icons/general/IconGlobe';
import { bdlWatermelonRed } from '../../styles/variables';
import { isBoxNote } from '../../utils/file';
import Browser from '../../utils/Browser';
import convertToBoxItem from './utils/item';
import SharedLinkAccessMenu from './SharedLinkAccessMenu';
import SharedLinkPermissionMenu from './SharedLinkPermissionMenu';
import messages from './messages';
import { ANYONE_IN_COMPANY, ANYONE_WITH_LINK, CAN_EDIT, CAN_VIEW_DOWNLOAD, CAN_VIEW_ONLY, PEOPLE_IN_ITEM } from './constants';
class SharedLinkSection extends React.Component {
constructor(props) {
super(props);
_defineProperty(this, "canAddSharedLink", (isSharedLinkEnabled, canAddLink) => {
return !isSharedLinkEnabled && canAddLink;
});
_defineProperty(this, "canRemoveSharedLink", (isSharedLinkEnabled, canRemoveLink) => {
return isSharedLinkEnabled && canRemoveLink;
});
_defineProperty(this, "getAllowedPermissionLevels", () => {
const {
isAllowEditSharedLinkForFileEnabled,
sharedLink
} = this.props;
const {
canChangeAccessLevel,
isEditSettingAvailable,
isDownloadSettingAvailable,
permissionLevel
} = sharedLink;
let allowedPermissionLevels = [CAN_EDIT, CAN_VIEW_DOWNLOAD, CAN_VIEW_ONLY];
if (!canChangeAccessLevel) {
// remove all but current level
allowedPermissionLevels = allowedPermissionLevels.filter(level => level === permissionLevel);
}
// if we cannot set the download value, we remove this option from the dropdown
if (!isDownloadSettingAvailable) {
allowedPermissionLevels = allowedPermissionLevels.filter(level => level !== CAN_VIEW_DOWNLOAD);
}
// if the user cannot edit, we remove this option from the dropdown
if (!isEditSettingAvailable || !isAllowEditSharedLinkForFileEnabled) {
allowedPermissionLevels = allowedPermissionLevels.filter(level => level !== CAN_EDIT);
}
return allowedPermissionLevels;
});
this.state = {
isAutoCreatingSharedLink: false,
isCopySuccessful: null,
isSharedLinkEditTooltipShown: false
};
}
componentDidMount() {
const {
sharedLink,
autoCreateSharedLink,
addSharedLink,
submitting
} = this.props;
if (autoCreateSharedLink && !this.state.isAutoCreatingSharedLink && sharedLink && !sharedLink.url && !submitting && !sharedLink.isNewSharedLink) {
this.setState({
isAutoCreatingSharedLink: true
});
addSharedLink();
}
}
// We handle didUpdate but not didMount because
// the component initially renders with empty data
// in order to start showing UI components.
// When getInitialData completes in the parent we
// rerender with correct sharedLink data and can
// check whether to auto create a new one.
// Note: we are assuming the 2nd render is safe
// to start doing this check.
componentDidUpdate(prevProps) {
const {
sharedLink,
autoCreateSharedLink,
addSharedLink,
sharedLinkEditTooltipTargetingApi,
submitting,
triggerCopyOnLoad,
onCopyError = () => {},
onCopySuccess = () => {},
onCopyInit = () => {}
} = this.props;
const {
isAutoCreatingSharedLink,
isCopySuccessful,
isSharedLinkEditTooltipShown
} = this.state;
if (autoCreateSharedLink && !isAutoCreatingSharedLink && !sharedLink.url && !submitting && !sharedLink.isNewSharedLink) {
this.setState({
isAutoCreatingSharedLink: true
});
addSharedLink();
}
if (!prevProps.sharedLink.url && sharedLink.url) {
this.setState({
isAutoCreatingSharedLink: false
});
if (this.toggleRef) {
this.toggleRef.focus();
}
}
if (Browser.canWriteToClipboard() && triggerCopyOnLoad && !isAutoCreatingSharedLink && sharedLink.url && isCopySuccessful === null) {
onCopyInit();
navigator.clipboard.writeText(sharedLink.url).then(() => {
this.setState({
isCopySuccessful: true
});
onCopySuccess();
}).catch(() => {
this.setState({
isCopySuccessful: false
});
onCopyError();
});
}
// if ESL ftux tooltip is showing on initial mount, we call onShow
const allowedPermissionLevels = this.getAllowedPermissionLevels();
if (allowedPermissionLevels.includes(CAN_EDIT) && sharedLinkEditTooltipTargetingApi && sharedLinkEditTooltipTargetingApi.canShow && !isSharedLinkEditTooltipShown) {
const {
onShow
} = sharedLinkEditTooltipTargetingApi;
onShow();
this.setState({
isSharedLinkEditTooltipShown: true
});
}
}
renderSharedLink() {
const {
autofocusSharedLink,
changeSharedLinkAccessLevel,
changeSharedLinkPermissionLevel,
config,
item,
itemType,
intl,
onDismissTooltip,
onEmailSharedLinkClick,
sharedLink,
sharedLinkEditTagTargetingApi,
sharedLinkEditTooltipTargetingApi,
submitting,
trackingProps,
triggerCopyOnLoad,
tooltips
} = this.props;
const {
isCopySuccessful,
isSharedLinkEditTooltipShown
} = this.state;
const {
accessLevel,
accessLevelsDisabledReason,
allowedAccessLevels,
canChangeAccessLevel,
enterpriseName,
isEditAllowed,
permissionLevel,
url
} = sharedLink;
const {
copyButtonProps: copyButtonTrackingProps,
onChangeSharedLinkAccessLevel,
onChangeSharedLinkPermissionLevel,
onSharedLinkAccessMenuOpen,
onSharedLinkCopy = noop,
sendSharedLinkButtonProps,
sharedLinkAccessMenuButtonProps: sharedLinkAccessMenuButtonTrackingProps,
sharedLinkPermissionsMenuButtonProps: sharedLinkPermissionsMenuButtonTrackingProps
} = trackingProps;
const shouldTriggerCopyOnLoad = !!triggerCopyOnLoad && !!isCopySuccessful;
/**
* The email button should be rendered by default.
* Only hide the button if there is a config prop that declares showEmailSharedLinkForm to be false.
*/
const hideEmailButton = config && config.showEmailSharedLinkForm === false;
const isEditableBoxNote = isBoxNote(convertToBoxItem(item)) && isEditAllowed;
const allowedPermissionLevels = this.getAllowedPermissionLevels();
const copyButtonProps = _objectSpread(_objectSpread({}, copyButtonTrackingProps), {}, {
'data-target-id': 'Button-CopySharedLink'
});
const sharedLinkAccessMenuButtonProps = _objectSpread(_objectSpread({}, sharedLinkAccessMenuButtonTrackingProps), {}, {
'data-target-id': 'Button-SharedLinkAccessMenuLabel'
});
const sharedLinkPermissionsMenuButtonProps = _objectSpread(_objectSpread({}, sharedLinkPermissionsMenuButtonTrackingProps), {}, {
'data-target-id': 'Button-SharedLinkPermissionsMenuLabel'
});
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
className: "shared-link-field-row"
}, /*#__PURE__*/React.createElement(Tooltip, {
className: "usm-ftux-tooltip",
isShown: !!tooltips['shared-link-copy-button'],
onDismiss: () => onDismissTooltip('shared-link-copy-button'),
position: "middle-right",
showCloseButton: true,
text: tooltips['shared-link-copy-button'],
theme: "callout",
targetWrapperClassName: "shared-link-field-container-tooltip-wrapper"
}, /*#__PURE__*/React.createElement(TextInputWithCopyButton, {
"aria-label": intl.formatMessage(messages.sharedLinkURLLabel),
autofocus: autofocusSharedLink,
buttonProps: copyButtonProps,
className: "shared-link-field-container",
disabled: submitting,
label: "",
onCopySuccess: () => onSharedLinkCopy(permissionLevel),
triggerCopyOnLoad: shouldTriggerCopyOnLoad,
type: "url",
value: url
})), !hideEmailButton && /*#__PURE__*/React.createElement(Tooltip, {
position: "top-left",
text: intl.formatMessage(messages.sendSharedLink)
}, /*#__PURE__*/React.createElement(Button, _extends({
"aria-label": intl.formatMessage(messages.sendSharedLink),
className: "email-shared-link-btn",
"data-target-id": "Button-SendSharedLink",
isDisabled: submitting,
onClick: onEmailSharedLinkClick,
type: "button"
}, sendSharedLinkButtonProps), /*#__PURE__*/React.createElement(IconMail, null)))), /*#__PURE__*/React.createElement("div", {
className: "shared-link-access-row"
}, /*#__PURE__*/React.createElement(SharedLinkAccessMenu, {
accessLevel: accessLevel,
accessLevelsDisabledReason: accessLevelsDisabledReason,
allowedAccessLevels: allowedAccessLevels,
changeAccessLevel: changeSharedLinkAccessLevel,
enterpriseName: enterpriseName,
itemType: itemType,
onDismissTooltip: () => onDismissTooltip('shared-link-access-menu'),
tooltipContent: tooltips['shared-link-access-menu'] || null,
submitting: submitting,
trackingProps: {
onChangeSharedLinkAccessLevel,
onSharedLinkAccessMenuOpen,
sharedLinkAccessMenuButtonProps
}
}), !isEditableBoxNote && accessLevel !== PEOPLE_IN_ITEM && /*#__PURE__*/React.createElement(GuideTooltip, {
isShown: allowedPermissionLevels.includes(CAN_EDIT) && sharedLinkEditTooltipTargetingApi?.canShow,
title: intl.formatMessage(messages.ftuxEditPermissionTooltipTitle),
body: intl.formatMessage(messages.ftuxEditPermissionTooltipBody),
onDismiss: () => {
if (sharedLinkEditTooltipTargetingApi) {
const {
onClose
} = sharedLinkEditTooltipTargetingApi;
onClose();
}
},
position: "bottom-center"
}, /*#__PURE__*/React.createElement(SharedLinkPermissionMenu, {
allowedPermissionLevels: allowedPermissionLevels,
canChangePermissionLevel: canChangeAccessLevel,
changePermissionLevel: changeSharedLinkPermissionLevel,
isSharedLinkEditTooltipShown: isSharedLinkEditTooltipShown,
permissionLevel: permissionLevel,
sharedLinkEditTagTargetingApi: sharedLinkEditTagTargetingApi,
sharedLinkEditTooltipTargetingApi: sharedLinkEditTooltipTargetingApi,
submitting: submitting,
trackingProps: {
onChangeSharedLinkPermissionLevel,
sharedLinkPermissionsMenuButtonProps
}
})), isEditableBoxNote && /*#__PURE__*/React.createElement(Tooltip, {
text: intl.formatMessage(messages.sharedLinkPermissionsEditTooltip)
}, /*#__PURE__*/React.createElement(PlainButton, {
isDisabled: true,
className: "can-edit-btn"
}, /*#__PURE__*/React.createElement(FormattedMessage, messages.sharedLinkPermissionsEdit)))), accessLevel === ANYONE_WITH_LINK && /*#__PURE__*/React.createElement("div", {
className: "security-indicator-note"
}, /*#__PURE__*/React.createElement("span", {
className: "security-indicator-icon-globe"
}, /*#__PURE__*/React.createElement(IconGlobe, {
height: 12,
width: 12
})), permissionLevel === CAN_EDIT && /*#__PURE__*/React.createElement(FormattedMessage, _extends({
"data-testid": "shared-link-editable-publicly-available-message"
}, messages.sharedLinkEditablePubliclyAvailable)), permissionLevel !== CAN_EDIT && /*#__PURE__*/React.createElement(FormattedMessage, _extends({
"data-testid": "shared-link-publicly-available-message"
}, messages.sharedLinkPubliclyAvailable))), accessLevel === ANYONE_IN_COMPANY && permissionLevel === CAN_EDIT && /*#__PURE__*/React.createElement("div", {
className: "security-indicator-note"
}, /*#__PURE__*/React.createElement("span", {
className: "security-indicator-icon-globe"
}, /*#__PURE__*/React.createElement(IconGlobe, {
height: 12,
width: 12
})), /*#__PURE__*/React.createElement(FormattedMessage, _extends({
"data-testid": "shared-link-elevated-editable-company-available-message"
}, messages.sharedLinkElevatedEditableCompanyAvailable))));
}
renderSharedLinkSettingsLink() {
const {
intl,
onDismissTooltip,
onSettingsClick,
showSharedLinkSettingsCallout,
trackingProps,
tooltips
} = this.props;
const {
sharedLinkSettingsButtonProps
} = trackingProps;
return /*#__PURE__*/React.createElement("div", {
className: "shared-link-settings-btn-container"
}, /*#__PURE__*/React.createElement(Tooltip, {
className: "usm-ftux-tooltip",
isShown: !!tooltips['shared-link-settings'] || showSharedLinkSettingsCallout,
onDismiss: () => onDismissTooltip('shared-link-settings'),
position: "middle-right",
showCloseButton: true,
text: tooltips['shared-link-settings'] || intl.formatMessage(messages.sharedLinkSettingsCalloutText),
theme: "callout"
}, /*#__PURE__*/React.createElement(PlainButton, _extends({}, sharedLinkSettingsButtonProps, {
"aria-haspopup": "dialog",
className: "shared-link-settings-btn",
"data-target-id": "PlainButton-SharedLinkSettings",
onClick: onSettingsClick,
type: "button"
}), /*#__PURE__*/React.createElement(FormattedMessage, messages.sharedLinkSettings))));
}
renderToggle() {
const {
intl,
item,
onDismissTooltip,
onToggleSharedLink,
sharedLink,
submitting,
tooltips
} = this.props;
const {
canChangeAccessLevel,
expirationTimestamp,
url
} = sharedLink;
const isSharedLinkEnabled = !!url;
const canAddSharedLink = this.canAddSharedLink(isSharedLinkEnabled, item.grantedPermissions.itemShare);
const canRemoveSharedLink = this.canRemoveSharedLink(isSharedLinkEnabled, canChangeAccessLevel);
const isToggleEnabled = (canAddSharedLink || canRemoveSharedLink) && !submitting;
let linkText;
if (isSharedLinkEnabled) {
linkText = /*#__PURE__*/React.createElement(FormattedMessage, messages.linkShareOn);
if (expirationTimestamp && expirationTimestamp !== 0) {
linkText = /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(FormattedMessage, messages.linkShareOn), /*#__PURE__*/React.createElement(Tooltip, {
position: "top-center",
text: intl.formatMessage(messages.sharedLinkExpirationTooltip, {
expiration: convertToMs(expirationTimestamp)
})
}, /*#__PURE__*/React.createElement("span", {
"aria-label": intl.formatMessage(messages.expiresMessage),
className: "shared-link-expiration-badge",
role: "img"
}, /*#__PURE__*/React.createElement(IconClock, {
color: bdlWatermelonRed
}))));
}
} else {
linkText = /*#__PURE__*/React.createElement(FormattedMessage, messages.linkShareOff);
}
const toggleComponent = /*#__PURE__*/React.createElement(Toggle, {
"data-target-id": "Toggle-CreateSharedLink",
isDisabled: !isToggleEnabled,
isOn: isSharedLinkEnabled,
label: linkText,
name: "toggle",
onChange: onToggleSharedLink,
ref: ref => {
this.toggleRef = ref;
}
});
if (!submitting) {
if (canAddSharedLink) {
const sharedLinkToggleTooltip = tooltips['shared-link-toggle'];
if (sharedLinkToggleTooltip) {
return /*#__PURE__*/React.createElement(Tooltip, {
className: "usm-ftux-tooltip",
isShown: true,
onDismiss: () => onDismissTooltip('shared-link-toggle'),
position: "middle-left",
showCloseButton: true,
text: sharedLinkToggleTooltip,
theme: "callout"
}, toggleComponent);
}
return /*#__PURE__*/React.createElement(Tooltip, {
targetWrapperClassName: "usm-ftux-toggle-tooltip-target",
position: "top-right",
text: intl.formatMessage(messages.sharedLinkDisabledTooltipCopy)
}, toggleComponent);
}
if (!isToggleEnabled) {
const tooltipDisabledMessage = isSharedLinkEnabled ? messages.removeLinkTooltip : messages.disabledCreateLinkTooltip;
return /*#__PURE__*/React.createElement(Tooltip, {
className: "usm-disabled-message-tooltip",
position: "top-right",
text: intl.formatMessage(tooltipDisabledMessage)
}, toggleComponent);
}
}
return toggleComponent;
}
render() {
const {
sharedLink,
onSettingsClick
} = this.props;
const isSharedLinkEnabled = !!sharedLink.url;
return /*#__PURE__*/React.createElement("div", {
className: "be"
}, /*#__PURE__*/React.createElement("hr", {
className: "bdl-SharedLinkSection-separator"
}), /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("span", {
className: "label bdl-Label"
}, /*#__PURE__*/React.createElement(FormattedMessage, messages.sharedLinkSectionLabel))), /*#__PURE__*/React.createElement("div", {
className: "shared-link-toggle-row"
}, this.renderToggle(), isSharedLinkEnabled && onSettingsClick && this.renderSharedLinkSettingsLink()), isSharedLinkEnabled && this.renderSharedLink());
}
}
_defineProperty(SharedLinkSection, "defaultProps", {
trackingProps: {},
autoCreateSharedLink: false
});
export { SharedLinkSection as SharedLinkSectionBase };
export default injectIntl(SharedLinkSection);
//# sourceMappingURL=SharedLinkSection.js.map