-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
improvement: status type | edit/create mode #3185
base: develop
Are you sure you want to change the base?
improvement: status type | edit/create mode #3185
Conversation
WalkthroughThe pull request introduces several enhancements across multiple files, including new functions for fetching SVGs, determining text color, and managing task statuses with dynamic colors and icons. Localization files have been updated to include new keys for sorting and icons in various languages. The changes do not affect existing functionalities but expand the capabilities of the application, particularly in terms of visual representation and internationalization. Changes
Assessment against linked issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
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 (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Outside diff range and nitpick comments (4)
apps/web/app/services/server/fetch.ts (1)
58-61
: Add JSDoc documentation for the SVG fetch function.The function lacks documentation about its purpose, parameters, and usage.
Add comprehensive documentation:
+/** + * Fetches SVG content from a given URL with validation and error handling. + * + * @param url - The URL of the SVG resource to fetch + * @returns A Promise that resolves to the Response containing the SVG content + * @throws {Error} If the URL is invalid, the response is not OK, or the content is not SVG + * + * @example + * ```typescript + * try { + * const svgResponse = await fetchSvgContent('https://example.com/icon.svg'); + * const svgContent = await svgResponse.text(); + * } catch (error) { + * console.error('Failed to fetch SVG:', error); + * } + * ``` + */ export async function svgFetch(url: string): Promise<Response> {apps/web/lib/settings/icon-items.tsx (1)
Line range hint
68-89
: Consider improvements to the conditional rendering and error handling.Several suggestions to enhance the component:
- The fallback case ignores the
title
prop, which might be unexpected- The Image component lacks error handling for failed loads
- The translation key could be defined as a constant to avoid magic strings
Consider applying these improvements:
+ const ICON_TRANSLATION_KEY = 'common.ICON'; + return ( <div title={title} className={clsxm( 'flex items-center justify-start space-x-2 text-sm', 'cursor-pointer mb-4 max-w-full', className )} > <div> {url ? ( <div className={clsxm( 'w-[17px] h-[17px]', 'flex justify-center items-center', 'rounded-full text-xs text-default dark:text-white', disabled && ['dark:text-default'] )} > <Image src={url} alt={title || ''} width={20} height={20} decoding="async" data-nimg="1" loading="lazy" + onError={(e) => { + e.currentTarget.src = ''; // Add fallback image URL + }} /> </div> ) : ( - <span>{t('common.ICON')}</span> + <span>{title || t(ICON_TRANSLATION_KEY)}</span> )} </div> </div> );apps/web/lib/settings/task-statuses-form.tsx (1)
33-34
: Consider initializing randomColor with a valueInitialize
randomColor
with a random color value to avoid undefined states in the UI. This ensures the color picker always has a valid initial value.-const [randomColor, setRandomColor] = useState<string | undefined>(undefined); +const [randomColor, setRandomColor] = useState<string>(() => { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +});apps/web/lib/features/task/task-status.tsx (1)
857-858
: Consider handling edge cases in color determination.While the implementation looks good, consider these improvements:
- The fallback color 'white' might not be suitable for all themes
- The background color could be undefined when active is false
Consider this improvement:
style={{ backgroundColor: active ? backgroundColor : undefined, - color: getTextColor(backgroundColor ?? 'white') + color: getTextColor(backgroundColor ?? (theme === 'dark' ? '#1B1D22' : 'white')) }}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (18)
- apps/web/app/services/server/fetch.ts (1 hunks)
- apps/web/lib/features/task/task-status.tsx (3 hunks)
- apps/web/lib/settings/icon-items.tsx (4 hunks)
- apps/web/lib/settings/list-card.tsx (4 hunks)
- apps/web/lib/settings/task-statuses-form.tsx (8 hunks)
- apps/web/locales/ar.json (1 hunks)
- apps/web/locales/bg.json (1 hunks)
- apps/web/locales/de.json (1 hunks)
- apps/web/locales/en.json (1 hunks)
- apps/web/locales/es.json (1 hunks)
- apps/web/locales/fr.json (1 hunks)
- apps/web/locales/he.json (1 hunks)
- apps/web/locales/it.json (1 hunks)
- apps/web/locales/nl.json (1 hunks)
- apps/web/locales/pl.json (1 hunks)
- apps/web/locales/pt.json (1 hunks)
- apps/web/locales/ru.json (1 hunks)
- apps/web/locales/zh.json (1 hunks)
🔇 Additional comments (23)
apps/web/app/services/server/fetch.ts (1)
58-61
: Verify SVG fetch usage across the codebase.Let's ensure this new function is properly integrated with other components that need SVG fetching.
✅ Verification successful
The new
svgFetch
function is only used in one place for loading SVG iconsThe codebase analysis shows that the
svgFetch
function is only used inapps/web/lib/settings/list-card.tsx
for loading SVG icons in theloadSVG
function. All other SVG usages in the codebase are static imports or direct path references. The function's current implementation is appropriate for its limited usage.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Find potential usage points of SVG fetching in the codebase echo "Searching for SVG-related fetch calls..." rg -l "fetch.*svg|loadSVG|getSVG" --type ts --type tsx echo -e "\nSearching for SVG URL patterns..." rg "\.svg['\"]|/icons?/|/images?/" --type ts --type tsxLength of output: 346
Script:
#!/bin/bash # Let's try a different approach to find SVG-related patterns # First, let's find all TypeScript files echo "Finding TypeScript files with SVG-related patterns..." rg -t ts "\.svg|fetch.*svg|loadSVG|getSVG|/icons?/|/images?/" -l echo -e "\nChecking for actual implementations and usages..." rg -t ts "\.svg|fetch.*svg|loadSVG|getSVG" -C 2Length of output: 23920
apps/web/lib/settings/icon-items.tsx (3)
5-5
: LGTM: Clean import addition for internationalization.The addition of
useTranslations
hook import is well-placed and aligns with the internationalization requirements.
57-57
: LGTM: Clean hook initialization.The translation hook is properly initialized at the component level.
88-88
: Verify translation key existence and consistency.Let's ensure the translation key is properly defined across all language files.
✅ Verification successful
Translation key is properly defined and consistent across all locales
The translation key 'ICON' is correctly defined in all language files (ar, bg, de, en, es, fr, he, it, nl, pl, pt, ru, zh) with appropriate translations for each locale. The usage in the code as
t('common.ICON')
is valid.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check for the translation key in language files echo "Checking for 'common.ICON' translation key in language files..." rg -l '"ICON"' apps/web/messages/Length of output: 237
Script:
#!/bin/bash # First, let's find the correct location of translation files fd -t f "en.json|de.json|fr.json|es.json" -x echo "=== {} ===" \; cat {} # Also search for any usage of this translation key in the codebase echo -e "\n=== Searching for translation key usage ===" rg "common\.ICON"Length of output: 414
Script:
#!/bin/bash # Let's try a different approach to find translation files echo "=== Looking for translation files ===" fd -t f -e json . apps/web # Let's also check the package.json to understand the i18n setup echo -e "\n=== Checking package.json for i18n configuration ===" fd -t f "package.json" -x cat {}Length of output: 37255
Script:
#!/bin/bash # Let's check the content of translation files to verify the key echo "=== Checking translation files for 'common.ICON' key ===" fd -t f -e json . apps/web/locales -x echo "=== {} ===" \; cat {} # Also let's check for any other similar translation keys echo -e "\n=== Checking for similar translation keys ===" rg "ICON" apps/web/locales/Length of output: 1418
apps/web/lib/settings/list-card.tsx (1)
8-9
: LGTM! Imports are correctly added.The new imports are necessary for the component's enhanced functionality.
apps/web/locales/zh.json (1)
232-234
: LGTM! The translations are accurate and well-formatted.The new Chinese translations for "MOVE_TO", "SORT", and "ICON" are correctly implemented and maintain consistency with the existing localization structure.
apps/web/locales/he.json (1)
232-234
: LGTM! Verify consistency across other language files.The Hebrew translations for the new keys look correct and properly formatted.
Let's verify that these translations are consistently added across all mentioned language files:
✅ Verification successful
Translations for "SORT" and "ICON" are consistently present across all language files ✅
The verification confirms that both "SORT" and "ICON" keys are properly added with appropriate translations in all checked language files (ar, bg, de, es, fr, it, nl, pl, pt, ru, zh), maintaining consistency across the entire localization system.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check if SORT and ICON keys are present in all language files # Expected: All language files should have these keys # Test: Check for SORT and ICON keys in all JSON files for lang in ar bg de es fr it nl pl pt ru zh; do echo "Checking $lang.json:" rg -A 1 '"SORT":' "apps/web/locales/$lang.json" rg -A 1 '"ICON":' "apps/web/locales/$lang.json" doneLength of output: 2672
apps/web/locales/ar.json (2)
232-232
: LGTM: Valid JSON syntax.The trailing comma addition maintains proper JSON formatting and enables easier version control diffs for future additions.
233-234
: LGTM: New translations look accurate.The Arabic translations for "SORT" (فرز) and "ICON" (أيقونة) are correct and commonly used terms in Arabic UI localization. They appropriately maintain RTL (Right-to-Left) text direction which is crucial for Arabic language support.
Let's verify the consistency of these new keys across other language files:
✅ Verification successful
Translation keys are consistent across all locale files ✓
The verification confirms that both "SORT" and "ICON" keys are properly implemented across all language files (ar, bg, de, en, es, fr, he, it, nl, pl, pt, ru, zh) with appropriate translations for each language. The Arabic translations align well with the localization patterns used in other languages.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check if the new keys exist in other locale files # Test: Search for SORT and ICON keys in all locale files rg '"SORT":|"ICON":' apps/web/locales/Length of output: 1188
apps/web/locales/en.json (1)
232-234
: LGTM! Verify usage of new translations.The new translations are clear and maintain consistency with the existing structure.
Let's verify that these new translations are being used in the UI components:
✅ Verification successful
✓ New translations are properly used in the UI
The new translation keys are actively used in the codebase:
- "SORT" is used in
apps/web/lib/settings/task-statuses-form.tsx
- "ICON" is used in
apps/web/lib/settings/icon-items.tsx
- Both translations are properly integrated across multiple language files in both web and desktop apps
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for the usage of new translation keys in the codebase echo "Searching for SORT translation key usage:" rg "['\"](common\.)?SORT['\"]" --type ts --type tsx echo "Searching for ICON translation key usage:" rg "['\"](common\.)?ICON['\"]" --type ts --type tsxLength of output: 357
Script:
#!/bin/bash # Search for the usage of new translation keys in the codebase echo "Searching for SORT translation key usage:" rg "['\"](common\.)?SORT['\"]" echo -e "\nSearching for ICON translation key usage:" rg "['\"](common\.)?ICON['\"]" # Also search for t function calls which might use these keys echo -e "\nSearching for t function calls with these keys:" rg "t\(['\"](?:common\.)?(?:SORT|ICON)['\"]"Length of output: 2532
apps/web/locales/nl.json (1)
232-234
: LGTM! The new translations are well-structured and accurate.The additions follow the existing conventions and provide correct Dutch translations for the new keys.
apps/web/locales/bg.json (1)
232-234
: LGTM! Verify consistency across language files.The changes look good. The new translations for sorting and icons are properly added, and the comma after "MOVE_TO" maintains valid JSON syntax.
Let's verify that these keys exist across all language files:
✅ Verification successful
All translation keys are present and properly translated across language files
The verification confirms that both "SORT" and "ICON" keys are consistently present across all language files (ar, bg, de, en, es, fr, he, it, nl, pl, pt, ru, zh) with appropriate translations for each language.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check if SORT and ICON keys exist in all language files # Expected: All language files should have these keys # Test: Search for SORT and ICON keys in all locale files echo "Checking SORT key..." rg '"SORT"' apps/web/locales/ echo "Checking ICON key..." rg '"ICON"' apps/web/locales/Length of output: 1313
apps/web/locales/pl.json (1)
232-234
: LGTM! The translations are properly structured and consistent.The changes maintain proper JSON syntax and follow the localization patterns:
- Added trailing comma after "MOVE_TO" translation
- Added Polish translations for "SORT" ("Sortuj") and "ICON" ("Ikona")
apps/web/locales/it.json (1)
232-234
: LGTM! The new localization keys are properly structured.The added Italian translations for sorting and icon functionality maintain consistency with the existing localization patterns and appear to be grammatically correct.
apps/web/locales/ru.json (2)
232-234
: LGTM! Translations and syntax are correct.The changes look good:
- The trailing comma after "MOVE_TO" maintains proper JSON syntax
- The new translations for "SORT" ("Сортировать") and "ICON" ("Иконка") are accurate Russian translations
- The changes are consistent with other language files mentioned in the summary
232-234
: Verify consistency across all language files.Let's ensure the new keys are present in all language files with proper translations.
✅ Verification successful
Let me try a different script to properly check the structure and content of these files.
Translation keys are consistent across all language files ✓
The verification shows that both
SORT
andICON
keys are present in all language files (ar, bg, de, en, es, fr, he, it, nl, pl, pt, ru, zh) with appropriate translations for each language. The keys are correctly placed under thecommon
section as expected.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check if all language files have the required keys # Expected: All language files should have SORT and ICON keys under the common section echo "Checking language files for required keys..." for lang_file in $(fd -e json . apps/web/locales); do echo "Checking $lang_file..." # Check if the file has the required keys jq -r '.common | select(.SORT == null or .ICON == null) | path | join(".")' "$lang_file" if [ $? -eq 0 ]; then echo "✓ File has all required keys" else echo "⚠ Missing required keys" fi doneLength of output: 6748
Script:
#!/bin/bash # Let's first check the actual structure of one of the files to understand how they're organized echo "Checking structure of ru.json:" cat apps/web/locales/ru.json | head -n 10 echo -e "\nNow checking for SORT and ICON keys in all locale files:" for lang_file in $(fd -e json . apps/web/locales); do echo -e "\nFile: $lang_file" # Search for the exact keys, showing 2 lines of context rg -A 2 '"(SORT|ICON)":\s*"' "$lang_file" doneLength of output: 3621
apps/web/locales/pt.json (1)
232-234
: LGTM! Translations are accurate and well-formatted.The new translations maintain consistency with the existing localization patterns and correctly handle Portuguese accents.
apps/web/locales/es.json (2)
232-232
: LGTM: Proper JSON syntax correction.The added comma after the "MOVE_TO" entry is correct and necessary for valid JSON syntax.
233-234
: LGTM: Accurate Spanish translations added.The new translations are linguistically correct:
- "SORT" → "Ordenar"
- "ICON" → "Ícono"
Both translations are accurate and properly use Spanish diacritical marks.
Let's verify the consistency of these new keys across other language files:
✅ Verification successful
Let me verify the actual content of these keys in all language files to ensure they are properly translated and not missing.
Spanish translations are consistent with other language files
The Spanish translations "Ordenar" for "SORT" and "Ícono" for "ICON" are properly implemented and consistent with the translations in all other language files. Each language file contains appropriate translations that reflect the correct meaning in their respective languages, including proper use of diacritical marks where needed (e.g. "Ícono" in Spanish and Portuguese, "Icône" in French).
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check if the new keys (SORT, ICON) exist in other language files # Expected: These keys should be present in all language files echo "Checking for SORT and ICON keys in all language files..." rg -l '"SORT":|"ICON":' apps/web/locales/Length of output: 491
Script:
#!/bin/bash # Check the actual values of SORT and ICON in all locale files for file in $(find apps/web/locales -name "*.json"); do echo "=== $file ===" rg -A 1 '"SORT":|"ICON":' "$file" doneLength of output: 2955
apps/web/locales/de.json (1)
232-234
: LGTM! Verify translations across all language files.The German translations look appropriate:
- "SORT": "Sortieren" (correct German translation for "Sort")
- "ICON": "Symbol" (correct German translation for "Icon")
Let's verify that these new keys are consistently added across all language files mentioned in the AI summary:
✅ Verification successful
Both "SORT" and "ICON" keys are consistently present across all language files ✅
The verification shows that:
- "SORT" key is present in all 13 language files (ar, bg, de, en, es, fr, he, it, nl, pl, pt, ru, zh)
- "ICON" key is present in all 13 language files with appropriate translations
- Each translation appears culturally and linguistically appropriate for its target language
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check if the new keys "SORT" and "ICON" are present in all language files # Expected: All language files should have these keys with appropriate translations # Test: Search for SORT and ICON keys in all locale files echo "Checking SORT translations:" rg '"SORT"' apps/web/locales/ echo -e "\nChecking ICON translations:" rg '"ICON"' apps/web/locales/Length of output: 1347
apps/web/locales/fr.json (1)
232-234
: LGTM! Verify translations across all locale files.The French translations for "MOVE_TO", "SORT", and "ICON" are linguistically accurate and properly formatted.
Let's verify the consistency of these new keys across other locale files:
✅ Verification successful
All translation keys are properly synchronized across locale files
Based on the verification results:
- "SORT" and "ICON" are present and properly translated in all web locale files (en, fr, de, es, it, nl, pl, pt, ru, zh, ar, bg, he)
- "MOVE_TO" is also present and correctly translated across all locale files
- The French translations are linguistically accurate:
- "MOVE_TO": "Déplacer vers"
- "SORT": "Trier"
- "ICON": "Icône"
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check if the new keys exist in all locale files # Expected: All locale files should have these keys # Find all locale files and check for the presence of the new keys fd -e json -x sh -c 'echo "=== Checking {}" && jq -r ".common | select(.SORT != null and .ICON != null) | {SORT, ICON}" {}' . apps/web/locales/Length of output: 3299
Script:
#!/bin/bash # Let's check for the MOVE_TO key specifically since it wasn't captured in the previous query fd -e json -x sh -c 'echo "=== Checking {}" && jq -r ".common.MOVE_TO" {}' . apps/web/locales/Length of output: 3083
apps/web/lib/features/task/task-status.tsx (2)
36-36
: LGTM: Good addition of contrast helper.The import of
getTextColor
helper function is a good practice for ensuring text readability by dynamically determining the text color based on the background color.
1032-1032
: LGTM: Consistent height styling.The addition of "h-full" className to the Tooltip component maintains consistency with the styling approach used throughout the file.
export async function svgFetch(url: string): Promise<Response> { | ||
// Fetch the SVG | ||
return await fetch(url); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider implementing caching for SVG responses.
For better performance and reduced network calls, consider implementing a caching strategy for SVG responses.
Here's a suggested implementation using a simple in-memory cache:
const svgCache = new Map<string, {
content: Response,
timestamp: number
}>();
const CACHE_DURATION = 1000 * 60 * 60; // 1 hour
export async function fetchSvgContent(url: string): Promise<Response> {
const cached = svgCache.get(url);
const now = Date.now();
if (cached && (now - cached.timestamp) < CACHE_DURATION) {
return cached.content.clone();
}
const response = await /* previous implementation */;
svgCache.set(url, {
content: response.clone(),
timestamp: now
});
return response;
}
Add input validation and error handling for SVG fetching.
The current implementation lacks several important safety checks and error handling mechanisms:
- URL validation
- Response type verification
- Error handling
- Timeout handling
Consider implementing these improvements:
-export async function svgFetch(url: string): Promise<Response> {
- // Fetch the SVG
- return await fetch(url);
+export async function fetchSvgContent(url: string): Promise<Response> {
+ try {
+ // Validate URL
+ const validUrl = new URL(url);
+
+ const response = await fetch(validUrl.toString(), {
+ timeout: 5000,
+ headers: {
+ 'Accept': 'image/svg+xml'
+ }
+ });
+
+ if (!response.ok) {
+ throw new Error(`Failed to fetch SVG: ${response.statusText}`);
+ }
+
+ const contentType = response.headers.get('content-type');
+ if (!contentType?.includes('svg')) {
+ throw new Error('Response is not an SVG image');
+ }
+
+ return response;
+ } catch (error) {
+ if (error instanceof Error) {
+ throw new Error(`SVG fetch failed: ${error.message}`);
+ }
+ throw new Error('Unknown error occurred while fetching SVG');
+ }
+}
📝 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.
export async function svgFetch(url: string): Promise<Response> { | |
// Fetch the SVG | |
return await fetch(url); | |
} | |
export async function fetchSvgContent(url: string): Promise<Response> { | |
try { | |
// Validate URL | |
const validUrl = new URL(url); | |
const response = await fetch(validUrl.toString(), { | |
timeout: 5000, | |
headers: { | |
'Accept': 'image/svg+xml' | |
} | |
}); | |
if (!response.ok) { | |
throw new Error(`Failed to fetch SVG: ${response.statusText}`); | |
} | |
const contentType = response.headers.get('content-type'); | |
if (!contentType?.includes('svg')) { | |
throw new Error('Response is not an SVG image'); | |
} | |
return response; | |
} catch (error) { | |
if (error instanceof Error) { | |
throw new Error(`SVG fetch failed: ${error.message}`); | |
} | |
throw new Error('Unknown error occurred while fetching SVG'); | |
} | |
} |
className="min-h-[20px]" | ||
/> | ||
)} | ||
{statusIcon && <div id={'icon-container' + statusTitle}></div>} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve ID generation security and uniqueness.
The current ID generation method has potential security and uniqueness issues:
- No sanitization of statusTitle when used in ID
- Non-unique IDs if multiple instances have the same title
Consider using a more secure approach:
-{statusIcon && <div id={'icon-container' + statusTitle}></div>}
+{statusIcon && (
+ <div
+ id={`icon-container-${encodeURIComponent(statusTitle)}-${Math.random().toString(36).substr(2, 9)}`}
+ />
+)}
📝 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.
{statusIcon && <div id={'icon-container' + statusTitle}></div>} | |
{statusIcon && ( | |
<div | |
id={`icon-container-${encodeURIComponent(statusTitle)}-${Math.random().toString(36).substr(2, 9)}`} | |
/> | |
)} |
useEffect(() => { | ||
loadSVG(statusIcon, 'icon-container' + statusTitle, textColor); | ||
}, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add missing dependencies and cleanup to useEffect.
The current implementation has several issues:
- Missing dependencies:
statusIcon
andtextColor
should be in the dependency array - No cleanup handling for unmounting during SVG loading
Here's the suggested fix:
useEffect(() => {
- loadSVG(statusIcon, 'icon-container' + statusTitle, textColor);
+ let mounted = true;
+ const loadIcon = async () => {
+ if (mounted) {
+ await loadSVG(statusIcon, 'icon-container' + statusTitle, textColor);
+ }
+ };
+ loadIcon();
+ return () => {
+ mounted = false;
+ };
-}, []);
+}, [statusIcon, statusTitle, textColor]);
📝 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.
useEffect(() => { | |
loadSVG(statusIcon, 'icon-container' + statusTitle, textColor); | |
}, []); | |
useEffect(() => { | |
let mounted = true; | |
const loadIcon = async () => { | |
if (mounted) { | |
await loadSVG(statusIcon, 'icon-container' + statusTitle, textColor); | |
} | |
}; | |
loadIcon(); | |
return () => { | |
mounted = false; | |
}; | |
}, [statusIcon, statusTitle, textColor]); |
const loadSVG = async (url: string, containerId: string, color: string): Promise<void> => { | ||
try { | ||
const response = await svgFetch(url); | ||
|
||
if (!response.ok) { | ||
throw new Error(`Failed to fetch SVG: ${response.statusText}`); | ||
} | ||
|
||
let svgContent = await response.text(); | ||
|
||
// Update the fill color in the SVG content | ||
svgContent = svgContent.replace(/stroke="[^"]*"/g, `stroke="${color}"`); | ||
|
||
const container = document.getElementById(containerId); | ||
|
||
if (container) { | ||
container.innerHTML = svgContent; | ||
} else { | ||
console.error(`Container with ID "${containerId}" not found.`); | ||
} | ||
} catch (error) { | ||
console.error(`Error loading SVG: ${(error as Error).message}`); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Based on the context gathered, I can now generate the final response:
Security improvements needed for SVG loading implementation
The current implementation in list-card.tsx
loads SVGs from status icons and directly injects them using innerHTML, which poses security risks. However, the usage context shows this is specifically for status icons within a controlled environment, where:
- SVGs are loaded via
svgFetch
service, suggesting a controlled fetching mechanism - The usage is limited to status icons within the settings list card component
- The color modification is specifically for status indication
While the security concerns are valid, here's a more targeted improvement suggestion:
const loadSVG = async (url: string, containerId: string, color: string): Promise<void> => {
try {
const response = await svgFetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch SVG: ${response.statusText}`);
}
const parser = new DOMParser();
const svgDoc = parser.parseFromString(await response.text(), 'image/svg+xml');
// Verify we have an SVG element
const svgElement = svgDoc.querySelector('svg');
if (!svgElement) {
throw new Error('Invalid SVG content');
}
// Update stroke colors
svgElement.querySelectorAll('*').forEach(el => {
if (el instanceof Element && el.hasAttribute('stroke')) {
el.setAttribute('stroke', color);
}
});
const container = document.getElementById(containerId);
if (container) {
container.replaceChildren(svgElement);
}
} catch (error) {
console.error(`Error loading SVG: ${(error as Error).message}`);
}
};
- Consider adding a whitelist of allowed SVG attributes to further restrict potential XSS vectors
- Add MIME type validation in the
svgFetch
service
🔗 Analysis chain
Enhance SVG loading security and robustness.
The current implementation has several security and reliability concerns:
- Direct innerHTML usage is vulnerable to XSS
- Simple regex replacement might miss complex SVG color attributes
- No sanitization of SVG content before insertion
Consider implementing these security improvements:
const loadSVG = async (url: string, containerId: string, color: string): Promise<void> => {
try {
const response = await svgFetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch SVG: ${response.statusText}`);
}
let svgContent = await response.text();
+
+ // Create a DOMParser to safely parse the SVG
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(svgContent, 'image/svg+xml');
+
+ // Validate that we received an SVG
+ if (doc.documentElement.tagName !== 'svg') {
+ throw new Error('Invalid SVG content');
+ }
+
+ // Update colors using DOM methods instead of regex
+ const elements = doc.querySelectorAll('*');
+ elements.forEach(el => {
+ if (el.hasAttribute('stroke')) {
+ el.setAttribute('stroke', color);
+ }
+ });
const container = document.getElementById(containerId);
if (container) {
- container.innerHTML = svgContent;
+ // Clear existing content
+ while (container.firstChild) {
+ container.removeChild(container.firstChild);
+ }
+ // Safely append the new SVG
+ container.appendChild(doc.documentElement);
} else {
console.error(`Container with ID "${containerId}" not found.`);
}
} catch (error) {
console.error(`Error loading SVG: ${(error as Error).message}`);
}
};
Additionally, consider implementing a content security policy (CSP) to restrict SVG sources to trusted domains.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if we have any Content-Security-Policy headers defined
rg -l "Content-Security-Policy" --type-add 'config:*.{json,js,ts}' -t config
Length of output: 76
Script:
#!/bin/bash
# Let's check where this SVG loading function is used and what SVG sources are being loaded
rg -A 2 "loadSVG\("
# Also check for any existing SVG security measures or sanitization
rg -l "DOMParser|createElementNS|sanitize.*svg" --type=typescript
# Check for any SVG-related utility functions or components
fd -e ts -e tsx -X rg "svg" -l
Length of output: 10728
Script:
#!/bin/bash
# Let's check the svgFetch implementation and where SVGs are being loaded from
rg -A 5 "svgFetch" --type=typescript
# Check the specific usage context in list-card.tsx
cat "apps/web/lib/settings/list-card.tsx"
# Look for any existing security configurations or middleware
rg -l "security|sanitize|xss" --type=typescript
Length of output: 3616
onValueChange={(status) => { | ||
setValue('template', status) | ||
setSelectedStatusType(status) | ||
} } | ||
className="h-14 shrink-0" | ||
defaultValue={edit?.value} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle defaultValue prop consistently
The defaultValue
prop is only set for edit mode, which might lead to unexpected behavior when creating a new status.
<StandardTaskStatusDropDown
onValueChange={(status) => {
setValue('template', status)
setSelectedStatusType(status)
}}
className="h-14 shrink-0"
- defaultValue={edit?.value}
+ defaultValue={edit?.value || selectedStatusType}
/>
📝 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.
onValueChange={(status) => { | |
setValue('template', status) | |
setSelectedStatusType(status) | |
} } | |
className="h-14 shrink-0" | |
defaultValue={edit?.value} | |
onValueChange={(status) => { | |
setValue('template', status) | |
setSelectedStatusType(status) | |
} } | |
className="h-14 shrink-0" | |
defaultValue={edit?.value || selectedStatusType} |
const iconList: IIcon[] = useMemo(() => [ | ||
...taskStatusIconList, | ||
...taskSizesIconList, | ||
...taskPrioritiesIconList | ||
]; | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
],[]) ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add dependencies to useMemo
The empty dependency array means the iconList will never be recomputed even if the source lists change. Add the source lists as dependencies.
const iconList: IIcon[] = useMemo(() => [
...taskStatusIconList,
...taskSizesIconList,
...taskPrioritiesIconList
- // eslint-disable-next-line react-hooks/exhaustive-deps
- ],[]) ;
+ ],[taskStatusIconList, taskSizesIconList, taskPrioritiesIconList]) ;
📝 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.
const iconList: IIcon[] = useMemo(() => [ | |
...taskStatusIconList, | |
...taskSizesIconList, | |
...taskPrioritiesIconList | |
]; | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
],[]) ; | |
const iconList: IIcon[] = useMemo(() => [ | |
...taskStatusIconList, | |
...taskSizesIconList, | |
...taskPrioritiesIconList | |
],[taskStatusIconList, taskSizesIconList, taskPrioritiesIconList]) ; |
const getRandomColor = useCallback(() => { | ||
const letters = '0123456789ABCDEF'; | ||
let color = '#'; | ||
for (let i = 0; i < 6; i++) { | ||
color += letters[Math.floor(Math.random() * 16)]; | ||
} | ||
return color; | ||
}, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Simplify random color generation
The current implementation can be simplified using array methods.
const getRandomColor = useCallback(() => {
- const letters = '0123456789ABCDEF';
- let color = '#';
- for (let i = 0; i < 6; i++) {
- color += letters[Math.floor(Math.random() * 16)];
- }
- return color;
+ return '#' + Array.from({ length: 6 }, () =>
+ Math.floor(Math.random() * 16).toString(16)
+ ).join('');
}, []);
📝 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.
const getRandomColor = useCallback(() => { | |
const letters = '0123456789ABCDEF'; | |
let color = '#'; | |
for (let i = 0; i < 6; i++) { | |
color += letters[Math.floor(Math.random() * 16)]; | |
} | |
return color; | |
}, []); | |
const getRandomColor = useCallback(() => { | |
return '#' + Array.from({ length: 6 }, () => | |
Math.floor(Math.random() * 16).toString(16) | |
).join(''); | |
}, []); |
const getIcon = useCallback((iconName: string) => { | ||
const name = iconName == "ready-for-review" ? "ready" : iconName; | ||
const icon = iconList.find(icon => icon.title === name) | ||
|
||
if(icon){ | ||
setValue("icon", icon.path) | ||
} | ||
|
||
return icon | ||
|
||
},[iconList, setValue]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance getIcon function robustness
The function needs better error handling and could use a more maintainable approach for icon name mapping.
+const ICON_NAME_MAP: Record<string, string> = {
+ 'ready-for-review': 'ready'
+};
const getIcon = useCallback((iconName: string) => {
- const name = iconName == "ready-for-review" ? "ready" : iconName;
+ const name = ICON_NAME_MAP[iconName] || iconName;
const icon = iconList.find(icon => icon.title === name)
+ if (!icon) {
+ console.warn(`Icon not found for status: ${iconName}`);
+ }
if(icon){
setValue("icon", icon.path)
}
return icon
},[iconList, setValue])
📝 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.
const getIcon = useCallback((iconName: string) => { | |
const name = iconName == "ready-for-review" ? "ready" : iconName; | |
const icon = iconList.find(icon => icon.title === name) | |
if(icon){ | |
setValue("icon", icon.path) | |
} | |
return icon | |
},[iconList, setValue]) | |
const ICON_NAME_MAP: Record<string, string> = { | |
'ready-for-review': 'ready' | |
}; | |
const getIcon = useCallback((iconName: string) => { | |
const name = ICON_NAME_MAP[iconName] || iconName; | |
const icon = iconList.find(icon => icon.title === name) | |
if (!icon) { | |
console.warn(`Icon not found for status: ${iconName}`); | |
} | |
if(icon){ | |
setValue("icon", icon.path) | |
} | |
return icon | |
},[iconList, setValue]) |
@CREDO23 :
|
@evereq , @KostyaEver suggested stopping working on this ! I will continue after having a call with him and @GloireMutaliko21 ! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just reviewed it,
The RabbitAI refactor suggestions is very pertinent (especially the ones I've stuck with 👍🏽) , When you will continue to work on this Task, try to integrate/fix them.
@CREDO23
Description
FIX #3165
Type of Change
Checklist
Previous screenshots
Loom
Current screenshots
Loom
Summary by CodeRabbit
Release Notes
New Features
svgFetch
function for asynchronous SVG retrieval.TaskStatus
component with dynamic text color based on background.Improvements
IconItem
component to utilize dynamic translations.StatusesListCard
for flexible SVG icon handling.TaskStatusesForm
with dynamic color assignment and icon selection.Localization