Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persist skeleton group expansion state #7939

Merged
merged 28 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
dc16ee2
move skeleton expanded/collapsed group state to store
dieknolle3333 Jul 24, 2024
3fb992a
WIP: expand and collapse all skeleton groups
dieknolle3333 Jul 24, 2024
e190aca
fix expand/collapse skeleton groups
dieknolle3333 Jul 24, 2024
f5c9e31
expand group if tree is dropped
dieknolle3333 Jul 24, 2024
b5c055b
clean up code
dieknolle3333 Jul 24, 2024
0a7badd
lint
dieknolle3333 Jul 24, 2024
71d1c96
address review
dieknolle3333 Jul 24, 2024
860c9ff
address review 2/2
dieknolle3333 Jul 24, 2024
812dccf
remove console.log
dieknolle3333 Jul 24, 2024
679c3e9
lint
dieknolle3333 Jul 24, 2024
95e4925
add small condition for ondrop
dieknolle3333 Jul 24, 2024
aa94946
persist isExpanded state in backend
MichaelBuessemeyer Jul 25, 2024
c836384
make groups default expanded if field is absent in nml (backend only)
MichaelBuessemeyer Jul 29, 2024
db947c5
make groups default expanded if for written nmls (backend only)
MichaelBuessemeyer Jul 29, 2024
25d73ef
fix backend treegroup update action tests
MichaelBuessemeyer Jul 30, 2024
c9efab3
Merge branch 'master' of github.com:scalableminds/webknossos into mov…
MichaelBuessemeyer Jul 30, 2024
2aa32d8
add isExpanded to frontend nml support
dieknolle3333 Jul 30, 2024
0d80108
update snapshots
dieknolle3333 Jul 30, 2024
69caff3
omit object creation in var
dieknolle3333 Jul 30, 2024
c3be6f5
omit useless return statement in map
dieknolle3333 Jul 30, 2024
8312446
add isExpanded prop to tree groups in backend testing fixtures (dummies)
MichaelBuessemeyer Jul 30, 2024
a4656fe
add test to backend nml test to test properly setting default to expa…
MichaelBuessemeyer Jul 30, 2024
0094a25
Merge branch 'move-skeleton-expansion-to-store' of github.com:scalabl…
MichaelBuessemeyer Jul 30, 2024
e0f1f50
add changelog
dieknolle3333 Jul 31, 2024
d9c32be
Merge branch 'tree-tree' of github.com:scalableminds/webknossos into …
philippotto Jul 31, 2024
5e4c06d
WIP: address review
dieknolle3333 Jul 31, 2024
c8ae492
fix bug where drag and drop of empty groups was failing
dieknolle3333 Aug 1, 2024
f07db71
remove comment
dieknolle3333 Aug 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/javascripts/oxalis/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export type Tree = {
export type TreeGroupTypeFlat = {
readonly name: string;
readonly groupId: number;
readonly isExpanded?: boolean;
};
export type TreeGroup = TreeGroupTypeFlat & {
readonly children: TreeGroup[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,11 @@ class SkeletonTabView extends React.PureComponent<Props, State> {
getTreeAndTreeGroupList = memoizeOne(
(trees: TreeMap, treeGroups: Array<TreeGroup>, sortBy: string): Array<TreeOrTreeGroup> => {
const groupToTreesMap = createGroupToTreesMap(trees);
const rootGroup = {
const rootGroup: TreeGroup = {
name: "Root",
groupId: MISSING_GROUP_ID,
children: treeGroups,
isExpanded: true,
};

const makeTree = (tree: Tree) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import {
GroupTypeEnum,
deepFlatFilter,
getNodeKey,
getNodeKeyFromNode,
moveGroupsHelper,
findParentGroupNode,
} from "oxalis/view/right-border-tabs/tree_hierarchy_view_helpers";
Expand All @@ -69,8 +68,8 @@ import { formatNumberToLength, formatLengthAsVx } from "libs/format_utils";
import { api, Store } from "oxalis/singletons";
import { ChangeColorMenuItemContent } from "components/color_picker";
import { HideTreeEdgesIcon } from "./hide_tree_eges_icon";
import { useEffectOnlyOnce } from "libs/react_hooks";
import { ColoredDotIcon } from "./segments_tab/segment_list_item";
import { mapGroups } from "oxalis/model/accessors/skeletontracing_accessor";

type Props = {
activeTreeId: number | null | undefined;
Expand Down Expand Up @@ -106,25 +105,20 @@ function TreeHierarchyView(props: Props) {
name: "Root",
groupId: MISSING_GROUP_ID,
children: props.treeGroups,
isExpanded: true,
};

const generatedGroupTree = insertTreesAndTransform([rootGroup], groupToTreesMap, props.sortBy);
setUITreeData(generatedGroupTree);
}, [props.trees, props.sortBy, props.treeGroups]);

useEffectOnlyOnce(() => {
// set default expanded keys
// the defaults should include the root node and at the active tree's group if applicable
let defaultExpandedKeys: React.Key[] = [getNodeKey(GroupTypeEnum.GROUP, MISSING_GROUP_ID)];
if (props.activeTreeId) {
const activeTreesGroupId = props.trees[props.activeTreeId].groupId;
if (activeTreesGroupId) {
defaultExpandedKeys.push(getNodeKey(GroupTypeEnum.GROUP, activeTreesGroupId));
}

setExpandedNodeKeys(defaultExpandedKeys);
}
});
useEffect(() => {
const expandedKeys = deepFlatFilter(
UITreeData,
(node) => node.type === GroupTypeEnum.GROUP && node.expanded,
).map((node) => node.key);
setExpandedNodeKeys(expandedKeys);
}, [UITreeData]);

useEffect(() => {
// scroll to active tree if it changes
Expand All @@ -148,17 +142,25 @@ function TreeHierarchyView(props: Props) {

const onExpand: TreeProps<TreeNode>["onExpand"] = (expandedKeys, info) => {
const clickedNode = info.node;
const expandedKeySet = new Set(expandedKeys);

if (clickedNode.type === GroupTypeEnum.GROUP && info.expanded === false) {
// when collapsing a group, we need to collapse all its sub-gropus
const subGroupKeys = deepFlatFilter(
[clickedNode],
(node) => node.type === GroupTypeEnum.GROUP,
).map((node) => node.key);
expandedKeys = _.without(expandedKeys, ...subGroupKeys);
subGroupKeys.forEach((key) => expandedKeySet.delete(key));
}

setExpandedNodeKeys(expandedKeys);
const newGroups = mapGroups(props.treeGroups, (group) => {
const shouldBeExpanded = expandedKeySet.has(getNodeKey(GroupTypeEnum.GROUP, group.groupId));
if (shouldBeExpanded !== group.isExpanded) {
return { ...group, isExpanded: shouldBeExpanded };
} else {
return group;
}
});
setUpdateTreeGroups(newGroups);
};

const onCheck: TreeProps<TreeNode>["onCheck"] = (_checkedKeysValue, info) => {
Expand Down Expand Up @@ -238,17 +240,30 @@ function TreeHierarchyView(props: Props) {
}
}

function setExpansionOfAllSubgroupsTo(group: TreeNode, expanded: boolean) {
const selectedGroupIdKey = getNodeKeyFromNode(group);
const subGroupKeys = deepFlatFilter([group], (node) => node.type === GroupTypeEnum.GROUP).map(
(node) => node.key,
);

if (expanded) {
setExpandedNodeKeys(_.uniq([...expandedNodeKeys, ...subGroupKeys]));
} else {
setExpandedNodeKeys(_.without(expandedNodeKeys, selectedGroupIdKey, ...subGroupKeys));
function setExpansionOfAllSubgroupsTo(parentGroup: TreeNode, expanded: boolean) {
if (parentGroup.id === MISSING_GROUP_ID) {
const newGroups = mapGroups(props.treeGroups, (group) => {
if (group.isExpanded !== expanded) {
return { ...group, isExpanded: expanded };
}
return group;
});
setUpdateTreeGroups(newGroups);
return;
}
const subGroups = getGroupByIdWithSubgroups(props.treeGroups, parentGroup.id);
const subGroupsMap = new Set(subGroups);
// If the subgroups will should be collapsed, not collapse the group itself.
dieknolle3333 marked this conversation as resolved.
Show resolved Hide resolved
// Do expand the group if the subgroups are expanded though.
if (expanded === false) subGroupsMap.delete(parentGroup.id);
const newGroups = mapGroups(props.treeGroups, (group) => {
if (subGroupsMap.has(group.groupId) && expanded !== group.isExpanded) {
return { ...group, isExpanded: expanded };
} else {
return group;
}
});
setUpdateTreeGroups(newGroups);
}

function onMoveWithContextAction(targetParentNode: TreeNode) {
Expand Down Expand Up @@ -302,7 +317,14 @@ function TreeHierarchyView(props: Props) {
}

// in either case expand the parent group
setExpandedNodeKeys([...expandedNodeKeys, getNodeKey(GroupTypeEnum.GROUP, parentGroupId)]);
const newGroups = mapGroups(props.treeGroups, (group) => {
if (group.groupId === parentGroupId) {
dieknolle3333 marked this conversation as resolved.
Show resolved Hide resolved
return { ...group, isExpanded: true };
} else {
return group;
}
});
setUpdateTreeGroups(newGroups);
}

function createGroup(groupId: number) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export function insertTreesAndTransform(
timestamp: 0,
children: _.orderBy(treeNodeChildren, ["name"], ["asc"]),
disableCheckbox: treeNodeChildren.length === 0,
expanded: group.isExpanded == null || group.isExpanded,
isChecked: treeNodeChildren.every(
// Groups that don't contain any trees should not influence the state of their parents
(groupOrTree) => groupOrTree.isChecked || !groupOrTree.containsTrees,
Expand Down