Skip to content

fix: API key key display truncation#1890

Open
elibosley wants to merge 1 commit intomainfrom
codex/fix-api-key-display-1889
Open

fix: API key key display truncation#1890
elibosley wants to merge 1 commit intomainfrom
codex/fix-api-key-display-1889

Conversation

@elibosley
Copy link
Member

@elibosley elibosley commented Mar 5, 2026

Summary

  • replace the fixed-width API key input with a wrapping monospace code block in the management UI
  • apply the same full-key wrapping behavior in the standalone authorization success view
  • keep the existing reveal and copy affordances while removing the need for horizontal scrolling

Validation

  • pnpm --dir web type-check
  • pnpm --dir web exec eslint src/components/ApiKey/ApiKeyManager.vue src/components/ApiKeyAuthorize.standalone.vue

Fixes #1889

Summary by CodeRabbit

  • Improvements
    • API key copy-to-clipboard button now displays interactive tooltip feedback with copy status confirmation.
    • Enhanced API key visibility toggle with improved button positioning and styling for better usability.
    • Redesigned API key display layout using code-block formatting for enhanced readability and visual presentation across key management interfaces.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

Walkthrough

API key display components are refactored to address truncation issues by replacing Input-based displays with native code blocks that properly handle full-length keys. Copy-to-clipboard functionality and visibility toggles are enhanced with improved UX patterns including tooltips and adjusted button positioning.

Changes

Cohort / File(s) Summary
API Key Display Refactoring
web/src/components/ApiKey/ApiKeyManager.vue, web/src/components/ApiKeyAuthorize.standalone.vue
Replaced Input components with dedicated code block layouts to properly display full-length API keys without truncation. Added copy-to-clipboard buttons with tooltip feedback ("Copied!" state), visibility toggle buttons with adjusted positioning (top-2 right-2), and improved flex layouts (items-start alignment) to ensure proper text handling and wrapping.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A key's no good when half is hidden away,
So we built a better display, hip-hooray!
With code blocks pristine and buttons that glow,
Copy, toggle, and see the full show! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: replacing truncated API key display with a wrapping code block solution.
Linked Issues check ✅ Passed The changes directly address issue #1889 by replacing the fixed-width input with a wrapping monospace code block that displays the full API key without truncation.
Out of Scope Changes check ✅ Passed All changes are focused on the API key display UI in two components, directly addressing the truncation issue without introducing unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-api-key-display-1889

Comment @coderabbitai help to get the list of available commands and usage tips.

@elibosley elibosley changed the title Fix API key key display truncation fix: API key key display truncation Mar 5, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/components/ApiKeyAuthorize.standalone.vue (1)

162-172: ⚠️ Potential issue | 🟠 Major

Add accessible names to icon-only key action controls.

Line 162 and Line 170 render icon-only controls without an accessible name, which makes these actions ambiguous for screen readers.

♿ Suggested fix
                 <button
                   type="button"
+                  :aria-label="showKey ? 'Hide API key' : 'Show API key'"
+                  :title="showKey ? 'Hide API key' : 'Show API key'"
                   class="text-muted-foreground hover:text-foreground absolute top-2 right-2 flex items-center px-1"
                   `@click`="toggleShowKey"
                 >
                   <component :is="showKey ? EyeSlashIcon : EyeIcon" class="h-4 w-4" />
                 </button>
               </div>
