mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-12 08:51:20 -05:00
fix: highlighting for question with cyclic logic (#2669)
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
c8f2f94361
commit
1848e062f1
+12
-3
@@ -19,7 +19,12 @@ import { checkForEmptyFallBackValue, extractRecallInfo } from "@formbricks/lib/u
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
import { TSurvey, TSurveyQuestion } from "@formbricks/types/surveys";
|
||||
|
||||
import { isCardValid, validateQuestion, validateSurveyQuestionsInBatch } from "../lib/validation";
|
||||
import {
|
||||
findQuestionsWithCyclicLogic,
|
||||
isCardValid,
|
||||
validateQuestion,
|
||||
validateSurveyQuestionsInBatch,
|
||||
} from "../lib/validation";
|
||||
import { AddQuestionButton } from "./AddQuestionButton";
|
||||
import { EditThankYouCard } from "./EditThankYouCard";
|
||||
import { EditWelcomeCard } from "./EditWelcomeCard";
|
||||
@@ -89,8 +94,12 @@ export const QuestionsView = ({
|
||||
const isFirstQuestion = question.id === localSurvey.questions[0].id;
|
||||
let temp = structuredClone(invalidQuestions);
|
||||
if (validateQuestion(question, surveyLanguages, isFirstQuestion)) {
|
||||
temp = invalidQuestions.filter((id) => id !== question.id);
|
||||
setInvalidQuestions(temp);
|
||||
// If question is valid, we now check for cyclic logic
|
||||
const questionsWithCyclicLogic = findQuestionsWithCyclicLogic(localSurvey.questions);
|
||||
if (!questionsWithCyclicLogic.includes(question.id)) {
|
||||
temp = invalidQuestions.filter((id) => id !== question.id);
|
||||
setInvalidQuestions(temp);
|
||||
}
|
||||
} else if (!invalidQuestions.includes(question.id)) {
|
||||
temp.push(question.id);
|
||||
setInvalidQuestions(temp);
|
||||
|
||||
+14
-11
@@ -246,12 +246,13 @@ export const validateId = (
|
||||
return true;
|
||||
};
|
||||
|
||||
// Checks if there is a cycle present in the survey data logic.
|
||||
export const isSurveyLogicCyclic = (questions: TSurveyQuestions) => {
|
||||
// Checks if there is a cycle present in the survey data logic and returns all questions responsible for the cycle.
|
||||
export const findQuestionsWithCyclicLogic = (questions: TSurveyQuestions): string[] => {
|
||||
const visited: Record<string, boolean> = {};
|
||||
const recStack: Record<string, boolean> = {};
|
||||
const cyclicQuestions: Set<string> = new Set();
|
||||
|
||||
const checkForCycle = (questionId: string) => {
|
||||
const checkForCyclicLogic = (questionId: string): boolean => {
|
||||
if (!visited[questionId]) {
|
||||
visited[questionId] = true;
|
||||
recStack[questionId] = true;
|
||||
@@ -261,12 +262,14 @@ export const isSurveyLogicCyclic = (questions: TSurveyQuestions) => {
|
||||
for (const logic of question.logic) {
|
||||
const destination = logic.destination;
|
||||
if (!destination) {
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!visited[destination] && checkForCycle(destination)) {
|
||||
if (!visited[destination] && checkForCyclicLogic(destination)) {
|
||||
cyclicQuestions.add(questionId);
|
||||
return true;
|
||||
} else if (recStack[destination]) {
|
||||
cyclicQuestions.add(questionId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -274,7 +277,7 @@ export const isSurveyLogicCyclic = (questions: TSurveyQuestions) => {
|
||||
// Handle default behavior
|
||||
const nextQuestionIndex = questions.findIndex((question) => question.id === questionId) + 1;
|
||||
const nextQuestion = questions[nextQuestionIndex];
|
||||
if (nextQuestion && !visited[nextQuestion.id] && checkForCycle(nextQuestion.id)) {
|
||||
if (nextQuestion && !visited[nextQuestion.id] && checkForCyclicLogic(nextQuestion.id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -286,12 +289,10 @@ export const isSurveyLogicCyclic = (questions: TSurveyQuestions) => {
|
||||
|
||||
for (const question of questions) {
|
||||
const questionId = question.id;
|
||||
if (checkForCycle(questionId)) {
|
||||
return true;
|
||||
}
|
||||
checkForCyclicLogic(questionId);
|
||||
}
|
||||
|
||||
return false;
|
||||
return Array.from(cyclicQuestions);
|
||||
};
|
||||
|
||||
export const isSurveyValid = (
|
||||
@@ -455,7 +456,9 @@ export const isSurveyValid = (
|
||||
}
|
||||
|
||||
// Detecting any cyclic dependencies in survey logic.
|
||||
if (isSurveyLogicCyclic(survey.questions)) {
|
||||
const questionsWithCyclicLogic = findQuestionsWithCyclicLogic(survey.questions);
|
||||
if (questionsWithCyclicLogic.length > 0) {
|
||||
setInvalidQuestions(questionsWithCyclicLogic);
|
||||
toast.error("Cyclic logic detected. Please fix it before saving.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user