Merge branch 'dev' into 'staging'

fix branching graph unmount bug

See merge request frontend/squiz!332
This commit is contained in:
Nastya 2024-05-31 21:48:18 +00:00
commit 58dcba5ac8
3 changed files with 60 additions and 105 deletions

@ -9,11 +9,9 @@ import {
cleardragQuestionContentId,
setModalQuestionParentContentId,
setModalQuestionTargetContentId,
updateModalInfoWhyCantCreate,
updateOpenedModalSettingsId,
} from "@root/uiTools/actions";
import { useUiTools } from "@root/uiTools/store";
import { ProblemIcon } from "@ui_kit/ProblemIcon";
import type { Core } from "cytoscape";
import { enqueueSnackbar } from "notistack";
import { useEffect, useLayoutEffect, useMemo, useRef } from "react";
@ -27,24 +25,16 @@ import "./style/styles.css";
import { stylesheet } from "./style/stylesheet";
function CsComponent() {
const desireToOpenABranchingModal = useUiTools(
(state) => state.desireToOpenABranchingModal,
);
const canCreatePublic = useUiTools((state) => state.canCreatePublic);
const modalQuestionParentContentId = useUiTools(
(state) => state.modalQuestionParentContentId,
);
const modalQuestionTargetContentId = useUiTools(
(state) => state.modalQuestionTargetContentId,
);
const desireToOpenABranchingModal = useUiTools((state) => state.desireToOpenABranchingModal);
const modalQuestionParentContentId = useUiTools((state) => state.modalQuestionParentContentId);
const modalQuestionTargetContentId = useUiTools((state) => state.modalQuestionTargetContentId);
const trashQuestions = useQuestionsStore((state) => state.questions);
const cyRef = useRef<Core | null>(null);
const { removeNode } = useRemoveNode({ cyRef });
const csElements = useMemo(() => {
const questions = trashQuestions.filter(
(question): question is AnyTypedQuizQuestion =>
question.type !== null && question.type !== "result",
(question): question is AnyTypedQuizQuestion => question.type !== null && question.type !== "result"
);
return storeToNodes(questions);
@ -54,9 +44,7 @@ function CsComponent() {
const cy = cyRef?.current;
if (desireToOpenABranchingModal) {
setTimeout(() => {
cy
?.getElementById(desireToOpenABranchingModal)
?.data("eroticeyeblink", true);
cy?.getElementById(desireToOpenABranchingModal)?.data("eroticeyeblink", true);
}, 250);
} else {
cy?.elements().data("eroticeyeblink", false);
@ -64,10 +52,7 @@ function CsComponent() {
}, [desireToOpenABranchingModal]);
useEffect(() => {
if (
modalQuestionTargetContentId.length !== 0 &&
modalQuestionParentContentId.length !== 0
) {
if (modalQuestionTargetContentId.length !== 0 && modalQuestionParentContentId.length !== 0) {
if (!cyRef.current) return;
addNode({
@ -93,12 +78,11 @@ function CsComponent() {
cyRef.current?.layout(layoutOptions).run();
cyRef.current?.fit(undefined, 70);
},
[csElements],
[csElements]
);
return (
<>
<CsNodeButtons csElements={csElements} cyRef={cyRef} />
<Box mb="20px">
<Button
sx={{
@ -115,12 +99,19 @@ function CsComponent() {
Выровнять
</Button>
</Box>
<Box
sx={{
position: "relative",
height: "480px",
background: "#F2F3F7",
}}
>
<CytoscapeComponent
wheelSensitivity={0.1}
elements={csElements}
style={{
height: "480px",
background: "#F2F3F7",
height: "100%",
width: "100%",
overflow: "hidden",
}}
stylesheet={stylesheet}
@ -132,6 +123,8 @@ function CsComponent() {
autounselectify={true}
boxSelectionEnabled={false}
/>
<CsNodeButtons csElements={csElements} cyRef={cyRef} />
</Box>
<DeleteNodeModal removeNode={removeNode} />
</>
);

@ -8,29 +8,14 @@ import {
updateOpenedModalSettingsId,
} from "@root/uiTools/actions";
import { Core, EventObject, NodeSingular } from "cytoscape";
import {
MutableRefObject,
forwardRef,
useEffect,
useMemo,
useRef,
} from "react";
import { createPortal } from "react-dom";
import {
addNode,
isElementANode,
isNodeInViewport,
isQuestionProhibited,
storeToNodes,
} from "./helper";
import { MutableRefObject, forwardRef, useEffect, useMemo, useRef } from "react";
import { addNode, isElementANode, isNodeInViewport, isQuestionProhibited, storeToNodes } from "./helper";
const csButtonTypes = ["delete", "add", "settings", "select"] as const;
type CsButtonType = (typeof csButtonTypes)[number];
type CsNodeButtonsByType = Partial<
Record<CsButtonType, HTMLButtonElement | null>
>;
type CsNodeButtonsByType = Partial<Record<CsButtonType, HTMLButtonElement | null>>;
type CsButtonsById = Record<string, CsNodeButtonsByType | undefined>;
@ -44,10 +29,7 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
const buttons = useMemo(() => {
const nodeElements = csElements.filter(isElementANode);
buttonRefsById.current = nodeElements.reduce<CsButtonsById>(
(acc, node) => ((acc[node.data.id] = {}), acc),
{},
);
buttonRefsById.current = nodeElements.reduce<CsButtonsById>((acc, node) => ((acc[node.data.id] = {}), acc), {});
return (
<Box
sx={{
@ -56,6 +38,10 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
left: 0,
width: "100%",
height: "100%",
pointerEvents: "none",
"> *": {
pointerEvents: "auto",
},
}}
>
{nodeElements.flatMap((csElement) => [
@ -80,8 +66,7 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
cleardragQuestionContentId();
}}
/>,
!csElement.data.isRoot &&
!isQuestionProhibited(csElement.data.qtype) && (
!csElement.data.isRoot && !isQuestionProhibited(csElement.data.qtype) && (
<CsSettingsButton
key={`settings-${csElement.data.id}`}
ref={(r) => {
@ -102,12 +87,7 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
}}
onClick={() => {
setModalQuestionParentContentId(csElement.data.id);
setOpenedModalQuestions(
!(
isQuestionProhibited(csElement.data.type) &&
csElement.data.children > 0
),
);
setOpenedModalQuestions(!(isQuestionProhibited(csElement.data.type) && csElement.data.children > 0));
}}
/>,
])}
@ -150,10 +130,7 @@ export default function CsNodeButtons({ csElements, cyRef }: Props) {
};
}, []);
const container = cyRef.current?.container();
const buttonsPortal = container ? createPortal(buttons, container) : null;
return buttonsPortal;
return buttons;
}
const applyButtonStyleByType: Record<
@ -162,10 +139,8 @@ const applyButtonStyleByType: Record<
> = {
delete(button, node, zoom) {
const nodePosition = node.renderedPosition();
const shiftX =
node.renderedWidth() / 2 - (CLOSE_BUTTON_WIDTH / 2 + 6) * zoom;
const shiftY =
node.renderedHeight() / 2 - (CLOSE_BUTTON_HEIGHT / 2 + 6) * zoom;
const shiftX = node.renderedWidth() / 2 - (CLOSE_BUTTON_WIDTH / 2 + 6) * zoom;
const shiftY = node.renderedHeight() / 2 - (CLOSE_BUTTON_HEIGHT / 2 + 6) * zoom;
if (!isNodeInViewport(node, 100)) {
return button.style.setProperty("display", "none");
@ -176,7 +151,7 @@ const applyButtonStyleByType: Record<
button.style.setProperty("top", `${nodePosition.y}px`);
button.style.setProperty(
"transform",
`translate3d(calc(-50% + ${shiftX}px), calc(-50% - ${shiftY}px), 0) scale(${zoom})`,
`translate3d(calc(-50% + ${shiftX}px), calc(-50% - ${shiftY}px), 0) scale(${zoom})`
);
},
add(button, node, zoom) {
@ -190,15 +165,11 @@ const applyButtonStyleByType: Record<
button.style.setProperty("display", "flex");
button.style.setProperty("left", `${nodePosition.x}px`);
button.style.setProperty("top", `${nodePosition.y}px`);
button.style.setProperty(
"transform",
`translate3d(calc(-50% + ${shiftX}px), -50%, 0) scale(${zoom})`,
);
button.style.setProperty("transform", `translate3d(calc(-50% + ${shiftX}px), -50%, 0) scale(${zoom})`);
},
settings(button, node, zoom) {
const nodePosition = node.renderedPosition();
const shiftX =
-node.renderedWidth() / 2 - (SETTINGS_BUTTON_WIDTH / 2) * zoom;
const shiftX = -node.renderedWidth() / 2 - (SETTINGS_BUTTON_WIDTH / 2) * zoom;
if (!isNodeInViewport(node, 100)) {
return button.style.setProperty("display", "none");
@ -207,10 +178,7 @@ const applyButtonStyleByType: Record<
button.style.setProperty("display", "flex");
button.style.setProperty("left", `${nodePosition.x}px`);
button.style.setProperty("top", `${nodePosition.y}px`);
button.style.setProperty(
"transform",
`translate3d(calc(-50% + ${shiftX}px), -50%, 0) scale(${zoom})`,
);
button.style.setProperty("transform", `translate3d(calc(-50% + ${shiftX}px), -50%, 0) scale(${zoom})`);
},
select(button, node, zoom) {
const nodePosition = node.renderedPosition();
@ -222,10 +190,7 @@ const applyButtonStyleByType: Record<
button.style.setProperty("display", "flex");
button.style.setProperty("left", `${nodePosition.x}px`);
button.style.setProperty("top", `${nodePosition.y}px`);
button.style.setProperty(
"transform",
`translate3d(-50%, -50%, 0) scale(${zoom})`,
);
button.style.setProperty("transform", `translate3d(-50%, -50%, 0) scale(${zoom})`);
},
};

@ -7,13 +7,10 @@ import { FirstNodeField } from "./FirstNodeField";
export const BranchingMap = () => {
const quiz = useCurrentQuiz();
const dragQuestionContentId = useUiTools(
(state) => state.dragQuestionContentId,
);
const dragQuestionContentId = useUiTools((state) => state.dragQuestionContentId);
return (
<Box
id="cytoscape-container"
sx={{
overflow: "hidden",
padding: "20px",