@gravity-ui/graph
Version:
Modern graph editor component
143 lines (142 loc) • 5.32 kB
JavaScript
import { batch, computed, signal } from "@preact/signals-core";
import groupBy from "lodash/groupBy";
import { ESelectionStrategy } from "../../utils/types/types";
import { GroupState } from "./Group";
export class GroupsListStore {
constructor(rootStore, graph) {
this.rootStore = rootStore;
this.graph = graph;
this.$groupsMap = signal(new Map());
this.$groups = computed(() => {
return Array.from(this.$groupsMap.value.values());
});
this.$blockGroups = computed(() => {
return groupBy(this.rootStore.blocksList.$blocks.value, (item) => item.$state.value.group);
});
this.$selectedGroups = computed(() => {
return this.$groups.value.filter((group) => group.selected);
});
}
updateGroupsMap(groups) {
this.$groupsMap.value = new Map(groups);
}
addGroup(group) {
this.$groupsMap.value.set(group.id, this.getOrCreateGroupState(group));
this.updateGroupsMap(this.$groupsMap.value);
return group.id;
}
deleteGroups(groups) {
const map = new Map(this.$groupsMap.value);
groups.forEach((gId) => {
const id = typeof gId === "string" ? gId : gId.id;
map.delete(id);
});
this.updateGroupsMap(map);
}
updateGroups(groups) {
this.updateGroupsMap(groups.reduce((acc, group) => {
const state = this.getOrCreateGroupState(group);
acc.set(group.id, state);
return acc;
}, this.$groupsMap.value));
}
setGroups(groups) {
const groupStates = groups.map((group) => this.getOrCreateGroupState(group));
this.applyGroupsState(groupStates);
}
getOrCreateGroupState(group) {
const groupState = this.$groupsMap.value.get(group.id);
if (groupState) {
groupState.updateGroup(group);
return groupState;
}
return GroupState.fromTGroup(this, group);
}
applyGroupsState(groups) {
this.updateGroupsMap(groups.map((group) => [group.id, group]));
}
getGroupState(id) {
return this.$groupsMap.value.get(id);
}
getGroup(id) {
return this.getGroupState(id)?.asTGroup();
}
reset() {
this.applyGroupsState([]);
}
toJSON() {
return this.$groups.value.map((group) => group.asTGroup());
}
setGroupSelection(group, selected, params) {
const groupState = group instanceof GroupState ? group : this.$groupsMap.value.get(group);
if (!groupState) {
return false;
}
if (selected !== Boolean(groupState.selected)) {
if (!params?.ignoreChanges) {
groupState.updateGroup({ selected });
}
return true;
}
return false;
}
computeSelectionChange(ids, selected, strategy = ESelectionStrategy.REPLACE) {
const list = new Set(this.$selectedGroups.value);
let add;
let removed;
if (!selected) {
removed = new Set(this.getGroupStates(ids).filter((group) => {
if (this.setGroupSelection(group.id, false, { ignoreChanges: true })) {
list.delete(group);
return true;
}
return false;
}));
}
else {
if (strategy === ESelectionStrategy.REPLACE) {
removed = new Set(this.$selectedGroups.value.filter((group) => {
return this.setGroupSelection(group.id, false, { ignoreChanges: true });
}));
list.clear();
}
add = new Set(this.getGroupStates(ids).filter((group) => {
if (this.setGroupSelection(group.id, true, { ignoreChanges: true }) ||
strategy === ESelectionStrategy.REPLACE) {
removed?.delete(group);
list.add(group);
return true;
}
return false;
}));
}
return { add: Array.from(add || []), removed: Array.from(removed || []), list: Array.from(list) };
}
updateGroupsSelection(ids, selected, strategy = ESelectionStrategy.REPLACE) {
const { add, removed, list } = this.computeSelectionChange(ids, selected, strategy);
if (add.length || removed.length) {
this.graph.executеDefaultEventAction("groups-selection-change", {
list: list.map((group) => group.id),
changes: {
add: add.map((group) => group.id),
removed: removed.map((group) => group.id),
},
}, () => {
batch(() => {
removed.forEach((group) => {
this.setGroupSelection(group.id, false);
});
add.forEach((group) => {
this.setGroupSelection(group.id, true);
});
});
});
}
}
resetSelection() {
this.updateGroupsSelection(this.$selectedGroups.value.map((group) => group.id), false);
}
getGroupStates(ids) {
return ids.map((id) => this.getGroupState(id)).filter(Boolean);
}
}