Skip to content

Comments

fix: replace index-only keys with stable composite keys in mapped lists#3777

Open
karyanayandi wants to merge 1 commit intoDokploy:canaryfrom
karyanayandi:fix/stable-composite-keys-in-mapped-lists
Open

fix: replace index-only keys with stable composite keys in mapped lists#3777
karyanayandi wants to merge 1 commit intoDokploy:canaryfrom
karyanayandi:fix/stable-composite-keys-in-mapped-lists

Conversation

@karyanayandi
Copy link

@karyanayandi karyanayandi commented Feb 22, 2026

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:

  • You created a dedicated branch based on the canary branch.
  • You have read the suggestions in the CONTRIBUTING.md file https://github.com/Dokploy/dokploy/blob/canary/CONTRIBUTING.md#pull-request
  • You have tested this PR in your local instance. If you have not tested it yet, please do so before submitting. This helps avoid wasting maintainers' time reviewing code that has not been verified by you.

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 components now use ${log.rawTimestamp ?? ""}-${index} instead of just index, providing better stability when logs are filtered or reordered
  • Path badges in GitHub/GitLab providers use ${path}-${index}, making keys more descriptive
  • Backup codes use ${code}-${index} for better uniqueness guarantees
  • Features list switched from index to feature.title as the natural unique identifier

All changes follow React best practices for list keys by combining stable identifiers with indices as fallback uniqueness guarantees.

Confidence Score: 5/5

  • Safe to merge - improves React key stability without changing functionality
  • All changes are straightforward improvements to React keys that maintain uniqueness while adding semantic meaning. No logic changes, no new dependencies, and follows established patterns in the codebase.
  • No files require special attention

Last reviewed commit: 69d3286

(4/5) You can add custom instructions or style guidelines for the agent here!

Copilot AI review requested due to automatic review settings February 22, 2026 13:42
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 unused index param).
  • 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}`}
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backup codes are expected to be unique; using ${code}-${index} makes keys order-dependent. Prefer key={code} for a stable key.

Suggested change
key={`${code}-${index}`}
key={code}

Copilot uses AI. Check for mistakes.
filteredLogs.map((log: LogLine, index: number) => (
<TerminalLine key={index} log={log} noTimestamp />
<TerminalLine
key={`${log.rawTimestamp ?? ""}-${index}`}
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
key={`${log.rawTimestamp ?? ""}-${index}`}
key={JSON.stringify(log)}

Copilot uses AI. Check for mistakes.
filteredLogs.map((filteredLog: LogLine, index: number) => (
<TerminalLine
key={index}
key={`${filteredLog.rawTimestamp ?? ""}-${index}`}
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
key={`${filteredLog.rawTimestamp ?? ""}-${index}`}
key={`${filteredLog.rawTimestamp ?? ""}-${filteredLog.message ?? ""}`}

Copilot uses AI. Check for mistakes.
Comment on lines +197 to +211
<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
/>
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines 403 to 405
<code
key={index}
key={`${code}-${index}`}
className="bg-muted p-2 rounded text-sm font-mono"
Copy link

Copilot AI Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant