@sanity/desk-tool
Version:
Tool for managing all sorts of content in a structured manner
184 lines (180 loc) • 9.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.resolveIntent = resolveIntent;
var _omit2 = _interopRequireDefault(require("lodash/omit"));
var _operators = require("rxjs/operators");
var _assignId = require("./assignId");
var _createPaneResolver = require("./createPaneResolver");
var _loadStructure = require("./loadStructure");
var _memoBind = require("./memoBind");
var _excluded = ["id", "type"];
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } /* eslint-disable complexity */
/**
* Resolves an intent request using breadth first search. If a match is not
* found, the intent will resolve to the fallback editor.
*
* A match is found if:
* 1. the `PaneNode` is of type `document` and the its ID matches the intent ID
* 2. the `PaneNode` is of type `documentList` and the `schemaTypeName` matches
* 3. the `PaneNode`'s `canHandleIntent` method returns true
*
* If a `PaneNode` of type `list` is found, it will be searched for a match.
*
* @see PaneNode
*/
function resolveIntent(_x) {
return _resolveIntent.apply(this, arguments);
}
function _resolveIntent() {
_resolveIntent = _asyncToGenerator(function* (options) {
var resolvedPaneCache = new Map();
// this is a simple version of the memoizer in `createResolvedPaneNodeStream`
var memoize = nextFn => (unresolvedPane, context, flatIndex) => {
var key = unresolvedPane && "".concat((0, _assignId.assignId)(unresolvedPane), "-").concat(context.path.join('__'));
var cachedResolvedPane = key && resolvedPaneCache.get(key);
if (cachedResolvedPane) return cachedResolvedPane;
var result = nextFn(unresolvedPane, context, flatIndex);
if (key) resolvedPaneCache.set(key, result);
return result;
};
var resolvePane = (0, _createPaneResolver.createPaneResolver)(memoize);
var fallbackEditorPanes = [[{
id: "__edit__".concat(options.params.id),
params: _objectSpread(_objectSpread({}, (0, _omit2.default)(options.params, ['id'])), {}, {
type: options.params.type
}),
payload: options.payload
}]];
function traverse(_x2) {
return _traverse.apply(this, arguments);
}
function _traverse() {
_traverse = _asyncToGenerator(function* (_ref) {
var _resolvedPane$canHand;
var currentId = _ref.currentId,
flatIndex = _ref.flatIndex,
intent = _ref.intent,
params = _ref.params,
parent = _ref.parent,
path = _ref.path,
payload = _ref.payload,
unresolvedPane = _ref.unresolvedPane,
levelIndex = _ref.levelIndex;
if (!unresolvedPane) return [];
var targetId = params.id,
schemaTypeName = params.type,
otherParams = _objectWithoutProperties(params, _excluded);
var context = {
id: currentId,
splitIndex: 0,
parent,
path,
index: flatIndex,
params: {},
payload: undefined
};
var resolvedPane = yield resolvePane(unresolvedPane, context, flatIndex).pipe((0, _operators.first)()).toPromise();
// if the resolved pane is a document pane and the pane's ID matches then
// resolve the intent to the current path
if (resolvedPane.type === 'document' && resolvedPane.id === targetId) {
return [{
panes: [...path.slice(0, path.length - 1).map(i => [{
id: i
}]), [{
id: targetId,
params: otherParams,
payload
}]],
depthIndex: path.length,
levelIndex
}];
}
// NOTE: if you update this logic, please also update the similar handler in
// `getIntentState.ts`
if (
// if the resolve pane's `canHandleIntent` returns true, then resolve
(_resolvedPane$canHand = resolvedPane.canHandleIntent) !== null && _resolvedPane$canHand !== void 0 && _resolvedPane$canHand.call(resolvedPane, intent, params, {
pane: resolvedPane,
index: flatIndex
}) ||
// if the pane's `canHandleIntent` did not return true, then match against
// this default case. we will resolve the intent if:
resolvedPane.type === 'documentList' &&
// 1. the schema type matches (this required for the document to render)
resolvedPane.schemaTypeName === schemaTypeName &&
// 2. the filter is the default filter.
//
// NOTE: this case is to prevent false positive matches where the user
// has configured a more specific filter for a particular type. In that
// case, the user can implement their own `canHandleIntent` function
resolvedPane.options.filter === '_type == $type') {
return [{
panes: [
// map the current path to router panes
...path.map(id => [{
id
}]),
// then augment with the intents IDs and params
[{
id: params.id,
params: otherParams,
payload
}]],
depthIndex: path.length,
levelIndex
}];
}
if (resolvedPane.type === 'list' && resolvedPane.child && resolvedPane.items) {
return (yield Promise.all(resolvedPane.items.map((item, nextLevelIndex) => {
if (item.type === 'divider') return Promise.resolve([]);
return traverse({
currentId: item._id || item.id,
flatIndex: flatIndex + 1,
intent,
params,
parent: resolvedPane,
path: [...path, item.id],
payload,
unresolvedPane: typeof resolvedPane.child === 'function' ? (0, _memoBind.memoBind)(resolvedPane, 'child') : resolvedPane.child,
levelIndex: nextLevelIndex
});
}))).flat();
}
return [];
});
return _traverse.apply(this, arguments);
}
var matchingPanes = yield traverse({
currentId: 'root',
flatIndex: 0,
levelIndex: 0,
intent: options.intent,
params: options.params,
parent: null,
path: [],
payload: options.payload,
unresolvedPane: options.rootPaneNode || (0, _loadStructure.loadStructure)()
});
var closestPaneToRoot = matchingPanes.sort((a, b) => {
// break ties with the level index
if (a.depthIndex === b.depthIndex) return a.levelIndex - b.levelIndex;
return a.depthIndex - b.depthIndex;
})[0];
if (closestPaneToRoot) {
return closestPaneToRoot.panes;
}
return fallbackEditorPanes;
});
return _resolveIntent.apply(this, arguments);
}