Skip to content

Commit d9c7ccb

Browse files
authored
fix: manage selected pod globally (#125)
1 parent 9c3b8ef commit d9c7ccb

File tree

3 files changed

+34
-45
lines changed

3 files changed

+34
-45
lines changed

ui/src/components/Canvas.tsx

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const ScopeNode = memo<Props>(({ data, id, isConnectable }) => {
7777
const [frame] = React.useState({
7878
translate: [0, 0],
7979
});
80-
const selected = useStore(store, (state) => state.selected);
80+
const selected = useStore(store, (state) => state.pods[id]?.selected);
8181
const role = useStore(store, (state) => state.role);
8282

8383
const onResize = useCallback(({ width, height, offx, offy }) => {
@@ -154,7 +154,7 @@ const ScopeNode = memo<Props>(({ data, id, isConnectable }) => {
154154
id="right"
155155
isConnectable={isConnectable}
156156
/>
157-
{selected === id && role !== RoleType.GUEST && (
157+
{selected && role !== RoleType.GUEST && (
158158
<Moveable
159159
target={target}
160160
resizable={true}
@@ -339,7 +339,7 @@ const CodeNode = memo<Props>(({ data, id, isConnectable }) => {
339339
const isRightLayout = layout === "right";
340340
const { setNodes } = useReactFlow();
341341
// const selected = useStore(store, (state) => state.selected);
342-
const setSelected = useStore(store, (state) => state.setSelected);
342+
const setPodSelected = useStore(store, (state) => state.setPodSelected);
343343
const setCurrentEditor = useStore(store, (state) => state.setCurrentEditor);
344344
const getPod = useStore(store, (state) => state.getPod);
345345
const pod = getPod(id);
@@ -494,7 +494,7 @@ const CodeNode = memo<Props>(({ data, id, isConnectable }) => {
494494
onClick={(e) => {
495495
// If the node is selected (for resize), the cursor is not shown. So
496496
// we need to deselect it when we re-focus on the editor.
497-
setSelected(null);
497+
setPodSelected(id, false);
498498
setNodes((nds) =>
499499
applyNodeChanges(
500500
[
@@ -717,6 +717,8 @@ export function Canvas() {
717717
},
718718
level: 0,
719719
extent: "parent",
720+
//otherwise, throws a lot of warnings, see https://reactflow.dev/docs/guides/troubleshooting/#only-child-nodes-can-use-a-parent-extent
721+
parentNode: undefined,
720722
dragHandle: ".custom-drag-handle",
721723
};
722724

@@ -782,18 +784,6 @@ export function Canvas() {
782784
},
783785
});
784786
}
785-
setNodes((nds) =>
786-
applyNodeChanges(
787-
[
788-
{
789-
id: node.id,
790-
type: "select",
791-
selected: true,
792-
},
793-
],
794-
nds
795-
)
796-
);
797787
},
798788
[nodesMap, setNodes, userColor]
799789
);
@@ -888,19 +878,6 @@ export function Canvas() {
888878

889879
nodesMap.set(node.id, currentNode);
890880
}
891-
892-
setNodes((nds) =>
893-
applyNodeChanges(
894-
[
895-
{
896-
id: node.id,
897-
type: "select",
898-
selected: true,
899-
},
900-
],
901-
nds
902-
)
903-
);
904881
},
905882
// We need to monitor nodes, so that getScopeAt can have all the nodes.
906883
[
@@ -970,6 +947,7 @@ export function Canvas() {
970947
nodesDraggable={role !== RoleType.GUEST}
971948
// disable node delete on backspace when the user is a guest.
972949
deleteKeyCode={role === RoleType.GUEST ? null : "Backspace"}
950+
multiSelectionKeyCode={"Control"}
973951
>
974952
<Box>
975953
<MiniMap

ui/src/lib/nodes.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export function useNodesStateSynced(nodeList) {
1414
const getPod = useStore(store, (state) => state.getPod);
1515
const deletePod = useStore(store, (state) => state.deletePod);
1616
const updatePod = useStore(store, (state) => state.updatePod);
17-
const setSelected = useStore(store, (state) => state.setSelected);
17+
const setPodSelected = useStore(store, (state) => state.setPodSelected);
1818
const role = useStore(store, (state) => state.role);
1919
const ydoc = useStore(store, (state) => state.ydoc);
2020
const nodesMap = ydoc.getMap<Node>("pods");
@@ -35,17 +35,17 @@ export function useNodesStateSynced(nodeList) {
3535
}
3636

3737
changes.forEach((change) => {
38-
if (!isNodeAddChange(change) && !isNodeResetChange(change)) {
38+
if (!isNodeAddChange(change)) {
3939
if (isNodeRemoveChange(change)) {
4040
nodesMap.delete(change.id);
4141
return;
4242
}
4343
const node = nextNodes.find((n) => n.id === change.id);
44+
4445
if (!node) return;
4546

46-
if (change.type === "select" && change.selected) {
47-
// FIXME: consider the case where only unselect is called
48-
setSelected(node.id);
47+
if (isNodeResetChange(change) || change.type === "select") {
48+
setPodSelected(node.id, change.selected as boolean);
4949
return;
5050
}
5151

@@ -98,10 +98,11 @@ export function useNodesStateSynced(nodeList) {
9898

9999
// TOFIX: a node may be shadowed behind its parent, due to the order to render reactflow node, to fix this, comment out the following sorted method, which brings in a large overhead.
100100
setNodes(
101-
Array.from(nodesMap.values()).sort(
102-
(a: Node & { level }, b: Node & { level }) => a.level - b.level
103-
)
101+
Array.from(nodesMap.values())
102+
.sort((a: Node & { level }, b: Node & { level }) => a.level - b.level)
103+
.map((node) => ({ ...node, selected: getPod(node.id)?.selected }))
104104
);
105+
105106
// setNodes(Array.from(nodesMap.values()));
106107
};
107108

ui/src/lib/store.tsx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ const initialState = {
7878
socket: null,
7979
socketIntervalId: null,
8080
// keep different seletced info on each user themselves
81-
selected: null,
8281
// to fixed maco editor command bug
8382
currentEditor: null,
8483
//TODO: all presence information are now saved in clients map for future usage. create a modern UI to show those information from clients (e.g., online users)
@@ -123,6 +122,7 @@ export type Pod = {
123122
ns?: string;
124123
running?: boolean;
125124
focus?: boolean;
125+
selected?: boolean;
126126
};
127127

128128
export interface RepoSlice {
@@ -180,21 +180,20 @@ export interface RepoSlice {
180180
}) => void;
181181
setPodPosition: ({ id, x, y }: any) => void;
182182
setPodParent: ({ id, parent }: any) => void;
183-
selected: string | null;
184-
setSelected: (id: string | null) => void;
185183
currentEditor: string | null;
186184
setCurrentEditor: (id: string | null) => void;
187185
setUser: (user: any) => void;
188186
addClient: (clientId: any, name, color) => void;
189187
deleteClient: (clientId: any) => void;
190188
flipShowLineNumbers: () => void;
191189
disconnect: () => void;
192-
getPod: (string) => Pod;
190+
getPod: (id: string) => Pod;
193191
getPods: () => Record<string, Pod>;
194192
getId2children: (string) => string[];
195-
setPodVisibility: (id, visible) => void;
196-
setPodFocus: (id) => void;
197-
setPodBlur: (id) => void;
193+
setPodVisibility: (id: any, visible: any) => void;
194+
setPodFocus: (id: string) => void;
195+
setPodBlur: (id: string) => void;
196+
setPodSelected: (id: string, target: boolean) => void;
198197
}
199198

200199
type BearState = RepoSlice & RuntimeSlice;
@@ -244,7 +243,6 @@ const createRepoSlice: StateCreator<
244243
setSessionId: (id) => set({ sessionId: id }),
245244
addError: (error) => set({ error }),
246245
clearError: () => set({ error: null }),
247-
setSelected: (id) => set({ selected: id }),
248246
setCurrentEditor: (id) => set({ currentEditor: id }),
249247
addPod: async (
250248
client,
@@ -286,6 +284,8 @@ const createRepoSlice: StateCreator<
286284
// the backend instead.
287285
children: [],
288286
io: {},
287+
selected: false,
288+
focus: false,
289289
// from payload
290290
parent,
291291
index,
@@ -835,6 +835,16 @@ const createRepoSlice: StateCreator<
835835
}
836836
})
837837
),
838+
setPodSelected: (id: string, target: boolean) => {
839+
set(
840+
produce((state) => {
841+
if (state.pods[id]) {
842+
state.pods[id].selected = target;
843+
}
844+
})
845+
);
846+
},
847+
getPodSelected: (id: string) => get().pods[id]?.selected as boolean,
838848
});
839849

840850
export const createRepoStore = () =>

0 commit comments

Comments
 (0)