-              <Button variant="outline" size="icon" `@click`="copyApiKey">
+              <Button
+                variant="outline"
+                size="icon"
+                aria-label="Copy API key to clipboard"
+                title="Copy API key to clipboard"
+                `@click`="copyApiKey"
+              >
                 <ClipboardDocumentIcon class="h-4 w-4" />
               </Button>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/ApiKeyAuthorize.standalone.vue` around lines 162 - 172,
The icon-only controls for toggling visibility and copying the API key lack
accessible names; update the toggle button (the element using
`@click`="toggleShowKey" and <component :is="showKey ? EyeSlashIcon : EyeIcon">)
and the copy Button (the Button invoking `@click`="copyApiKey" with
<ClipboardDocumentIcon>) to include descriptive accessible attributes (e.g.,
aria-label or aria-labelledby, and optional title) that reflect their actions
like "Show API key"/"Hide API key" for the toggle (use showKey to pick the
correct label) and "Copy API key" for the clipboard button so screen readers can
identify the controls.
🧹 Nitpick comments (1)
web/src/components/ApiKey/ApiKeyManager.vue (1)

280-280: Track copy feedback per key row instead of globally.

Line 280 uses shared copied, so a tooltip in a different row can briefly show “Copied!” after another key was copied. Consider tracking copiedKeyId for row-specific feedback.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/ApiKey/ApiKeyManager.vue` at line 280, The component
currently uses a single shared reactive flag copied which causes any row's
tooltip to show “Copied!” when any key is copied; change to a row-scoped
identifier copiedKeyId (or similar) instead: replace the copied boolean with
copiedKeyId in the component state (null when none), update the copy handler
(e.g., the method that copies a key) to set copiedKeyId = key.id and start/clear
the timeout to reset it to null, and update the template expression that
currently reads "copied ? 'Copied!' : 'Copy to clipboard...'" to use
"copiedKeyId === key.id ? 'Copied!' : 'Copy to clipboard...'". Ensure all
references to copied are updated to the new variable (including any imports,
watchers, or timeouts).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/components/ApiKey/ApiKeyManager.vue`:
- Around line 270-277: The icon-only Button elements in ApiKeyManager.vue (the
copy button that calls copyKeyValue(key.key) and the visibility button that
toggles key visibility) lack accessible names; add clear accessible labels by
adding aria-label attributes (or visually hidden text) to those Button
components (e.g., aria-label="Copy API key" for the ClipboardDocumentIcon button
and aria-label="Show API key" / "Hide API key" for the visibility toggle) and
ensure the toggle updates its label based on state so screen readers get the
correct action.
- Around line 267-283: The TooltipTrigger wrapping the Button should include the
as-child prop to pass semantics to the wrapped interactive element; update the
TooltipTrigger surrounding the Button (the one that calls copyKeyValue(key.key)
and references copied) to use as-child so the Button remains the real focusable
element and keyboard/focus behavior is preserved.

---

Outside diff comments:
In `@web/src/components/ApiKeyAuthorize.standalone.vue`:
- Around line 162-172: The icon-only controls for toggling visibility and
copying the API key lack accessible names; update the toggle button (the element
using `@click`="toggleShowKey" and <component :is="showKey ? EyeSlashIcon :
EyeIcon">) and the copy Button (the Button invoking `@click`="copyApiKey" with
<ClipboardDocumentIcon>) to include descriptive accessible attributes (e.g.,
aria-label or aria-labelledby, and optional title) that reflect their actions
like "Show API key"/"Hide API key" for the toggle (use showKey to pick the
correct label) and "Copy API key" for the clipboard button so screen readers can
identify the controls.

---

Nitpick comments:
In `@web/src/components/ApiKey/ApiKeyManager.vue`:
- Line 280: The component currently uses a single shared reactive flag copied
which causes any row's tooltip to show “Copied!” when any key is copied; change
to a row-scoped identifier copiedKeyId (or similar) instead: replace the copied
boolean with copiedKeyId in the component state (null when none), update the
copy handler (e.g., the method that copies a key) to set copiedKeyId = key.id
and start/clear the timeout to reset it to null, and update the template
expression that currently reads "copied ? 'Copied!' : 'Copy to clipboard...'" to
use "copiedKeyId === key.id ? 'Copied!' : 'Copy to clipboard...'". Ensure all
references to copied are updated to the new variable (including any imports,
watchers, or timeouts).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8d34c8c3-e848-471f-99c1-43636a11fef0

📥 Commits

Reviewing files that changed from the base of the PR and between 7956987 and 2dedc13.

📒 Files selected for processing (2)
  • web/src/components/ApiKey/ApiKeyManager.vue
  • web/src/components/ApiKeyAuthorize.standalone.vue

Comment on lines +267 to +283
<TooltipProvider>
<Tooltip :delay-duration="0">
<TooltipTrigger>
<Button
variant="ghost"
size="icon"
class="h-8 w-8"
@click="copyKeyValue(key.key)"
>
<ClipboardDocumentIcon class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{{ copied ? 'Copied!' : 'Copy to clipboard...' }}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, verify the file exists and check the actual code at the specified lines
fd "ApiKeyManager.vue" web

Repository: unraid/api

Length of output: 97


🏁 Script executed:

# Read the file to confirm the code snippet
cat -n web/src/components/ApiKey/ApiKeyManager.vue | sed -n '260,290p'

Repository: unraid/api

Length of output: 1789


🏁 Script executed:

# Search for TooltipTrigger imports and usage in the file
rg -n "TooltipTrigger|import.*Tooltip" web/src/components/ApiKey/ApiKeyManager.vue

Repository: unraid/api

Length of output: 257


🏁 Script executed:

# Search for TooltipTrigger component definition or package info
rg -n "TooltipTrigger" web/src/components --type=vue -A2 | head -50

Repository: unraid/api

Length of output: 81


🏁 Script executed:

# Check if as-child is used elsewhere with TooltipTrigger in the codebase
rg "TooltipTrigger.*as-child" web --type=vue

Repository: unraid/api

Length of output: 81


🏁 Script executed:

# Read around line 332 to see the context where as-child IS used
cat -n web/src/components/ApiKey/ApiKeyManager.vue | sed -n '325,345p'

Repository: unraid/api

Length of output: 1204


🏁 Script executed:

# Search for TooltipTrigger patterns without type flag
rg -n "TooltipTrigger" web/src/components/ApiKey/ApiKeyManager.vue -C2

Repository: unraid/api

Length of output: 1278


🏁 Script executed:

# Check for TooltipTrigger usage across the entire codebase
rg "TooltipTrigger(?!.*as-child)" web/src --multiline-dotall 2>/dev/null | head -40

Repository: unraid/api

Length of output: 36


🏁 Script executed:

# Find where TooltipTrigger component is defined or imported from
rg "from.*TooltipTrigger|import.*TooltipTrigger" web/src

Repository: unraid/api

Length of output: 190


🏁 Script executed:

# Find `@unraid/ui` location - is it in the repo or external?
fd -t f "@unraid/ui" . 2>/dev/null || find . -name "*unraid*" -type d 2>/dev/null | grep -v node_modules | head -20

Repository: unraid/api

Length of output: 36


🏁 Script executed:

# Search for all TooltipTrigger usages in the codebase
rg "TooltipTrigger" web/src --no-heading | sort | uniq -c

Repository: unraid/api

Length of output: 1567


🏁 Script executed:

# Get all TooltipTrigger context across the codebase
rg -B1 -A4 "TooltipTrigger" web/src 2>/dev/null

Repository: unraid/api

Length of output: 8458


🏁 Script executed:

# Check package.json for `@unraid/ui` info
fd "package.json" web -exec cat {} \; | grep -A5 -B5 "@unraid/ui" | head -20

Repository: unraid/api

Length of output: 200


Add as-child to TooltipTrigger for proper semantics.

Line 269 wraps a <Button> inside TooltipTrigger without the as-child prop. The rest of the codebase consistently uses as-child when wrapping interactive elements—see line 332 in the same file for the correct pattern. Without as-child, nested button elements can break focus behavior and keyboard accessibility.

🛠️ Suggested fix
-                        <TooltipTrigger>
+                        <TooltipTrigger as-child>
                           <Button
                             variant="ghost"
                             size="icon"
                             class="h-8 w-8"
                             `@click`="copyKeyValue(key.key)"
                           >
                             <ClipboardDocumentIcon class="h-4 w-4" />
                           </Button>
-                        </TooltipTrigger>
+                        </TooltipTrigger>
📝 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.

Suggested change
<TooltipProvider>
<Tooltip :delay-duration="0">
<TooltipTrigger>
<Button
variant="ghost"
size="icon"
class="h-8 w-8"
@click="copyKeyValue(key.key)"
>
<ClipboardDocumentIcon class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{{ copied ? 'Copied!' : 'Copy to clipboard...' }}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip :delay-duration="0">
<TooltipTrigger as-child>
<Button
variant="ghost"
size="icon"
class="h-8 w-8"
`@click`="copyKeyValue(key.key)"
>
<ClipboardDocumentIcon class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{{ copied ? 'Copied!' : 'Copy to clipboard...' }}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/ApiKey/ApiKeyManager.vue` around lines 267 - 283, The
TooltipTrigger wrapping the Button should include the as-child prop to pass
semantics to the wrapped interactive element; update the TooltipTrigger
surrounding the Button (the one that calls copyKeyValue(key.key) and references
copied) to use as-child so the Button remains the real focusable element and
keyboard/focus behavior is preserved.

