корректное удаление коневого узла, безошибочное первое открытие модалки ветвления

This commit is contained in:
Nastya 2023-12-04 12:30:14 +03:00
parent 7029c86f19
commit cceafeb615
9 changed files with 72 additions and 105 deletions

@ -30,7 +30,6 @@ async function getQuestionList(body?: Partial<GetQuestionListRequest>) {
} }
function editQuestion(body: EditQuestionRequest, signal?: AbortSignal) { function editQuestion(body: EditQuestionRequest, signal?: AbortSignal) {
console.log("`${baseUrl}/question/edit` start")
return makeRequest<EditQuestionRequest, EditQuestionResponse>({ return makeRequest<EditQuestionRequest, EditQuestionResponse>({
url: `${baseUrl}/question/edit`, url: `${baseUrl}/question/edit`,
body, body,

@ -1,7 +1,7 @@
import { MessageIcon } from "@icons/messagIcon"; import { MessageIcon } from "@icons/messagIcon";
import { PointsIcon } from "@icons/questionsPage/PointsIcon"; import { PointsIcon } from "@icons/questionsPage/PointsIcon";
import { DeleteIcon } from "@icons/questionsPage/deleteIcon"; import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
import { TextareaAutosize } from "@mui/base/TextareaAutosize"; import TextareaAutosize from "@mui/base/TextareaAutosize";
import { import {
Box, Box,
FormControl, FormControl,

@ -124,14 +124,12 @@ export const CsComponent = ({
useEffect(() => { useEffect(() => {
if (modalQuestionTargetContentId.length !== 0 && modalQuestionParentContentId.length !== 0) { if (modalQuestionTargetContentId.length !== 0 && modalQuestionParentContentId.length !== 0) {
console.log("был выбран вопрос " + modalQuestionTargetContentId) addNode({ parentNodeContentId: modalQuestionParentContentId, targetNodeContentId: modalQuestionTargetContentId })
addNode({ parentNodeContentId:modalQuestionParentContentId, targetNodeContentId:modalQuestionTargetContentId })
} }
}, [modalQuestionTargetContentId]) }, [modalQuestionTargetContentId])
const addNode = ({ parentNodeContentId, targetNodeContentId }: { parentNodeContentId: string, targetNodeContentId?: string }) => { const addNode = ({ parentNodeContentId, targetNodeContentId }: { parentNodeContentId: string, targetNodeContentId?: string }) => {
console.log("dragQuestionContentId " + dragQuestionContentId)
const cy = cyRef?.current const cy = cyRef?.current
const parentNodeChildren = cy?.$('edge[source = "' + parentNodeContentId + '"]')?.length const parentNodeChildren = cy?.$('edge[source = "' + parentNodeContentId + '"]')?.length
//если есть инфо о выбранном вопросе из модалки - берём родителя из инфо модалки. Иначе из значения дропа //если есть инфо о выбранном вопросе из модалки - берём родителя из инфо модалки. Иначе из значения дропа
@ -139,7 +137,7 @@ export const CsComponent = ({
if (Object.keys(targetQuestion).length !== 0 && Object.keys(targetQuestion).length !== 0 && parentNodeContentId && parentNodeChildren !== undefined) { if (Object.keys(targetQuestion).length !== 0 && Object.keys(targetQuestion).length !== 0 && parentNodeContentId && parentNodeChildren !== undefined) {
clearDataAfterAddNode({ parentNodeContentId, targetQuestion, parentNodeChildren }) clearDataAfterAddNode({ parentNodeContentId, targetQuestion, parentNodeChildren })
cy?.data('changed',true) cy?.data('changed', true)
cy?.add([ cy?.add([
{ {
data: { data: {
@ -161,8 +159,6 @@ export const CsComponent = ({
} }
const clearDataAfterAddNode = ({ parentNodeContentId, targetQuestion, parentNodeChildren }: { parentNodeContentId: string, targetQuestion: AnyQuizQuestion, parentNodeChildren: number }) => { const clearDataAfterAddNode = ({ parentNodeContentId, targetQuestion, parentNodeChildren }: { parentNodeContentId: string, targetQuestion: AnyQuizQuestion, parentNodeChildren: number }) => {
console.log("записываю на бек ид родителя")
console.log({ parentNodeContentId, targetQuestion, parentNodeChildren })
//предупреждаем добавленный вопрос о том, кто его родитель //предупреждаем добавленный вопрос о том, кто его родитель
updateQuestion(targetQuestion.content.id, question => { updateQuestion(targetQuestion.content.id, question => {
question.content.rule.parentId = parentNodeContentId question.content.rule.parentId = parentNodeContentId
@ -179,9 +175,8 @@ export const CsComponent = ({
} }
const removeNode = ({ targetNodeContentId }: { targetNodeContentId: string }) => { const removeNode = ({ targetNodeContentId }: { targetNodeContentId: string }) => {
const deleteNodes = [] as string[] const deleteNodes = [] as string[]
const deleteEdges:any = [] const deleteEdges: any = []
console.log("remove")
const cy = cyRef?.current const cy = cyRef?.current
const findChildrenToDelete = (node) => { const findChildrenToDelete = (node) => {
@ -205,60 +200,49 @@ export const CsComponent = ({
const targetQuestion = getQuestionByContentId(targetNodeContentId) const targetQuestion = getQuestionByContentId(targetNodeContentId)
if (targetQuestion.content.rule.parentId === "root" && quiz) { if (targetQuestion.content.rule.parentId === "root" && quiz) {
console.log("click ROOT") updateRootContentId(quiz?.id, "")
updateQuestion(targetNodeContentId, question => { updateQuestion(targetNodeContentId, question => {
question.content.rule.parentId = "" question.content.rule.parentId = ""
question.content.rule.main = [] question.content.rule.main = []
question.content.rule.default = "" question.content.rule.default = ""
}) })
updateRootContentId(quiz?.id, false)
} else { } else {
console.log("click not ROOT")
const parentQuestionContentId = cy?.$('edge[target = "' + targetNodeContentId + '"]')?.toArray()?.[0]?.data()?.source const parentQuestionContentId = cy?.$('edge[target = "' + targetNodeContentId + '"]')?.toArray()?.[0]?.data()?.source
if (targetNodeContentId && parentQuestionContentId) { if (targetNodeContentId && parentQuestionContentId) {
clearDataAfterRemoveNode({ targetQuestionContentId: targetNodeContentId, parentQuestionContentId }) clearDataAfterRemoveNode({ targetQuestionContentId: targetNodeContentId, parentQuestionContentId })
cy?.remove(cy?.$('#' + targetNodeContentId)).layout(lyopts).run() cy?.remove(cy?.$('#' + targetNodeContentId)).layout(lyopts).run()
} }
console.log(deleteNodes, deleteEdges)
//После всех манипуляций удаляем грани из CS и ноды из бекенда
deleteNodes.forEach((nodeId) => {//Ноды
cy?.remove(cy?.$("#" + nodeId))
removeButtons(nodeId)
updateQuestion(nodeId, question => {
question.content.rule.parentId = ""
question.content.rule.main = []
question.content.rule.default = ""
})
})
deleteEdges.forEach((edge:any) => {//Грани
cy?.remove(edge)
})
removeButtons(targetNodeContentId)
cy?.data('changed',true)
cy?.layout(lyopts).run()
} }
//После всех манипуляций удаляем грани из CS и ноды из бекенда
deleteNodes.forEach((nodeId) => {//Ноды
cy?.remove(cy?.$("#" + nodeId))
removeButtons(nodeId)
updateQuestion(nodeId, question => {
question.content.rule.parentId = ""
question.content.rule.main = []
question.content.rule.default = ""
})
})
deleteEdges.forEach((edge: any) => {//Грани
cy?.remove(edge)
})
removeButtons(targetNodeContentId)
cy?.data('changed', true)
cy?.layout(lyopts).run()
} }
const clearDataAfterRemoveNode = ({ targetQuestionContentId, parentQuestionContentId }: { targetQuestionContentId: string, parentQuestionContentId: string }) => { const clearDataAfterRemoveNode = ({ targetQuestionContentId, parentQuestionContentId }: { targetQuestionContentId: string, parentQuestionContentId: string }) => {
console.log({ targetQuestionContentId, parentQuestionContentId })
updateQuestion(targetQuestionContentId, question => { updateQuestion(targetQuestionContentId, question => {
question.content.rule.parentId = "" question.content.rule.parentId = ""
question.content.rule.main = [] question.content.rule.main = []
question.content.rule.default = "" question.content.rule.default = ""
}) })
updateQuestion(parentQuestionContentId, question => { updateQuestion(parentQuestionContentId, question => {
console.log("parent default " + question.content.rule.default)
console.log("target ID " + targetQuestionContentId)
console.log(question.content.rule.default === targetQuestionContentId)
if (question.content.rule.default === targetQuestionContentId) question.content.rule.default = "" if (question.content.rule.default === targetQuestionContentId) question.content.rule.default = ""
}) })
@ -282,22 +266,20 @@ export const CsComponent = ({
const readyLO = (e) => { const readyLO = (e) => {
console.log(e.cy.data('firstNode'),"SKEEER",e.cy.data('changed'))
if (e.cy.data('firstNode') === 'nonroot') { if (e.cy.data('firstNode') === 'nonroot') {
e.cy.data('firstNode','root') e.cy.data('firstNode', 'root')
e.cy.nodes().sort((a,b) => (a.data('root')?1:-1)).layout(lyopts).run() e.cy.nodes().sort((a, b) => (a.data('root') ? 1 : -1)).layout(lyopts).run()
} else {
} else {
e.cy.data('changed', false)
e.cy.removeData('firstNode')
} e.cy.data('changed', false)
e.cy.removeData('firstNode')
}
//удаляем иконки //удаляем иконки
e.cy.nodes().forEach((ele: any) => { e.cy.nodes().forEach((ele: any) => {
const data = ele.data() const data = ele.data()
console.log(data)
data.id && removeButtons(data.id); data.id && removeButtons(data.id);
}) })
initialPopperIcons(e) initialPopperIcons(e)
@ -307,11 +289,9 @@ console.log(e.cy.data('firstNode'),"SKEEER",e.cy.data('changed'))
name: 'preset', name: 'preset',
positions: (e) => { positions: (e) => {
console.log('BBBBBBBBBBBBBBB', e.cy().data('changed'))
if (!e.cy().data('changed')) { if (!e.cy().data('changed')) {
return e.data('oldPos') return e.data('oldPos')
} else {e.removeData('oldPos')} } else { e.removeData('oldPos') }
console.log('POSITIIIIIIIONS')
const id = e.id() const id = e.id()
const incomming = e.cy().edges(`[target="${id}"]`) const incomming = e.cy().edges(`[target="${id}"]`)
const layer = 0 const layer = 0
@ -319,7 +299,7 @@ console.log(e.cy.data('firstNode'),"SKEEER",e.cy.data('changed'))
if (incomming.length === 0) { if (incomming.length === 0) {
if (e.cy().data('firstNode') === undefined) if (e.cy().data('firstNode') === undefined)
e.cy().data('firstNode','root') e.cy().data('firstNode', 'root')
e.data('root', true) e.data('root', true)
const children = e.cy().edges(`[source="${id}"]`).targets() const children = e.cy().edges(`[source="${id}"]`).targets()
e.data('layer', layer) e.data('layer', layer)
@ -341,7 +321,6 @@ console.log(e.cy.data('firstNode'),"SKEEER",e.cy.data('changed'))
queue.push({ parent: e, children: children }) queue.push({ parent: e, children: children })
while (queue.length) { while (queue.length) {
const task = queue.pop() const task = queue.pop()
console.log('WIIIING',task.parent.data(),task.children.length)
if (task.children.length === 0) { if (task.children.length === 0) {
task.parent.data('subtreeWidth', task.parent.height()) task.parent.data('subtreeWidth', task.parent.height())
continue continue
@ -360,22 +339,20 @@ console.log('WIIIING',task.parent.data(),task.children.length)
task?.parent.data('subtreeWidth', task.children.reduce((p, n) => p + n.data('subtreeWidth'), 0)) task?.parent.data('subtreeWidth', task.children.reduce((p, n) => p + n.data('subtreeWidth'), 0))
} }
const pos = { x: 0, y: 0 } const pos = { x: 0, y: 0 }
console.log(e.data())
e.data('oldPos', pos) e.data('oldPos', pos)
return pos return pos
} else { } else {
if (e.cy().data('firstNode') !== 'root') { if (e.cy().data('firstNode') !== 'root') {
e.cy().data('firstNode','nonroot') e.cy().data('firstNode', 'nonroot')
return {x:0,y:0} return { x: 0, y: 0 }
} }
if (e.cy().data('firstNode') === undefined) if (e.cy().data('firstNode') === undefined)
e.cy().data('firstNode','nonroot') e.cy().data('firstNode', 'nonroot')
const parent = e.cy().edges(`[target="${e.id()}"]`)[0].source() const parent = e.cy().edges(`[target="${e.id()}"]`)[0].source()
const wing = (parent.data('children') === 1) ? 0 : parent.data('subtreeWidth') / 2 + 50 const wing = (parent.data('children') === 1) ? 0 : parent.data('subtreeWidth') / 2 + 50
const lastOffset = parent.data('lastChild') const lastOffset = parent.data('lastChild')
const step = wing * 2 / (parent.data('children') - 1) const step = wing * 2 / (parent.data('children') - 1)
//e.removeData('subtreeWidth') //e.removeData('subtreeWidth')
console.log('AAAAAAAAAAa', e.data(), lastOffset, step, parent.position().y, wing)
if (lastOffset !== undefined) { if (lastOffset !== undefined) {
parent.data('lastChild', lastOffset + step) parent.data('lastChild', lastOffset + step)
const pos = { x: 250 * e.data('layer'), y: (lastOffset + step) } const pos = { x: 250 * e.data('layer'), y: (lastOffset + step) }
@ -386,7 +363,7 @@ if (e.cy().data('firstNode') !== 'root') {
const pos = { x: 250 * e.data('layer'), y: (parent.position().y - wing) } const pos = { x: 250 * e.data('layer'), y: (parent.position().y - wing) }
e.data('oldPos', pos) e.data('oldPos', pos)
return pos return pos
} }
} }
}, // map of (node id) => (position obj); or function(node){ return somPos; } }, // map of (node id) => (position obj); or function(node){ return somPos; }
zoom: undefined, // the zoom level to set (prob want fit = false if set) zoom: undefined, // the zoom level to set (prob want fit = false if set)
@ -502,7 +479,7 @@ if (e.cy().data('firstNode') !== 'root') {
layoutElement.classList.add("popper-layout"); layoutElement.classList.add("popper-layout");
layoutElement.setAttribute("data-id", item.id()); layoutElement.setAttribute("data-id", item.id());
layoutElement.addEventListener("mouseup", () => { layoutElement.addEventListener("mouseup", () => {
//Узнаём грани, идущие от этой ноды //Узнаём грани, идущие от этой ноды
setModalQuestionParentContentId(item.id()) setModalQuestionParentContentId(item.id())
setOpenedModalQuestions(true) setOpenedModalQuestions(true)
}); });
@ -533,7 +510,7 @@ if (e.cy().data('firstNode') !== 'root') {
plusElement.addEventListener("mouseup", () => { plusElement.addEventListener("mouseup", () => {
setStartCreate(node.id()); setStartCreate(node.id());
}); });
plusesContainer.current?.appendChild(plusElement); plusesContainer.current?.appendChild(plusElement);
return plusElement; return plusElement;
@ -594,7 +571,6 @@ if (e.cy().data('firstNode') !== 'root') {
gearElement.style.zIndex = "1" gearElement.style.zIndex = "1"
gearsContainer.current?.appendChild(gearElement); gearsContainer.current?.appendChild(gearElement);
gearElement.addEventListener("mouseup", (e) => { gearElement.addEventListener("mouseup", (e) => {
console.log(item.id())
updateOpenedModalSettingsId(item.id()) updateOpenedModalSettingsId(item.id())
}); });
@ -672,27 +648,27 @@ if (e.cy().data('firstNode') !== 'root') {
return ( return (
<> <>
<CytoscapeComponent <CytoscapeComponent
wheelSensitivity={0.1} wheelSensitivity={0.1}
elements={[]} elements={[]}
// elements={createGraphElements(tree, quiz)} // elements={createGraphElements(tree, quiz)}
style={{ height: "480px", background: "#F2F3F7" }} style={{ height: "480px", background: "#F2F3F7" }}
stylesheet={stylesheet} stylesheet={stylesheet}
layout={(lyopts)} layout={(lyopts)}
cy={(cy) => { cy={(cy) => {
cyRef.current = cy; cyRef.current = cy;
}} }}
/> />
<button onClick={() => { <button onClick={() => {
console.log("NODES____________________________") console.log("NODES____________________________")
cyRef.current?.elements().forEach((ele:any) => { cyRef.current?.elements().forEach((ele: any) => {
console.log(ele.data()) console.log(ele.data())
}) })
}}>nodes</button> }}>nodes</button>
<button onClick={() => { <button onClick={() => {
console.log("ELEMENTS____________________________") console.log("ELEMENTS____________________________")
console.log(questions) console.log(questions)
}}>elements</button> }}>elements</button>
</> </>
); );
}; };

@ -14,14 +14,11 @@ export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetCon
const { dragQuestionContentId } = useQuestionsStore() const { dragQuestionContentId } = useQuestionsStore()
const Container = useRef<HTMLDivElement | null>(null); const Container = useRef<HTMLDivElement | null>(null);
const quiz = useCurrentQuiz(); const quiz = useCurrentQuiz();
console.log(dragQuestionContentId)
const modalOpen = () => setOpenedModalQuestions(true) const modalOpen = () => setOpenedModalQuestions(true)
const newRootNode = () => { const newRootNode = () => {
if (quiz) { if (quiz) {
console.log(dragQuestionContentId)
if (dragQuestionContentId) { if (dragQuestionContentId) {
updateRootContentId(quiz?.id, dragQuestionContentId) updateRootContentId(quiz?.id, dragQuestionContentId)
updateQuestion(dragQuestionContentId, (question) => question.content.rule.parentId = "root") updateQuestion(dragQuestionContentId, (question) => question.content.rule.parentId = "root")

@ -15,11 +15,9 @@ interface Edges {
} }
export const storeToNodes = (questions: AnyQuizQuestion[]) => { export const storeToNodes = (questions: AnyQuizQuestion[]) => {
console.log(questions)
const nodes: Nodes[] = [] const nodes: Nodes[] = []
const edges: Edges[] = [] const edges: Edges[] = []
questions.forEach((question) => { questions.forEach((question) => {
console.log(question)
if (question.content.rule.parentId) { if (question.content.rule.parentId) {
nodes.push({data: { nodes.push({data: {
id: question.content.id, id: question.content.id,
@ -38,6 +36,5 @@ export const storeToNodes = (questions: AnyQuizQuestion[]) => {
}}) }})
} }
}) })
console.log([...nodes, ...edges])
return [...nodes, ...edges]; return [...nodes, ...edges];
} }

@ -32,33 +32,32 @@ export default function BranchingQuestions() {
const { openedModalSettingsId } = useQuestionsStore(); const { openedModalSettingsId } = useQuestionsStore();
const [targetQuestion, setTargetQuestion] = useState<AnyQuizQuestion | null>(getQuestionById(openedModalSettingsId) || getQuestionByContentId(openedModalSettingsId)) const [targetQuestion, setTargetQuestion] = useState<AnyQuizQuestion | null>(getQuestionById(openedModalSettingsId) || getQuestionByContentId(openedModalSettingsId))
console.log(targetQuestion)
const [parentQuestion, setParentQuestion] = useState<AnyQuizQuestion | null>(getQuestionByContentId(targetQuestion?.content.rule.parentId)) const [parentQuestion, setParentQuestion] = useState<AnyQuizQuestion | null>(getQuestionByContentId(targetQuestion?.content.rule.parentId))
console.log(parentQuestion)
useLayoutEffect(() => { useLayoutEffect(() => {
if (parentQuestion === null) return if (parentQuestion === null) return
if (parentQuestion.content.rule.main.length === 0) updateQuestion(parentQuestion.id, question => question.content.rule.main.push({ if (parentQuestion.content.rule.main.length === 0) {
let mutate = JSON.parse(JSON.stringify(parentQuestion))
mutate.content.rule.main = [{
next: targetQuestion.content.id, next: targetQuestion.content.id,
or: true, or: true,
rules: [{ rules: [{
question: parentQuestion.content.id, question: parentQuestion.content.id,
answers: [] answers: []
}] }]
})) }]
setParentQuestion(mutate)
}
}) })
if (targetQuestion === null || parentQuestion === null) { if (targetQuestion === null || parentQuestion === null) {
console.log(openedModalSettingsId)
enqueueSnackbar("Невозможно найти данные ветвления для этого вопроса") enqueueSnackbar("Невозможно найти данные ветвления для этого вопроса")
return <></> return <></>
} }
const saveData = () => { const saveData = () => {
console.log(parentQuestion)
if (parentQuestion !== null) { if (parentQuestion !== null) {
updateQuestion(parentQuestion.content.id, question => question.content = parentQuestion.content) updateQuestion(parentQuestion.content.id, question => question.content = parentQuestion.content)
} }

@ -23,7 +23,6 @@ type AnyQuestion = UntypedQuizQuestion | AnyTypedQuizQuestion
export const QuestionsList = () => { export const QuestionsList = () => {
const { questions } = useQuestionsStore() const { questions } = useQuestionsStore()
console.log(questions)
return ( return (
<Box sx={{ padding: "15px" }}> <Box sx={{ padding: "15px" }}>

@ -38,7 +38,6 @@ export const BranchingQuestionsModal = ({ openedModalQuestions, setOpenedModalQu
> >
<Box sx={{ margin: "0 auto", maxWidth: "350px" }}> <Box sx={{ margin: "0 auto", maxWidth: "350px" }}>
{questions.filter((q:AnyQuestion) => { {questions.filter((q:AnyQuestion) => {
console.log(q.content)
if (q.content === null) return true if (q.content === null) return true
return (q.type && !q.content.rule.parentId)}).map((question: AnyTypedQuizQuestion, index:number) => ( return (q.type && !q.content.rule.parentId)}).map((question: AnyTypedQuizQuestion, index:number) => (
<Button <Button

@ -28,6 +28,7 @@ export default function QuestionsPage() {
const [settingBranching, setSettingBranching] = useState<boolean>(false); const [settingBranching, setSettingBranching] = useState<boolean>(false);
if (!quiz) return null; if (!quiz) return null;
return ( return (
<> <>
<Box <Box