feat(ui): 데모 화면 버튼 및 링크 접근성(aria-label) 개선 - #403
Conversation
데모 화면(`demo.js`)에서 동적으로 생성되는 리스트 내 액션 버튼('Details', 'Status JSON')과 링크('Open viewer')에 문서 이름을 포함하는 `aria-label`을 추가했습니다.
스크린 리더 등 보조 기기를 사용하는 사용자가 맥락을 파악하기 쉽도록 웹 접근성을 개선하였습니다.
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
📝 WalkthroughWalkthrough데모 UI의 링크와 버튼 생성 함수가 선택적 Changes데모 UI 접근성 라벨
Estimated code review effort: 1 (Trivial) | ~5 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/resources/static/assets/viewer/demo.js`:
- Line 162: Update the button creation in openJobDetail() so its accessibility
state reflects loading when updateJob() changes the button text to “Loading...”.
Ensure every newly recreated button receives the loading indication, either
through a matching aria-label or a stable aria-live status, while preserving the
normal “Details for …” label after loading completes.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: ce553b6d-caac-4e1e-88a3-32e8d6ca4b5e
📒 Files selected for processing (2)
CHANGELOG.mdsrc/main/resources/static/assets/viewer/demo.js
| btn.disabled = false; | ||
| }); | ||
| })); | ||
| }, `Details for ${job.fileName || "Document"}`)); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
file='src/main/resources/static/assets/viewer/demo.js'
printf '%s\n' '--- file outline ---'
if command -v ast-grep >/dev/null 2>&1; then
ast-grep outline "$file" || true
fi
printf '%s\n' '--- relevant symbols and calls ---'
rg -n -C 8 'createActionButton|createLink|openJobDetail|Details for|Loading\.\.\.|aria-label|renderHistory' "$file"
printf '%s\n' '--- nearby source ---'
sed -n '70,180p' "$file"
printf '%s\n' '--- related aria-label usage ---'
rg -n -C 5 'aria-label|createActionButton|openJobDetail' src/main/resources/static/assets/viewerRepository: ContextualWisdomLab/clearfolio
Length of output: 19971
🏁 Script executed:
#!/bin/bash
set -eu
file='src/main/resources/static/assets/viewer/demo.js'
printf '%s\n' '--- openJobDetail implementation ---'
sed -n '240,305p' "$file"
printf '%s\n' '--- updateJob callers in the relevant range ---'
rg -n -C 6 'updateJob\(' "$file"
printf '%s\n' '--- tests and accessibility references ---'
rg -n -i -C 3 'aria-label|accessible name|screen reader|Loading details|Details for|demo\.js' \
--glob '!src/main/resources/static/assets/viewer/demo.js' \
--glob '!node_modules' \
--glob '!build' \
--glob '!dist' . || true
printf '%s\n' '--- available browser/runtime tools ---'
command -v chromium || true
command -v chromium-browser || true
command -v google-chrome || true
command -v firefox || true
command -v playwright || true
node --version 2>/dev/null || trueRepository: ContextualWisdomLab/clearfolio
Length of output: 34883
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from dataclasses import dataclass, field
`@dataclass`
class Button:
text: str
aria_label: str | None
disabled: bool = False
attached: bool = True
def accessible_name(button: Button) -> str:
# Relevant Accessible Name and Description Computation rule for this
# native button: aria-label takes precedence over descendant content.
return button.aria_label if button.aria_label else button.text
def render_details(file_name: str) -> Button:
return Button(
text="Details",
aria_label=f"Details for {file_name or 'Document'}",
)
def simulate_handler(file_name: str):
old = render_details(file_name)
initial_text = old.text
old.disabled = True
old.text = "Loading..."
# openJobDetail() updates the job and renderHistory() replaces the row.
current = render_details(file_name)
old.attached = False
# This models the proposed finally callback, which still owns `old`.
old.text = initial_text
old.disabled = False
old.aria_label = f"Details for {file_name or 'Document'}"
return old, current
button = render_details("report.pdf")
before = accessible_name(button)
button.text = "Loading..."
during = accessible_name(button)
assert before == "Details for report.pdf"
assert during == "Details for report.pdf"
assert button.text == "Loading..."
print("fixed aria-label masks the visible Loading... text:", during)
old, current = simulate_handler("report.pdf")
assert not old.attached
assert current.attached
assert accessible_name(current) == "Details for report.pdf"
print("renderHistory replacement leaves the current button with the non-loading label:",
accessible_name(current))
PYRepository: ContextualWisdomLab/clearfolio
Length of output: 345
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from dataclasses import dataclass
`@dataclass`
class Button:
text: str
aria_label: str | None
disabled: bool = False
attached: bool = True
def accessible_name(button: Button) -> str:
# Relevant Accessible Name and Description Computation rule for this
# native button: aria-label takes precedence over descendant content.
return button.aria_label if button.aria_label else button.text
def render_details(file_name: str) -> Button:
return Button(
text="Details",
aria_label=f"Details for {file_name or 'Document'}",
)
def simulate_handler(file_name: str):
old = render_details(file_name)
initial_text = old.text
old.disabled = True
old.text = "Loading..."
# openJobDetail() updates the job and renderHistory() replaces the row.
current = render_details(file_name)
old.attached = False
# This models the proposed finally callback, which still owns `old`.
old.text = initial_text
old.disabled = False
old.aria_label = f"Details for {file_name or 'Document'}"
return old, current
button = render_details("report.pdf")
before = accessible_name(button)
button.text = "Loading..."
during = accessible_name(button)
assert before == "Details for report.pdf"
assert during == "Details for report.pdf"
assert button.text == "Loading..."
print("fixed aria-label masks the visible Loading... text:", during)
old, current = simulate_handler("report.pdf")
assert not old.attached
assert current.attached
assert accessible_name(current) == "Details for report.pdf"
print("renderHistory replacement leaves the current button with the non-loading label:",
accessible_name(current))
PYRepository: ContextualWisdomLab/clearfolio
Length of output: 345
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from dataclasses import dataclass
from typing import Optional
`@dataclass`
class Button:
text: str
aria_label: Optional[str]
disabled: bool = False
attached: bool = True
def accessible_name(button):
# For this native button, an explicit aria-label takes precedence
# over descendant text in the accessible name computation.
return button.aria_label if button.aria_label else button.text
def render_details(file_name):
return Button(
text="Details",
aria_label="Details for " + (file_name or "Document"),
)
def simulate_handler(file_name):
old = render_details(file_name)
initial_text = old.text
old.disabled = True
old.text = "Loading..."
# openJobDetail() calls updateJob(), which calls renderHistory()
# and replaces the row containing the original button.
current = render_details(file_name)
old.attached = False
# Model the proposed finally callback, which still owns old.
old.text = initial_text
old.disabled = False
old.aria_label = "Details for " + (file_name or "Document")
return old, current
button = render_details("report.pdf")
assert accessible_name(button) == "Details for report.pdf"
button.text = "Loading..."
assert accessible_name(button) == "Details for report.pdf"
print("aria-label masks the visible loading text:",
accessible_name(button))
old, current = simulate_handler("report.pdf")
assert not old.attached
assert current.attached
assert accessible_name(current) == "Details for report.pdf"
print("the rerendered current button retains the non-loading label:",
accessible_name(current))
PYRepository: ContextualWisdomLab/clearfolio
Length of output: 318
로딩 상태를 aria-label 또는 별도 상태로 제공하세요.
aria-label이 Details for ...로 고정되어 버튼 텍스트가 Loading...으로 바뀌어도 접근성 이름은 변경되지 않습니다. 또한 openJobDetail()의 updateJob()가 버튼을 다시 생성하므로 기존 btn에 라벨을 복원하는 방식만으로는 부족합니다. 새 버튼에도 로딩 상태를 반영하거나 안정적인 aria-live 상태를 제공하세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/resources/static/assets/viewer/demo.js` at line 162, Update the
button creation in openJobDetail() so its accessibility state reflects loading
when updateJob() changes the button text to “Loading...”. Ensure every newly
recreated button receives the loading indication, either through a matching
aria-label or a stable aria-live status, while preserving the normal “Details
for …” label after loading completes.
Superseded by current-base PR #264.
#403 adds only document-specific
aria-labeltext indemo.jsand a CHANGELOG entry, with no focused executable accessibility regression. PR #264 already owns the samedemo.jsaccessibility lane on the current protected-main baseline and provides the stronger contract: document-specific accessible names for Details/Status JSON/Open viewer, markup-safe DOM text handling, nested/repeated busy-state depth, exact ARIA/disabled/child-node restoration, duplicate-activation suppression, dependency-free Node unit/integration execution, and exact-head CI/Security/SAST/fuzz evidence.Keeping both open would create competing writers for the same production path and could regress #264's tested nested-safe behavior. Closing this PR preserves #264 as the single implementation owner; no claim is made that #264 is merged until normal protection and independent review complete.