Comment on lines +270 to +277
<Button
variant="ghost"
size="icon"
class="h-8 w-8"
@click="copyKeyValue(key.key)"
>
<ClipboardDocumentIcon class="h-4 w-4" />
</Button>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add accessible names to icon-only copy and visibility buttons.

Line 270 and Line 291 use icon-only buttons without accessible names, reducing usability for assistive technologies.

♿ Suggested fix
                           <Button
                             variant="ghost"
                             size="icon"
                             class="h-8 w-8"
+                            aria-label="Copy API key to clipboard"
+                            title="Copy API key to clipboard"
                             `@click`="copyKeyValue(key.key)"
                           >
                             <ClipboardDocumentIcon class="h-4 w-4" />
                           </Button>
@@
                     <Button
                       variant="ghost"
                       size="icon"
                       class="absolute top-2 right-2 h-auto w-auto px-1 text-gray-500 hover:text-gray-700"
+                      :aria-label="showKey[key.id] ? 'Hide API key' : 'Show API key'"
+                      :title="showKey[key.id] ? 'Hide API key' : 'Show API key'"
                       `@click`="toggleShowKey(key.id)"
                     >

Also applies to: 291-298

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/ApiKey/ApiKeyManager.vue` around lines 270 - 277, The
icon-only Button elements in ApiKeyManager.vue (the copy button that calls
copyKeyValue(key.key) and the visibility button that toggles key visibility)
lack accessible names; add clear accessible labels by adding aria-label
attributes (or visually hidden text) to those Button components (e.g.,
aria-label="Copy API key" for the ClipboardDocumentIcon button and
aria-label="Show API key" / "Hide API key" for the visibility toggle) and ensure
the toggle updates its label based on state so screen readers get the correct
action.

@codecov
Copy link

codecov bot commented Mar 5, 2026

Codecov Report

❌ Patch coverage is 0% with 34 lines in your changes missing coverage. Please review.
✅ Project coverage is 48.65%. Comparing base (38a6f0c) to head (2dedc13).
⚠️ Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
web/src/components/ApiKey/ApiKeyManager.vue 0.00% 26 Missing ⚠️
web/src/components/ApiKeyAuthorize.standalone.vue 0.00% 8 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1890      +/-   ##
==========================================
+ Coverage   46.40%   48.65%   +2.24%     
==========================================
  Files         954     1013      +59     
  Lines       59791    67635    +7844     
  Branches     5538     6944    +1406     
==========================================
+ Hits        27749    32908    +5159     
- Misses      31923    34606    +2683     
- Partials      119      121       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

Management Access / API Key - Key Display not long enough

1 participant