import { getRoot, protect, types, unprotect } from "mobx-state-tree";
|
import ProcessAttrsMixin from "./ProcessAttrs";
|
import { parseValue } from "../utils/data";
|
import { guidGenerator } from "../utils/unique";
|
import { FF_DEV_3391 } from "../utils/feature-flags";
|
import { ff } from "@humansignal/core";
|
|
const DynamicChildrenMixin = types
|
.model({})
|
.views(() => ({
|
get defaultChildType() {
|
console.error("DynamicChildrenMixin needs to implement defaultChildType getter in views");
|
return undefined;
|
},
|
}))
|
.actions((self) => {
|
const prepareDynamicChildrenData = (data, store, parent) => {
|
// Right now with the FF on, we are traverseing the Tree in the store::initRoot and the
|
// AnnotationStore::afterCreate which will generate duplicated children so we only need to
|
// run this once, when the annotation store is not yet initialized
|
if (ff.isActive(FF_DEV_3391) && store.annotationStore.initialized) return;
|
|
if (data && data.length) {
|
for (const obj of data) {
|
// No matter if using Interactive View mode or not, we add the ids for consistency
|
const id = obj.id ?? guidGenerator();
|
parent.children.push({
|
type: self.defaultChildType,
|
...obj,
|
id,
|
children: [],
|
});
|
|
const child = parent.children[parent.children.length - 1];
|
|
child.updateValue?.(store);
|
prepareDynamicChildrenData(obj.children, store, child);
|
}
|
}
|
};
|
|
const postprocessDynamicChildren = (children, store) => {
|
children?.forEach((item) => {
|
postprocessDynamicChildren(item.children, store);
|
item.updateValue?.(store);
|
});
|
};
|
|
return {
|
updateWithDynamicChildren(data, store) {
|
const root = getRoot(self);
|
|
self.children = self.children ?? [];
|
|
unprotect(root);
|
prepareDynamicChildrenData(data, store, self);
|
protect(root);
|
},
|
|
updateValue(store) {
|
// If we want to use resolveValue or another asynchronous method here
|
// we may need to rewrite this, initRoot and the other related methods
|
// (actually a lot of them) to work asynchronously as well
|
|
if (ff.isActive(FF_DEV_3391)) {
|
self.updateDynamicChildren(store);
|
} else {
|
setTimeout(() => {
|
self.updateDynamicChildren(store);
|
});
|
}
|
},
|
|
updateDynamicChildren(store) {
|
if (self.locked !== true) {
|
const valueFromTask = parseValue(self.value, store.task?.dataObj);
|
|
if (!valueFromTask) return;
|
|
self.updateWithDynamicChildren(valueFromTask, store);
|
if (self.annotation) {
|
self.annotation.setupHotKeys();
|
self.needsUpdate?.();
|
}
|
}
|
},
|
|
generateDynamicChildren(data, store) {
|
if (self.children) {
|
const children = self.children;
|
const len = children.length;
|
const start = len - data.length;
|
const slice = children.slice(start, len);
|
|
postprocessDynamicChildren(slice, store);
|
}
|
},
|
};
|
});
|
|
export default types.compose(ProcessAttrsMixin, DynamicChildrenMixin);
|