box-ui-elements
Version:
Box UI Elements
255 lines (252 loc) • 8.66 kB
JavaScript
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); }
/**
*
* @file Skills sidebar component
* @author Box
*/
import * as React from 'react';
import flow from 'lodash/flow';
import getProp from 'lodash/get';
import noop from 'lodash/noop';
import { FormattedMessage } from 'react-intl';
import API from '../../api';
import LoadingIndicator from '../../components/loading-indicator/LoadingIndicator';
import messages from '../common/messages';
import SidebarContent from './SidebarContent';
import SidebarSkills from './skills/SidebarSkills';
import { EVENT_JS_READY } from '../common/logger/constants';
import { mark } from '../../utils/performance';
import { withAPIContext } from '../common/api-context';
import { withErrorBoundary } from '../common/error-boundary';
import { withLogger } from '../common/logger';
import { FIELD_PERMISSIONS_CAN_UPLOAD, SKILLS_TRANSCRIPT, ORIGIN_SKILLS_SIDEBAR, SIDEBAR_VIEW_SKILLS } from '../../constants';
import './SkillsSidebar.scss';
const MARK_NAME_JS_READY = `${ORIGIN_SKILLS_SIDEBAR}_${EVENT_JS_READY}`;
mark(MARK_NAME_JS_READY);
class SkillsSidebar extends React.PureComponent {
constructor(props) {
super(props);
_defineProperty(this, "state", {
errors: {}
});
/**
* Handles skills fetch success
*
* @private
* @param {Array<SkillCard>} cards - Skills cards
* @return {void}
*/
_defineProperty(this, "fetchSkillsSuccessCallback", cards => {
this.updatePreviewTranscript(cards);
this.setState({
cards
});
});
/**
* Updates Preview with transcript data
*
* @private
* @param {Array<SkillCard>} cards - Skills cards
* @return {void}
*/
_defineProperty(this, "updatePreviewTranscript", cards => {
const {
getPreview,
getViewer
} = this.props;
const preview = getPreview ? getPreview() : null;
const viewer = getViewer ? getViewer() : null;
const transcriptCard = cards.find(card => card.skill_card_type === SKILLS_TRANSCRIPT);
if (!transcriptCard || !preview) {
return;
}
if (!viewer) {
preview.addListener('load', ({
viewer: loadedViewer
}) => {
if (typeof loadedViewer.loadAutoGeneratedCaptions === 'function') {
loadedViewer.loadAutoGeneratedCaptions(transcriptCard);
}
});
} else if (typeof viewer.loadAutoGeneratedCaptions === 'function') {
viewer.loadAutoGeneratedCaptions(transcriptCard);
}
});
/**
* Success handler for save
*
* @private
* @param {Array} updatedCards - updated skill cards
* @param {number} index - index of the card being edited
* @return {void}
*/
_defineProperty(this, "onSaveSuccessHandler", (index, updatedCards) => {
const {
errors
} = this.state;
const clone = _objectSpread({}, errors);
delete clone[index];
this.updatePreviewTranscript(updatedCards);
this.setState({
cards: updatedCards,
errors: clone
});
});
/**
* Error handler for save
*
* @private
* @param {number} index - index of the card being edited
* @return {void}
*/
_defineProperty(this, "onSaveErrorHandler", index => {
const {
errors
} = this.state;
const clone = _objectSpread({}, errors);
clone[index] = true;
this.setState({
errors: clone
});
});
/**
* Updates skill metadata
*
* @private
* @param {number} index - index of the card being edited
* @param {Array} removes - entries to remove
* @param {Array} adds - entries to add
* @param {Array} replaces - entries to replace
* @return {void}
*/
_defineProperty(this, "onSave", (index, removes = [], adds = [], replaces = []) => {
const {
api,
file
} = this.props;
const {
cards = []
} = this.state;
const card = cards[index];
const path = `/cards/${index}`;
const ops = [];
const canEdit = getProp(file, FIELD_PERMISSIONS_CAN_UPLOAD, false);
if (!canEdit || !card) {
return;
}
if (Array.isArray(replaces)) {
replaces.forEach(({
replaced,
replacement
}) => {
const idx = card.entries.findIndex(entry => entry === replaced);
if (idx > -1) {
ops.push({
op: 'replace',
path: `${path}/entries/${idx}`,
value: replacement
});
}
});
}
if (Array.isArray(removes)) {
const deletes = [];
removes.forEach(removed => {
const idx = card.entries.findIndex(entry => entry === removed);
if (idx > -1) {
deletes.push(idx);
}
});
// To maintain metadata index positions, removes should be
// done is reverse order with largest index being removed first.
// Remove operations are atomic and don't happen in batch.
deletes.sort((a, b) => b - a) // number sort in descending order
.forEach(idx => {
ops.push({
op: 'remove',
path: `${path}/entries/${idx}`
});
});
}
if (Array.isArray(adds)) {
adds.forEach(added => {
ops.push({
op: 'add',
path: `${path}/entries/-`,
value: added
});
});
}
// If no ops, don't proceed
if (ops.length === 0) {
return;
}
// Add test ops before any other ops
ops.splice(0, 0, {
op: 'test',
path,
value: card
});
api.getMetadataAPI(false).updateSkills(file, ops, updatedCards => {
this.onSaveSuccessHandler(index, updatedCards);
}, () => {
this.onSaveErrorHandler(index);
});
});
const {
logger
} = this.props;
logger.onReadyMetric({
endMarkName: MARK_NAME_JS_READY
});
}
componentDidMount() {
const {
api,
file
} = this.props;
api.getMetadataAPI(false).getSkills(file, this.fetchSkillsSuccessCallback, noop);
}
componentDidUpdate({
refreshIdentity: prevRefreshIdentity
}) {
const {
api,
file,
refreshIdentity
} = this.props;
if (refreshIdentity !== prevRefreshIdentity) {
api.getMetadataAPI(false).getSkills(file, this.fetchSkillsSuccessCallback, noop);
}
}
render() {
const {
file,
getViewer,
elementId
} = this.props;
const {
cards,
errors
} = this.state;
return /*#__PURE__*/React.createElement(SidebarContent, {
className: "bcs-skills",
elementId: elementId,
sidebarView: SIDEBAR_VIEW_SKILLS,
title: /*#__PURE__*/React.createElement(FormattedMessage, messages.sidebarSkillsTitle)
}, cards ? /*#__PURE__*/React.createElement(SidebarSkills, {
cards: cards,
errors: errors,
file: file,
getViewer: getViewer,
onSkillChange: this.onSave
}) : /*#__PURE__*/React.createElement(LoadingIndicator, null));
}
}
export { SkillsSidebar as SkillsSidebarComponent };
export default flow([withLogger(ORIGIN_SKILLS_SIDEBAR), withErrorBoundary(ORIGIN_SKILLS_SIDEBAR), withAPIContext])(SkillsSidebar);
//# sourceMappingURL=SkillsSidebar.js.map