feat: logic fallback option added#4306
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 2 Skipped Deployments
|
WalkthroughThe changes in this pull request primarily enhance the survey logic handling within the application. Key modifications include the introduction of fallback logic for survey questions, updates to the handling of conditional logic, and improvements in localization files for various languages. New functions and properties are added to support these features, while existing functions are refined for better error handling and logic evaluation. The overall structure of the affected components remains intact, ensuring functionality is preserved alongside the enhancements. Changes
Possibly related PRs
Suggested labels
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
Thank you for following the naming conventions for pull request titles! 🙏 |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Outside diff range and nitpick comments (16)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (2)
38-65: Enhance type safety and simplify the implementation.The useMemo implementation is correct, but could benefit from some improvements:
Consider applying these enhancements:
+ type FallbackOption = { + icon?: ReactElement; + label: string; + value: string; + }; const fallbackOptions = useMemo(() => { - let options: { - icon?: ReactElement; - label: string; - value: string; - }[] = []; + const options: FallbackOption[] = []; localSurvey.questions.forEach((ques) => { - if (ques.id === question.id) return null; + if (ques.id === question.id) return; options.push({ icon: QUESTIONS_ICON_MAP[ques.type], label: getLocalizedValue(ques.headline, "default"), value: ques.id, }); });
Line range hint
37-115: Consider adding validation and error handling.The implementation could benefit from additional safeguards:
- Add null checks for localSurvey.questions and localSurvey.endings arrays
- Validate that the logicFallback value exists in the available options before applying it
- Consider adding error boundaries to handle potential rendering failures
Would you like me to provide a code example implementing these safeguards?
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx (1)
Line range hint
1-190: Consider extracting logic operations to a custom hook.The component currently handles multiple logic operations (add, remove, move, duplicate). To improve maintainability and reusability, consider:
- Extracting these operations into a custom hook (e.g.,
useSurveyLogic)- Moving the logic transformation utilities to a separate service
- Creating a dedicated LogicOperations context if these operations are used across multiple components
Example structure:
// hooks/useSurveyLogic.ts export function useSurveyLogic(question, questionIdx, updateQuestion) { const addLogic = useCallback(() => { // Current addLogic implementation }, [question, questionIdx, updateQuestion]); const removeLogic = useCallback((logicItemIdx) => { // Current handleRemoveLogic implementation }, [question, questionIdx, updateQuestion]); // ... other operations return { addLogic, removeLogic, moveLogic, duplicateLogic }; }packages/types/surveys/validation.ts (2)
229-229: Consider documenting the fallback behavior.The comment "Handle default behavior" could be more explicit about the precedence rules between jump actions, fallback logic, and default next question behavior.
- // Handle default behavior: move to the next question if no jump actions or fallback logic is defined + // Precedence: 1. Jump actions (if conditions met) + // 2. Fallback logic (if specified) + // 3. Default: move to next question
217-229: Consider performance optimization for deep fallback chains.While the implementation is correct, deep fallback chains could impact performance during validation. Consider:
- Adding a maximum depth limit for fallback chains
- Caching visited paths to optimize repeated validations
- Adding telemetry to monitor chain depths in production
Example implementation:
const MAX_FALLBACK_DEPTH = 10; const visitedPaths = new Map<string, Set<string>>(); const checkForCyclicLogic = (questionId: TSurveyQuestionId, depth = 0): boolean => { if (depth > MAX_FALLBACK_DEPTH) { console.warn(`Maximum fallback depth exceeded for question ${questionId}`); return false; } // Cache hit: return early if we've seen this path before const pathKey = Array.from(recStack).filter(([_, v]) => v).map(([k]) => k).join(','); if (visitedPaths.has(pathKey)) { return visitedPaths.get(pathKey)!.has(questionId); } // Rest of the existing logic... }packages/surveys/src/components/general/Survey.tsx (2)
Line range hint
258-275: Add validation for logicFallback valueThe current implementation should validate the logicFallback value to ensure it references a valid question or ending ID.
Add validation to prevent navigation to invalid questions:
// Use logicFallback if no jump target was set if (!firstJumpTarget && currQuesTemp.logicFallback) { + // Validate that logicFallback points to a valid question or ending + const isValidQuestion = questions.some(q => q.id === currQuesTemp.logicFallback); + const isValidEnding = survey.endings.some(e => e.id === currQuesTemp.logicFallback); + if (!isValidQuestion && !isValidEnding) { + console.warn(`Invalid logicFallback target: ${currQuesTemp.logicFallback}`); + firstJumpTarget = questions[currentQuestionIndex + 1]?.id || firstEndingId; + } else { firstJumpTarget = currQuesTemp.logicFallback; + } }
Line range hint
245-260: Enhance error handling in logic evaluationThe current error handling is minimal and could be improved to provide better debugging information and handle edge cases more gracefully.
Consider enhancing the error handling:
if (questionId === "start") return { nextQuestionId: questions[0]?.id || firstEndingId, calculatedVariables: {} }; - if (!currQuesTemp) throw new Error("Question not found"); + if (!currQuesTemp) { + console.error(`Failed to find question with ID: ${questionId}`); + throw new Error(`Question not found: ${questionId}`); + } let firstJumpTarget: string | undefined; const allRequiredQuestionIds: string[] = []; let calculationResults = { ...currentVariables }; const localResponseData = { ...responseData, ...data }; + try { if (currQuesTemp.logic && currQuesTemp.logic.length > 0) { for (const logic of currQuesTemp.logic) { if ( evaluateLogic( localSurvey, localResponseData, calculationResults, logic.conditions, selectedLanguage ) ) { // ... existing logic ... } } } + } catch (error) { + console.error(`Logic evaluation failed for question ${questionId}:`, error); + // Fallback to next question in sequence + return { + nextQuestionId: questions[currentQuestionIndex + 1]?.id || firstEndingId, + calculatedVariables: calculationResults + }; + }apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.ts (3)
122-125: Add documentation for the fallback logic behavior.While the implementation is correct, adding a comment explaining when and why the fallback logic is triggered would improve code maintainability.
- // If no jump target was set, check for a fallback logic + // If no conditions in the logic array evaluate to true or no jump target is set, + // use the fallback logic to determine the next question. This ensures a default + // path when no specific logic conditions are met. if (!firstJumpTarget && currQuesTemp.logicFallback) {
Line range hint
1-1000: Consider adding more specific error handling.The error handling is good but could be enhanced by adding specific error types for different scenarios. This would help in better error reporting and debugging.
Consider creating and handling specific error types for:
- Invalid filter criteria
- Cache-related errors
- Data transformation errors
Example implementation:
class InvalidFilterError extends Error { constructor(message: string) { super(message); this.name = 'InvalidFilterError'; } } class CacheError extends Error { constructor(message: string) { super(message); this.name = 'CacheError'; } }
Line range hint
1-1000: Consider splitting the file into smaller modules.The file has grown quite large and handles multiple responsibilities. Consider breaking it down into smaller, more focused modules for better maintainability.
Suggested structure:
- Create a separate module for each question type handler
- Move utility functions to a separate file
- Create a dedicated types file
- Consider using the Strategy pattern for question type handling
Example reorganization:
// questionHandlers/ // - multipleChoice.ts // - rating.ts // - openText.ts // etc. // utils/ // - validation.ts // - transformation.ts // - cache.ts // types/ // - questions.ts // - responses.ts // - summary.tsapps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx (3)
1063-1065: Consider improving readability with destructuringThe condition check could be more readable by destructuring the question properties.
- (question) => - question.logicFallback === questionId || - (question.id !== questionId && question.logic?.some(isUsedInLogicRule)) + ({ id, logicFallback, logic }) => + logicFallback === questionId || + (id !== questionId && logic?.some(isUsedInLogicRule))
1151-1163: Add JSDoc documentation for consistencyThe new function follows the pattern of other utility functions but lacks documentation. Consider adding JSDoc for consistency with other utility functions.
+/** + * Finds the index of the first question that uses the specified ending card in its logic + * @param survey - The survey to search in + * @param endingCardId - The ID of the ending card to search for + * @returns The index of the first question using the ending card, or -1 if not found + */ export const findEndingCardUsedInLogic = (survey: TSurvey, endingCardId: string): number => {
1160-1162: Consider improving readability with destructuring (similar to previous comment)For consistency with the suggested improvement above, consider destructuring here as well.
- (question) => question.logicFallback === endingCardId || question.logic?.some(isUsedInLogicRule) + ({ logicFallback, logic }) => logicFallback === endingCardId || logic?.some(isUsedInLogicRule)packages/lib/messages/de-DE.json (1)
Line range hint
1-2000: Inconsistent use of formal/informal address throughout the fileThere are inconsistencies in the use of formal ("Sie") and informal ("Du") address forms throughout the translations. For example, some sections use the informal "Du" while others use the formal "Sie", which could create an inconsistent tone of voice.
Consider standardizing the address form throughout the translations to maintain consistency. The informal "Du" form seems to be more prevalent and aligns better with modern software UI conventions.
packages/types/surveys/types.ts (2)
2032-2076: Consider returning an empty array fromvalidateLogicFallbackfor consistency.To simplify the handling of validation issues, modify
validateLogicFallbackto always return az.ZodIssue[], returning an empty array when there are no issues. This avoids the need to check forundefinedwhen combining validation results.Apply this diff to implement the change:
-const validateLogicFallback = (survey: TSurvey, questionIdx: number): z.ZodIssue[] | undefined => { +const validateLogicFallback = (survey: TSurvey, questionIdx: number): z.ZodIssue[] => { const question = survey.questions[questionIdx]; - if (!question.logicFallback) return; + if (!question.logicFallback) return []; // ... rest of the code ... }Update the
validateLogicfunction accordingly:const validateLogic = (survey: TSurvey, questionIndex: number, logic: TSurveyLogic[]): z.ZodIssue[] => { const logicFallbackIssue = validateLogicFallback(survey, questionIndex); - return [...logicIssues.flat(), ...(logicFallbackIssue ? logicFallbackIssue : [])]; + return [...logicIssues.flat(), ...logicFallbackIssue]; };
2055-2066: Simplify collection ofpossibleFallbackIds.You can improve readability by using array methods like
filterandmapto collectpossibleFallbackIds.Apply this diff to refactor the code:
- const possibleFallbackIds: string[] = []; - - survey.questions.forEach((q, idx) => { - if (idx !== questionIdx) { - possibleFallbackIds.push(q.id); - } - }); - - survey.endings.forEach((e) => { - possibleFallbackIds.push(e.id); - }); + const possibleFallbackIds = survey.questions + .filter((_, idx) => idx !== questionIdx) + .map((q) => q.id) + .concat(survey.endings.map((e) => e.id));
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (10)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx(1 hunks)apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx(3 hunks)apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx(2 hunks)apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.ts(1 hunks)packages/lib/messages/de-DE.json(2 hunks)packages/lib/messages/en-US.json(2 hunks)packages/lib/messages/pt-BR.json(2 hunks)packages/surveys/src/components/general/Survey.tsx(1 hunks)packages/types/surveys/types.ts(2 hunks)packages/types/surveys/validation.ts(1 hunks)
🔇 Additional comments (9)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (1)
5-15: LGTM: Imports are well-organized and necessary.
The new imports support the fallback logic functionality and maintain consistency with the existing codebase.
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx (1)
90-95: LGTM with minor suggestions for type safety.
The logic for clearing the fallback when removing the last logic item is sound. However, consider these improvements:
- const isLast = logicCopy.length === 1;
+ const isLast = Array.isArray(logicCopy) && logicCopy.length === 1;Let's verify the logicFallback property is properly typed in the TSurveyQuestion interface:
packages/types/surveys/validation.ts (1)
217-228: Verify edge cases in fallback logic cycle detection.
The implementation correctly checks for cyclic dependencies in fallback logic, following the same pattern as jump actions. However, there are a few edge cases to consider:
- A question could have both logic jumps and fallback logic
- The fallback chain could be very long, potentially affecting performance
Let's verify these edge cases:
✅ Verification successful
After analyzing the complete implementation, I can now provide a final response:
The cyclic logic detection implementation is robust and handles edge cases correctly
The implementation in findQuestionsWithCyclicLogic properly handles all edge cases:
- Questions with both logic jumps and fallback logic are handled sequentially - first checking jump actions, then fallback logic
- The recursive implementation with
visitedandrecStackmaps prevents infinite loops in long fallback chains - The function maintains the existing behavior of checking next questions while adding fallback logic support
The code follows the same proven depth-first search pattern used for jump actions, making it a reliable solution for detecting cycles in the question flow graph.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for questions with both logic jumps and fallback logic
# This helps us understand the complexity of logic chains
# Search for questions with both logic and logicFallback
ast-grep --pattern 'const question = {
$$$
logic: $_,
$$$
logicFallback: $_,
$$$
}'
Length of output: 95
Script:
#!/bin/bash
# Let's try a different approach to analyze the cyclic logic detection implementation
# First, let's see the full implementation of the cyclic detection function
rg -A 30 "function.*findQuestionsWithCyclicLogic"
# Then, let's look for any test cases that verify this behavior
rg -l "logicFallback.*test|test.*logicFallback"
# Also search for any interfaces or types defining the question structure
ast-grep --pattern 'interface $_ {
$$$
logicFallback?: $_
$$$
}'
Length of output: 174
Script:
#!/bin/bash
# Let's try a simpler approach focusing on the validation.ts file
# View the complete validation.ts file to understand the full context
cat packages/types/surveys/validation.ts
# Also check for any test files in the same directory
fd "validation.test" packages/types/surveys/
Length of output: 9884
packages/surveys/src/components/general/Survey.tsx (1)
261-264: Verify handling of logicFallback in all survey flows
The implementation of the logic fallback looks correct, providing a clean fallback mechanism when no jump target is determined from the logic conditions. However, we should ensure this change is properly integrated with all survey scenarios.
Let's verify the integration of logicFallback:
Consider adding a comment explaining the fallback behavior for better maintainability:
// Use logicFallback if no jump target was set
+ // This provides a default navigation path when no logic conditions are met
if (!firstJumpTarget && currQuesTemp.logicFallback) {
firstJumpTarget = currQuesTemp.logicFallback;
}✅ Verification successful
Based on the shell script results, I can now provide a final response:
Logic fallback implementation is properly integrated
The verification shows that:
- The
logicFallbackproperty is properly integrated into the survey system's type definitions and editor components - The feature is used in multiple places:
- Survey editor's logic editor component for configuration
- Survey validation in types package
- Survey flow evaluation in the main Survey component
- The implementation is consistent with the existing logic evaluation system and properly handles edge cases
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify logicFallback implementation and usage
# Check for logicFallback property definition in survey types
ast-grep --pattern 'interface TSurveyQuestion {
$$$
logicFallback?: $_
$$$
}'
# Check for logicFallback assignments in survey configuration
rg -A 3 'logicFallback.*='
# Check for potential edge cases in logic evaluation
rg -A 5 'evaluateLogic.*\('
Length of output: 11279
packages/lib/messages/en-US.json (1)
1261-1261: LGTM! Good refactoring of translation strings.
Breaking down "all_other_answers_will_continue_to_the_next_question" into two separate strings:
- "all_other_answers_will_continue_to"
- "next_question"
This improves modularity and allows for more flexible translations and string reuse.
Also applies to: 1438-1438
packages/lib/messages/pt-BR.json (1)
Line range hint 1-2000: LGTM! Overall translations look good
The Brazilian Portuguese translations are well-structured, culturally appropriate, and maintain consistent formatting throughout the file. The translations effectively convey the meaning while using natural language that would resonate with Brazilian users.
packages/lib/messages/de-DE.json (1)
Line range hint 1-2000: Verify completeness of translations for new features
Some newer features might be missing translations or using English fallbacks.
Let's verify the completeness of translations:
✅ Verification successful
Based on the search results, I can provide a final assessment of the translation completeness:
German translations are well-maintained with minimal English remnants
The scan reveals that English words appear primarily in expected contexts:
- Technical terms that are commonly left in English (e.g. "Button", "Settings", "Admin")
- Variable placeholders and code-related content (e.g. "in your settings", "click event")
- Brand names and product terms (e.g. "Formbricks")
The translations maintain high quality German with proper grammar and natural phrasing. The few English terms found are either:
- Industry standard technical terms
- Part of code examples/variables
- Intentionally preserved brand names
No concerning patterns of missing or incomplete translations were identified.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Find potential missing translations by looking for English text in the German translation file
# Look for common English words that shouldn't appear in German translations
rg -i '\b(the|and|or|with|in|on|at|to|for|is|are|was|were)\b' packages/lib/messages/de-DE.json
# Look for potential untranslated UI elements (words that are typically translated)
rg -i '\b(button|click|select|choose|settings|options|menu|file|edit|view|help)\b' packages/lib/messages/de-DE.json
Length of output: 20575
packages/types/surveys/types.ts (2)
468-468: Addition of logicFallback property is appropriate.
The optional logicFallback property correctly extends ZSurveyQuestionBase to support fallback logic in surveys.
2079-2088: Integration of validateLogicFallback into validateLogic is correct.
The validateLogic function correctly incorporates validateLogicFallback to include fallback logic validation alongside existing logic validations.
| <Select | ||
| autoComplete="true" | ||
| defaultValue={question.logicFallback || "default_selection"} | ||
| onValueChange={(val) => { | ||
| updateQuestion(questionIdx, { | ||
| logicFallback: val === "default_selection" ? undefined : val, | ||
| }); | ||
| }}> | ||
| <SelectTrigger className="w-auto bg-white"> | ||
| <SelectValue /> | ||
| </SelectTrigger> | ||
| <SelectContent> | ||
| <SelectItem key="default_selection" value={"default_selection"}> | ||
| {t("environments.surveys.edit.next_question")} | ||
| </SelectItem> | ||
| {fallbackOptions.map((option) => ( | ||
| <SelectItem key={option.value} value={option.value}> | ||
| <div className="flex items-center gap-2"> | ||
| {option.icon} | ||
| {option.label} | ||
| </div> | ||
| </SelectItem> | ||
| ))} | ||
| </SelectContent> | ||
| </Select> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Fix Select component props and enhance theme compatibility.
The Select implementation has a few minor issues that should be addressed:
Apply these fixes:
<Select
- autoComplete="true"
+ autoComplete={true}
defaultValue={question.logicFallback || "default_selection"}
onValueChange={(val) => {
updateQuestion(questionIdx, {
logicFallback: val === "default_selection" ? undefined : val,
});
}}>
- <SelectTrigger className="w-auto bg-white">
+ <SelectTrigger className="w-auto">
<SelectValue />
</SelectTrigger>
<SelectContent>
- <SelectItem key="default_selection" value={"default_selection"}>
+ <SelectItem key="fallback_default_selection" value={"default_selection"}>
{t("environments.surveys.edit.next_question")}
</SelectItem>
{fallbackOptions.map((option) => (
- <SelectItem key={option.value} value={option.value}>
+ <SelectItem key={`fallback_${option.value}`} value={option.value}>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Select | |
| autoComplete="true" | |
| defaultValue={question.logicFallback || "default_selection"} | |
| onValueChange={(val) => { | |
| updateQuestion(questionIdx, { | |
| logicFallback: val === "default_selection" ? undefined : val, | |
| }); | |
| }}> | |
| <SelectTrigger className="w-auto bg-white"> | |
| <SelectValue /> | |
| </SelectTrigger> | |
| <SelectContent> | |
| <SelectItem key="default_selection" value={"default_selection"}> | |
| {t("environments.surveys.edit.next_question")} | |
| </SelectItem> | |
| {fallbackOptions.map((option) => ( | |
| <SelectItem key={option.value} value={option.value}> | |
| <div className="flex items-center gap-2"> | |
| {option.icon} | |
| {option.label} | |
| </div> | |
| </SelectItem> | |
| ))} | |
| </SelectContent> | |
| </Select> | |
| <Select | |
| autoComplete={true} | |
| defaultValue={question.logicFallback || "default_selection"} | |
| onValueChange={(val) => { | |
| updateQuestion(questionIdx, { | |
| logicFallback: val === "default_selection" ? undefined : val, | |
| }); | |
| }}> | |
| <SelectTrigger className="w-auto"> | |
| <SelectValue /> | |
| </SelectTrigger> | |
| <SelectContent> | |
| <SelectItem key="fallback_default_selection" value={"default_selection"}> | |
| {t("environments.surveys.edit.next_question")} | |
| </SelectItem> | |
| {fallbackOptions.map((option) => ( | |
| <SelectItem key={`fallback_${option.value}`} value={option.value}> | |
| <div className="flex items-center gap-2"> | |
| {option.icon} | |
| {option.label} | |
| </div> | |
| </SelectItem> | |
| ))} | |
| </SelectContent> | |
| </Select> |
| "adjust_survey_closed_message_description": "Mude a mensagem que os visitantes veem quando a pesquisa está fechada.", | ||
| "adjust_the_theme_in_the": "Ajuste o tema no", | ||
| "all_other_answers_will_continue_to_the_next_question": "Todas as outras respostas continuarão para a próxima pergunta", | ||
| "all_other_answers_will_continue_to": "Todas as outras respostas continuarão a", |
There was a problem hiding this comment.
Fix incomplete translation string
The translation "Todas as outras respostas continuarão a" appears to be incomplete as it ends with a preposition "a" without completing the sentence. This could cause confusion for users.
Please complete the translation by adding what the answers will continue to do, for example:
- "Todas as outras respostas continuarão a próxima pergunta" or
- "Todas as outras respostas continuarão ao próximo passo"
| "adjust_survey_closed_message_description": "Ändere die Nachricht, die Besucher sehen, wenn die Umfrage geschlossen ist.", | ||
| "adjust_the_theme_in_the": "Passe das Thema an in den", | ||
| "all_other_answers_will_continue_to_the_next_question": "Alle anderen Antworten führen zur nächsten Frage", | ||
| "all_other_answers_will_continue_to": "Alle anderen Antworten werden weiterhin", |
There was a problem hiding this comment.
Incomplete translation needs attention
The translation "Alle anderen Antworten werden weiterhin" appears to be incomplete as it lacks the completion of the sentence. The phrase ends abruptly without specifying what happens with other answers.
Consider completing the sentence to properly convey the intended meaning.
...rvey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx
Outdated
Show resolved
Hide resolved
| return survey.questions.findIndex((question) => question.logic?.some(isUsedInLogicRule)); | ||
| }; | ||
|
|
||
| export const findEndingCardUsedInLogic = (survey: TSurvey, endingCardId: string): number => { |
There was a problem hiding this comment.
I couldn't find any implmentations of this function, pls use this or remove if its not required
…406-logic-allow-all-other-questions-to-be-changed
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (4)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (2)
38-65: Enhance the fallback options implementation.A few suggestions to improve the code:
+ interface FallbackOption { + icon?: ReactElement; + label: string; + value: string; + } const fallbackOptions = useMemo(() => { - let options: { - icon?: ReactElement; - label: string; - value: string; - }[] = []; + const availableOptions: FallbackOption[] = []; localSurvey.questions.forEach((ques) => { - if (ques.id === question.id) return null; + if (ques.id === question.id) return; options.push({ icon: QUESTIONS_ICON_MAP[ques.type], label: getLocalizedValue(ques.headline, "default"), value: ques.id, }); });
91-115: Extract string literals into constants.Consider extracting the repeated string literal into a constant for better maintainability:
+ const DEFAULT_SELECTION_VALUE = "defaultSelection"; <Select autoComplete={true} - defaultValue={question.logicFallback || "defaultSelection"} + defaultValue={question.logicFallback || DEFAULT_SELECTION_VALUE} onValueChange={(val) => { updateQuestion(questionIdx, { - logicFallback: val === "defaultSelection" ? undefined : val, + logicFallback: val === DEFAULT_SELECTION_VALUE ? undefined : val, }); }}> ... <SelectContent> <SelectItem key="fallback_default_selection" - value={"defaultSelection"} + value={DEFAULT_SELECTION_VALUE} >apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/EditEndingCard.tsx (1)
104-104: Consider enhancing the error message for better clarityThe current error message uses array index + 1 to show the question number. This might be confusing if questions can be reordered or if some questions are hidden/inactive.
Consider modifying the error message to include more context:
-toast.error(t("environments.surveys.edit.ending_card_used_in_logic", { questionIndex: quesIdx + 1 })); +toast.error(t("environments.surveys.edit.ending_card_used_in_logic", { + questionIndex: quesIdx + 1, + questionTitle: localSurvey.questions[quesIdx].headline[selectedLanguageCode] || `Question ${quesIdx + 1}` +}));You'll also need to update the translation key to include the question title in the message.
packages/types/surveys/types.ts (1)
2037-2045: Optimize the condition checkThe condition can be simplified using short-circuit evaluation.
- if (!question.logic?.length && question.logicFallback) { + if (!question.logic?.length) {This works because we already check for
logicFallbackexistence at line 2035.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (8)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/EditEndingCard.tsx(2 hunks)apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx(3 hunks)apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.ts(1 hunks)packages/lib/messages/de-DE.json(3 hunks)packages/lib/messages/en-US.json(3 hunks)packages/lib/messages/pt-BR.json(3 hunks)packages/surveys/src/components/general/Survey.tsx(1 hunks)packages/types/surveys/types.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.ts
- packages/lib/messages/de-DE.json
- packages/lib/messages/en-US.json
- packages/lib/messages/pt-BR.json
- packages/surveys/src/components/general/Survey.tsx
🔇 Additional comments (6)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (1)
91-115: Verify integration with survey logic evaluation.
The fallback logic implementation looks good, but let's ensure it's properly integrated with the survey logic evaluation system.
✅ Verification successful
Based on the gathered information, I can now provide the final response as the implementation details are clear. The logicFallback is properly integrated across the codebase with:
- Type definitions and validation in
types.ts - Cyclic dependency checks in
validation.ts - Logic evaluation in
Survey.tsx - Usage tracking in
utils.tsx - Proper state management in
ConditionalLogic.tsx
The logicFallback implementation is correctly integrated with the survey logic evaluation system
The implementation:
- Has proper type safety and validation
- Prevents cyclic logic paths
- Correctly evaluates fallback logic during survey execution
- Maintains consistency when questions are modified
- Properly handles the relationship with other logic rules
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the integration of logicFallback with survey logic evaluation
# Check for logicFallback usage in survey logic evaluation
echo "Checking for logicFallback usage in survey logic evaluation..."
rg -l "logicFallback" --type ts
# Check for potential validation implementations
echo "Checking for validation implementations..."
ast-grep --pattern 'function $_(logicFallback: $_) {
$$$
}'
Length of output: 889
Script:
#!/bin/bash
# Let's examine the implementation details in key files
# Check the types definition
echo "=== Checking types definition ==="
cat packages/types/surveys/types.ts | grep -A 10 "logicFallback"
# Check validation implementation
echo -e "\n=== Checking validation implementation ==="
cat packages/types/surveys/validation.ts | grep -A 10 "logicFallback"
# Check survey logic evaluation
echo -e "\n=== Checking survey logic evaluation ==="
cat packages/surveys/src/components/general/Survey.tsx | grep -A 10 "logicFallback"
# Check utils implementation
echo -e "\n=== Checking utils implementation ==="
cat "apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx" | grep -A 10 "logicFallback"
# Check conditional logic implementation
echo -e "\n=== Checking conditional logic implementation ==="
cat "apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx" | grep -A 10 "logicFallback"
Length of output: 5163
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/EditEndingCard.tsx (2)
6-9: LGTM: Import statements are properly structured
The new imports support the enhanced functionality for checking logic dependencies and error notifications.
Also applies to: 16-16
100-106: LGTM: Added safety check before deleting ending cards
The implementation correctly prevents deletion of ending cards that are referenced in survey logic, maintaining data integrity.
packages/types/surveys/types.ts (3)
468-468: LGTM: logicFallback property addition
The new logicFallback property is correctly typed as an optional ZSurveyQuestionId, ensuring consistent ID validation across the survey system.
2079-2088: LGTM: Clean integration of logicFallback validation
The integration preserves the existing validation structure while properly incorporating the new logicFallback validation. The spread operator usage ensures all validation results are properly combined.
2032-2076: Verify validation coverage for edge cases
The validation logic looks solid but let's verify coverage for all edge cases.
✅ Verification successful
Based on the comprehensive analysis of the codebase, I can now provide the final response:
The validation logic is robust and covers all critical edge cases
The implementation handles all important scenarios:
- Validates fallback logic without any conditional logic
- Prevents self-referential fallback logic
- Validates existence of fallback question ID
- Detects and prevents cyclic logic paths through both conditional logic and fallback logic
- Integrates with the broader survey validation system
The cyclic logic detection is particularly thorough, covering:
- Direct cycles through fallback logic
- Indirect cycles through question chains
- Combinations of conditional jumps and fallback logic
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for potential edge cases in the codebase
# Test: Search for existing logicFallback usage patterns
# Look for any existing logicFallback implementations
rg -l "logicFallback"
# Look for any logic-related test files
fd -e test.ts -e spec.ts | rg -i "logic"
Length of output: 626
Script:
#!/bin/bash
# Let's analyze the implementation and test coverage
# Check the validation implementation
rg -A 10 "logicFallback" packages/types/surveys/validation.ts
# Look for test cases in the codebase
rg -A 10 "validateLogicFallback" --type ts
# Check the actual usage in components to understand edge cases
rg -A 5 "logicFallback" packages/surveys/src/components/general/Survey.tsx
# Check logic editor implementation for potential edge cases
rg -A 5 "logicFallback" 'apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx'
Length of output: 3101
Script:
#!/bin/bash
# Let's check for cyclic logic validation and other edge cases
# Check cyclic logic validation implementation
ast-grep --pattern 'function checkForCyclicLogic($_) {
$$$
}'
# Look for any test cases involving cyclic logic
rg -B 5 -A 10 "cyclic.*logic" --type ts -i
# Check the schema definition to understand the complete logic structure
rg -A 10 "logicFallback.*z\." --type ts
Length of output: 12987
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (1)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyMenuBar.tsx (1)
347-347: Consider accessibility improvements for the tooltip textThe tooltip text is correctly using the pre-translated
cautionTextvariable. However, to improve accessibility and user experience:
- Consider adding an
aria-labelto the tooltip trigger for screen readers- The text size (
text-xs) might be too small for comfortable reading- <p className="py-2 text-center text-xs text-slate-500 dark:text-slate-400">{cautionText}</p> + <p className="py-2 text-center text-sm text-slate-500 dark:text-slate-400" role="tooltip">{cautionText}</p>Additionally, consider adding an aria-label to the trigger:
- <AlertTriangleIcon className="h-5 w-5 text-amber-400" /> + <AlertTriangleIcon className="h-5 w-5 text-amber-400" aria-label="Warning about survey changes" />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyMenuBar.tsx(1 hunks)
🔇 Additional comments (1)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyMenuBar.tsx (1)
Line range hint 183-235: Verify validation handling for new logic fallback feature
The validateSurveyWithZod function uses the ZSurvey schema for validation. Since this PR introduces logic fallback options, we should verify that this validation properly handles the new feature.

What does this PR do?
logic fallback option added
Fixes https://github.com/formbricks/internal/issues/406
How should this be tested?
Checklist
Required
pnpm buildconsole.logsgit pull origin mainAppreciated
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Localization Updates