Skip to content

feat(ui): 데모 화면 버튼 및 링크 접근성(aria-label) 개선 - #403

Closed
seonghobae wants to merge 1 commit into
mainfrom
fix-accessibility-demo-ui-10616308121239155005
Closed

feat(ui): 데모 화면 버튼 및 링크 접근성(aria-label) 개선#403
seonghobae wants to merge 1 commit into
mainfrom
fix-accessibility-demo-ui-10616308121239155005

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Superseded by current-base PR #264.

#403 adds only document-specific aria-label text in demo.js and a CHANGELOG entry, with no focused executable accessibility regression. PR #264 already owns the same demo.js accessibility 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.

데모 화면(`demo.js`)에서 동적으로 생성되는 리스트 내 액션 버튼('Details', 'Status JSON')과 링크('Open viewer')에 문서 이름을 포함하는 `aria-label`을 추가했습니다.
스크린 리더 등 보조 기기를 사용하는 사용자가 맥락을 파악하기 쉽도록 웹 접근성을 개선하였습니다.
@google-labs-jules

Copy link
Copy Markdown

👋 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 @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

데모 UI의 링크와 버튼 생성 함수가 선택적 aria-label을 지원합니다. 기록 목록의 Details, Status JSON, Open viewer 컨트롤은 파일명을 포함한 라벨을 사용합니다. 변경 내용은 CHANGELOG.md에 기록되었습니다.

Changes

데모 UI 접근성 라벨

Layer / File(s) Summary
aria-label 지원 추가
src/main/resources/static/assets/viewer/demo.js
createLinkcreateActionButton이 선택적 ariaLabel 인자를 받아 aria-label 속성을 설정합니다.
기록 목록 컨트롤 라벨 적용
src/main/resources/static/assets/viewer/demo.js, CHANGELOG.md
Details, Status JSON, Open viewer 컨트롤이 파일명을 포함한 접근성 라벨을 사용합니다. 변경 내역에도 이 내용을 추가했습니다.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

🚥 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 제목은 데모 UI 버튼과 링크의 접근성 개선이라는 주요 변경 사항을 정확하고 간결하게 설명합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-accessibility-demo-ui-10616308121239155005

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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between 55d7ae8 and 8d7e842.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • src/main/resources/static/assets/viewer/demo.js

btn.disabled = false;
});
}));
}, `Details for ${job.fileName || "Document"}`));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 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/viewer

Repository: 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 || true

Repository: 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))
PY

Repository: 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))
PY

Repository: 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))
PY

Repository: ContextualWisdomLab/clearfolio

Length of output: 318


로딩 상태를 aria-label 또는 별도 상태로 제공하세요.

aria-labelDetails 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.

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