@orfeas126/box-ui-elements
Version:
Box UI Elements
329 lines (321 loc) • 11.3 kB
JavaScript
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); }
/**
*
* @file Content Sidebar Component
* @author Box
*/
import * as React from 'react';
import classNames from 'classnames';
import flow from 'lodash/flow';
import getProp from 'lodash/get';
import noop from 'lodash/noop';
import uniqueid from 'lodash/uniqueId';
import { withRouter } from 'react-router-dom';
import LoadingIndicator from '../../components/loading-indicator/LoadingIndicator';
import LocalStore from '../../utils/LocalStore';
import SidebarNav from './SidebarNav';
import SidebarPanels from './SidebarPanels';
import SidebarUtils from './SidebarUtils';
import { withCurrentUser } from '../common/current-user';
import { isFeatureEnabled, withFeatureConsumer } from '../common/feature-checking';
import { SIDEBAR_VIEW_DOCGEN } from '../../constants';
import API from '../../api';
export const SIDEBAR_FORCE_KEY = 'bcs.force';
export const SIDEBAR_FORCE_VALUE_CLOSED = 'closed';
export const SIDEBAR_FORCE_VALUE_OPEN = 'open';
export const SIDEBAR_SELECTED_PANEL_KEY = 'sidebar-selected-panel';
class Sidebar extends React.Component {
constructor(props) {
super(props);
_defineProperty(this, "id", uniqueid('bcs_'));
_defineProperty(this, "sidebarPanels", /*#__PURE__*/React.createRef());
_defineProperty(this, "store", new LocalStore());
_defineProperty(this, "handleDocgenTemplateOnUpdate", prevProps => {
const {
history,
location,
file,
api,
metadataSidebarProps,
docGenSidebarProps
} = this.props;
const {
file: prevFile,
docGenSidebarProps: prevDocGenSidebarProps
} = prevProps;
// need to re-check if file is a docgen-template on file change
if (file.id !== prevFile.id && docGenSidebarProps.enabled && docGenSidebarProps.checkDocGenTemplate) {
docGenSidebarProps.checkDocGenTemplate(api, file, metadataSidebarProps.isFeatureEnabled);
}
// if file turns out to be a docgen template
if (docGenSidebarProps.enabled && prevDocGenSidebarProps.isDocGenTemplate !== docGenSidebarProps.isDocGenTemplate) {
if (docGenSidebarProps.isDocGenTemplate) {
// navigate to docgen tab
history.push(`/${SIDEBAR_VIEW_DOCGEN}`);
} else if (location.pathname === `/${SIDEBAR_VIEW_DOCGEN}`) {
history.push('/');
}
}
});
_defineProperty(this, "getUrlPrefix", pathname => {
const basePath = pathname.substring(1).split('/')[0];
return basePath;
});
/**
* Handle version history click
*
* @param {SyntheticEvent} event - The event
* @return {void}
*/
_defineProperty(this, "handleVersionHistoryClick", event => {
const {
file,
history
} = this.props;
const {
file_version: currentVersion
} = file;
const fileVersionSlug = currentVersion ? `/${currentVersion.id}` : '';
const urlPrefix = this.getUrlPrefix(history.location.pathname);
if (event.preventDefault) {
event.preventDefault();
}
history.push(`/${urlPrefix}/versions${fileVersionSlug}`);
});
_defineProperty(this, "handlePanelChange", name => {
const {
features,
onPanelChange = noop
} = this.props;
if (isFeatureEnabled(features, 'panelSelectionPreservation')) {
this.store.setItem(SIDEBAR_SELECTED_PANEL_KEY, name);
}
onPanelChange(name);
});
this.state = {
isDirty: this.getLocationState('open') || false
};
this.setForcedByLocation();
}
componentDidMount() {
const {
file,
api,
metadataSidebarProps,
docGenSidebarProps
} = this.props;
// if docgen feature is enabled, load metadata to check whether file is a docgen template
if (docGenSidebarProps.enabled) {
docGenSidebarProps.checkDocGenTemplate(api, file, metadataSidebarProps.isFeatureEnabled);
}
}
componentDidUpdate(prevProps) {
const {
fileId,
history,
location,
onOpenChange = noop
} = this.props;
const {
fileId: prevFileId,
location: prevLocation
} = prevProps;
const {
isDirty
} = this.state;
// User navigated to a different file without ever navigating the sidebar
if (!isDirty && fileId !== prevFileId && location.pathname !== '/') {
history.replace({
pathname: '/',
state: {
silent: true
}
});
}
// User navigated or toggled the sidebar intentionally, internally or externally
if (location !== prevLocation && !this.getLocationState('silent')) {
this.setForcedByLocation();
this.setState({
isDirty: true
});
const openState = this.getLocationState('open');
// Check if the sidebar was expanded / collapsed
if (prevLocation.state?.open !== openState) {
onOpenChange(openState);
}
}
this.handleDocgenTemplateOnUpdate(prevProps);
}
/**
* Getter for location state properties.
*
* NOTE: Each location on the history stack has its own optional state object that is wholly separate from
* this component's internal state. Values on the location state object can persist even between refreshes
* when using certain history contexts, such as BrowserHistory.
*
* @param key - Optionally get a specific key value from state
* @returns {any} - The location state or state key value
*/
getLocationState(key) {
const {
location
} = this.props;
const {
state: locationState = {}
} = location;
return getProp(locationState, key);
}
/**
* Getter/setter for sidebar forced state
*
* @param isOpen - Optionally set the sidebar to open/closed
* @returns {string|null} - The sidebar open/closed state
*/
isForced(isOpen) {
if (isOpen !== undefined) {
this.store.setItem(SIDEBAR_FORCE_KEY, isOpen ? SIDEBAR_FORCE_VALUE_OPEN : SIDEBAR_FORCE_VALUE_CLOSED);
}
return this.store.getItem(SIDEBAR_FORCE_KEY);
}
/**
* Getter for whether the sidebar has been forced open
* @returns {boolean} - True if the sidebar has been forced open
*/
isForcedOpen() {
return this.isForced() === SIDEBAR_FORCE_VALUE_OPEN;
}
/**
* Getter for whether the sidebar has been forced open/closed previously
* @returns {boolean} - True if the sidebar has been forced open/closed previously
*/
isForcedSet() {
return this.isForced() !== null;
}
/**
* Refreshes the sidebar panel
* @returns {void}
*/
refresh(shouldRefreshCache = true) {
const {
current: sidebarPanels
} = this.sidebarPanels;
if (sidebarPanels) {
sidebarPanels.refresh(shouldRefreshCache);
}
}
/**
* Helper to set the local store open state based on the location open state, if defined
*/
setForcedByLocation() {
const isLocationOpen = this.getLocationState('open');
if (isLocationOpen !== undefined && isLocationOpen !== null) {
this.isForced(isLocationOpen);
}
}
getDefaultPanel() {
const {
features
} = this.props;
if (!isFeatureEnabled(features, 'panelSelectionPreservation')) {
return undefined;
}
return this.store.getItem(SIDEBAR_SELECTED_PANEL_KEY) || undefined;
}
render() {
const {
activitySidebarProps,
additionalTabs,
boxAISidebarProps,
className,
currentUser,
currentUserError,
detailsSidebarProps,
docGenSidebarProps,
file,
fileId,
getPreview,
getViewer,
hasAdditionalTabs,
hasNav,
hasVersions,
isDefaultOpen,
isLoading,
metadataEditors,
metadataSidebarProps,
onAnnotationSelect,
onVersionChange,
versionsSidebarProps
} = this.props;
const isOpen = this.isForcedSet() ? this.isForcedOpen() : !!isDefaultOpen;
const hasBoxAI = SidebarUtils.canHaveBoxAISidebar(this.props);
const hasActivity = SidebarUtils.canHaveActivitySidebar(this.props);
const hasDetails = SidebarUtils.canHaveDetailsSidebar(this.props);
const hasMetadata = SidebarUtils.shouldRenderMetadataSidebar(this.props, metadataEditors);
const hasSkills = SidebarUtils.shouldRenderSkillsSidebar(this.props, file);
const onVersionHistoryClick = hasVersions ? this.handleVersionHistoryClick : this.props.onVersionHistoryClick;
const styleClassName = classNames('be bcs', className, {
'bcs-is-open': isOpen
});
const defaultPanel = this.getDefaultPanel();
return /*#__PURE__*/React.createElement("aside", {
id: this.id,
className: styleClassName,
"data-testid": "preview-sidebar"
}, isLoading ? /*#__PURE__*/React.createElement("div", {
className: "bcs-loading"
}, /*#__PURE__*/React.createElement(LoadingIndicator, null)) : /*#__PURE__*/React.createElement(React.Fragment, null, hasNav && /*#__PURE__*/React.createElement(SidebarNav, {
additionalTabs: additionalTabs,
elementId: this.id,
fileId: fileId,
hasActivity: hasActivity,
hasAdditionalTabs: hasAdditionalTabs,
hasBoxAI: hasBoxAI,
hasDetails: hasDetails,
hasMetadata: hasMetadata,
hasSkills: hasSkills,
hasDocGen: docGenSidebarProps.isDocGenTemplate,
isOpen: isOpen,
onPanelChange: this.handlePanelChange
}), /*#__PURE__*/React.createElement(SidebarPanels, {
activitySidebarProps: activitySidebarProps,
boxAISidebarProps: boxAISidebarProps,
currentUser: currentUser,
currentUserError: currentUserError,
elementId: this.id,
defaultPanel: defaultPanel,
detailsSidebarProps: detailsSidebarProps,
docGenSidebarProps: docGenSidebarProps,
file: file,
fileId: fileId,
getPreview: getPreview,
getViewer: getViewer,
hasActivity: hasActivity,
hasBoxAI: hasBoxAI,
hasDetails: hasDetails,
hasDocGen: docGenSidebarProps.isDocGenTemplate,
hasMetadata: hasMetadata,
hasSkills: hasSkills,
hasVersions: hasVersions,
isOpen: isOpen,
key: file.id,
metadataSidebarProps: metadataSidebarProps,
onAnnotationSelect: onAnnotationSelect,
onVersionChange: onVersionChange,
onVersionHistoryClick: onVersionHistoryClick,
ref: this.sidebarPanels,
versionsSidebarProps: versionsSidebarProps
})));
}
}
_defineProperty(Sidebar, "defaultProps", {
annotatorState: {},
isDefaultOpen: true,
isLoading: false,
getAnnotationsMatchPath: noop,
getAnnotationsPath: noop
});
export { Sidebar as SidebarComponent };
export default flow([withCurrentUser, withFeatureConsumer, withRouter])(Sidebar);
//# sourceMappingURL=Sidebar.js.map