fix: replace index-only keys with stable composite keys in mapped lists#3777
fix: replace index-only keys with stable composite keys in mapped lists#3777karyanayandi wants to merge 1 commit intoDokploy:canaryfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR aims to eliminate React list items keyed solely by array index, improving UI stability when mapped lists update (e.g., filtering, insertion/removal).
Changes:
- Updated several mapped lists to use composite or non-index keys (logs, backup codes, badges, feature cards).
- Switched feature card keys to
feature.title(and removed the unusedindexparam). - Adjusted various log list keys to include
rawTimestamp.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/dokploy/components/shared/drawer-logs.tsx | Updates TerminalLine keys for deployment log rendering. |
| apps/dokploy/components/dashboard/settings/servers/welcome-stripe/welcome-suscription.tsx | Uses feature.title instead of index for feature card keys. |
| apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx | Updates backup code list keys to composite. |
| apps/dokploy/components/dashboard/settings/profile/configure-2fa.tsx | Updates backup code list keys to composite. |
| apps/dokploy/components/dashboard/docker/logs/docker-logs-id.tsx | Updates TerminalLine keys in filtered docker logs list. |
| apps/dokploy/components/dashboard/application/general/generic/save-gitlab-provider.tsx | Updates badge keys for watchPaths list. |
| apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx | Updates badge keys for watchPaths list. |
| apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx | Updates TerminalLine keys for filtered logs and optional error logs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| {backupCodes.map((code, index) => ( | ||
| <code | ||
| key={index} | ||
| key={`${code}-${index}`} |
There was a problem hiding this comment.
Backup codes are expected to be unique; using ${code}-${index} makes keys order-dependent. Prefer key={code} for a stable key.
| key={`${code}-${index}`} | |
| key={code} |
| filteredLogs.map((log: LogLine, index: number) => ( | ||
| <TerminalLine key={index} log={log} noTimestamp /> | ||
| <TerminalLine | ||
| key={`${log.rawTimestamp ?? ""}-${index}`} |
There was a problem hiding this comment.
The list key still depends on index, so when filteredLogs changes due to filtering/searching the same log line can receive a different key and be remounted. Prefer a key derived solely from log identity (e.g., rawTimestamp + message, or introduce a stable id/lineNumber in LogLine) and avoid index unless duplicates are expected and handled.
| key={`${log.rawTimestamp ?? ""}-${index}`} | |
| key={JSON.stringify(log)} |
| filteredLogs.map((filteredLog: LogLine, index: number) => ( | ||
| <TerminalLine | ||
| key={index} | ||
| key={`${filteredLog.rawTimestamp ?? ""}-${index}`} |
There was a problem hiding this comment.
key still incorporates the array index, so changing filteredLogs (search/type filters, etc.) will reshuffle indexes and cause React to remount existing log rows. Use a key based on the log content/identity (e.g., rawTimestamp + message, or a stable id from parsing) to keep rows stable across filtering.
| key={`${filteredLog.rawTimestamp ?? ""}-${index}`} | |
| key={`${filteredLog.rawTimestamp ?? ""}-${filteredLog.message ?? ""}`} |
| <TerminalLine | ||
| key={`${log.rawTimestamp ?? ""}-${index}`} | ||
| log={log} | ||
| noTimestamp | ||
| /> | ||
| )) | ||
| ) : ( | ||
| <> | ||
| {optionalErrors.length > 0 ? ( | ||
| optionalErrors.map((log: LogLine, index: number) => ( | ||
| <TerminalLine key={`extra-${index}`} log={log} noTimestamp /> | ||
| <TerminalLine | ||
| key={`extra-${log.rawTimestamp ?? ""}-${index}`} | ||
| log={log} | ||
| noTimestamp | ||
| /> |
There was a problem hiding this comment.
Both mapped log lists use keys that include index, which will change when logs are filtered/toggled and can cause unnecessary remounting. Prefer keys based on log identity only (e.g., rawTimestamp + message or a stable parsed id/lineNumber) to keep rows stable.
| <code | ||
| key={index} | ||
| key={`${code}-${index}`} | ||
| className="bg-muted p-2 rounded text-sm font-mono" |
There was a problem hiding this comment.
Backup codes should already be unique values; including index makes the key unstable if the list order changes. Consider using key={code} to keep keys stable and simpler.
What is this PR about?
replace index-only keys with stable composite keys in mapped lists
Checklist
Before submitting this PR, please make sure that:
canarybranch.Issues related (if applicable)
Screenshots (if applicable)
Greptile Summary
Replaced index-only React keys with composite keys that combine meaningful data with array indices. Changes improve key stability across 8 files handling log displays, path badges, backup codes, and feature lists.
${log.rawTimestamp ?? ""}-${index}instead of justindex, providing better stability when logs are filtered or reordered${path}-${index}, making keys more descriptive${code}-${index}for better uniqueness guaranteesindextofeature.titleas the natural unique identifierAll changes follow React best practices for list keys by combining stable identifiers with indices as fallback uniqueness guarantees.
Confidence Score: 5/5
Last reviewed commit: 69d3286
(4/5) You can add custom instructions or style guidelines for the agent here!