Skip to content

🎨 Palette: 숫자 μž…λ ₯ ν•„λ“œ 빈 λ¬Έμžμ—΄ 처리 둜직 κ°œμ„  - #334

Open
seonghobae wants to merge 1 commit into
mainfrom
palette-ux-empty-string-handling-1666906190712593174
Open

🎨 Palette: 숫자 μž…λ ₯ ν•„λ“œ 빈 λ¬Έμžμ—΄ 처리 둜직 κ°œμ„ #334
seonghobae wants to merge 1 commit into
mainfrom
palette-ux-empty-string-handling-1666906190712593174

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

πŸ’‘ What: 숫자 μž…λ ₯ ν•„λ“œ(target_bytes)에 빈 λ¬Έμžμ—΄μ΄ μž…λ ₯될 λ•Œ μ—λŸ¬ μƒνƒœ(aria-invalid λ“±)λ₯Ό λͺ…μ‹œμ μœΌλ‘œ ν•΄μ œν•˜λ„λ‘ 인라인 μœ νš¨μ„± 검사 λ‘œμ§μ„ κ°œμ„ ν–ˆμŠ΅λ‹ˆλ‹€.
🎯 Why: μ‚¬μš©μžκ°€ 값을 λͺ¨λ‘ μ§€μ›Œμ„œ 빈 λ¬Έμžμ—΄μ΄ 될 경우, μ‹œκ°μ μœΌλ‘œλŠ” λΉ„μ–΄μžˆμ§€λ§Œ λΈŒλΌμš°μ € λ‚΄λΆ€μ μœΌλ‘œλŠ” 잘λͺ»λœ μƒνƒœκ°€ μœ μ§€λ˜μ–΄ required μ œμ•½ 쑰건이 μ œλŒ€λ‘œ λ™μž‘ν•˜μ§€ μ•Šκ±°λ‚˜ 잘λͺ»λœ 였λ₯˜ λ©”μ‹œμ§€κ°€ λ‚¨λŠ” ν˜Όλž€μ„ λ°©μ§€ν•˜κΈ° μœ„ν•¨μž…λ‹ˆλ‹€.
πŸ“Έ Before/After: λ³€κ²½ μ „μ—λŠ” 값을 λͺ¨λ‘ μ§€μš°λ©΄ μ»€μŠ€ν…€ μ—λŸ¬ λ©”μ‹œμ§€κ°€ λ‚¨μ•˜μœΌλ‚˜, λ³€κ²½ ν›„μ—λŠ” μ •μƒμ μœΌλ‘œ μ—λŸ¬ μƒνƒœκ°€ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.
β™Ώ Accessibility: aria-invalid 속성을 빈 λ¬Έμžμ—΄ μƒνƒœμΌ λ•Œ μ˜¬λ°”λ₯΄κ²Œ ν•΄μ œν•˜μ—¬ 슀크린 리더 μ‚¬μš©μžκ°€ 잘λͺ»λœ 였λ₯˜ μƒνƒœλ₯Ό 전달받지 μ•Šλ„λ‘ κ°œμ„ ν–ˆμŠ΅λ‹ˆλ‹€.


PR created automatically by Jules for task 1666906190712593174 started by @seonghobae

Summary by CodeRabbit

  • 버그 μˆ˜μ •
    • 단일 및 배치 파일의 숫자 μž…λ ₯값을 μ‚­μ œν•˜λ©΄ 미리보기, μ‚¬μš©μž μ§€μ • μœ νš¨μ„± 였λ₯˜, 잘λͺ»λœ μž…λ ₯ ν‘œμ‹œκ°€ μ¦‰μ‹œ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.
    • μž…λ ₯값이 λΉ„μ–΄ μžˆμ„ λ•Œ κΈ°μ‘΄ 프리셋 선택 μƒνƒœλ„ ν•¨κ»˜ μž¬μ„€μ •λ©λ‹ˆλ‹€.

πŸ’‘ What: 숫자 μž…λ ₯ ν•„λ“œ(target_bytes, batch_target_bytes)에 빈 λ¬Έμžμ—΄μ΄ μž…λ ₯될 λ•Œ μ—λŸ¬ μƒνƒœ(aria-invalid λ“±)λ₯Ό λͺ…μ‹œμ μœΌλ‘œ ν•΄μ œν•˜λ„λ‘ 인라인 μœ νš¨μ„± 검사 λ‘œμ§μ„ κ°œμ„ ν–ˆμŠ΅λ‹ˆλ‹€.
🎯 Why: μ‚¬μš©μžκ°€ 값을 λͺ¨λ‘ μ§€μ›Œμ„œ 빈 λ¬Έμžμ—΄μ΄ 될 경우, μ‹œκ°μ μœΌλ‘œλŠ” λΉ„μ–΄μžˆμ§€λ§Œ λΈŒλΌμš°μ € λ‚΄λΆ€μ μœΌλ‘œλŠ” 잘λͺ»λœ μƒνƒœκ°€ μœ μ§€λ˜μ–΄ required μ œμ•½ 쑰건이 μ œλŒ€λ‘œ λ™μž‘ν•˜μ§€ μ•Šκ±°λ‚˜ 잘λͺ»λœ 였λ₯˜ λ©”μ‹œμ§€κ°€ λ‚¨λŠ” ν˜Όλž€μ„ λ°©μ§€ν•˜κΈ° μœ„ν•¨μž…λ‹ˆλ‹€.
πŸ“Έ Before/After: λ³€κ²½ μ „μ—λŠ” 값을 λͺ¨λ‘ μ§€μš°λ©΄ μ»€μŠ€ν…€ μ—λŸ¬ λ©”μ‹œμ§€κ°€ λ‚¨μ•˜μœΌλ‚˜, λ³€κ²½ ν›„μ—λŠ” μ •μƒμ μœΌλ‘œ μ—λŸ¬ μƒνƒœκ°€ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.
β™Ώ Accessibility: aria-invalid 속성을 빈 λ¬Έμžμ—΄ μƒνƒœμΌ λ•Œ μ˜¬λ°”λ₯΄κ²Œ ν•΄μ œν•˜μ—¬ 슀크린 리더 μ‚¬μš©μžκ°€ 잘λͺ»λœ 였λ₯˜ μƒνƒœλ₯Ό 전달받지 μ•Šλ„λ‘ κ°œμ„ ν–ˆμŠ΅λ‹ˆλ‹€.
@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 1, 2026

Copy link
Copy Markdown

Review Change Stack

πŸ“ Walkthrough

Walkthrough

숫자 μž…λ ₯값이 빈 λ¬Έμžμ—΄μ΄ 되면 단일 파일과 배치 파일 μž…λ ₯ μ²˜λ¦¬κΈ°κ°€ μœ νš¨μ„±, μ ‘κ·Όμ„±, 미리보기, 프리셋 μƒνƒœλ₯Ό μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€. κ΄€λ ¨ UX 지침도 λ¬Έμ„œμ— μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€.

Changes

빈 숫자 μž…λ ₯ μƒνƒœ μ΄ˆκΈ°ν™”

Layer / File(s) Summary
단일 및 배치 μž…λ ₯ μƒνƒœ μ΄ˆκΈ°ν™”
saas_web.py, .jules/palette.md
단일 파일과 배치 파일의 빈 target_bytes μž…λ ₯μ—μ„œ μ‚¬μš©μž μ§€μ • μœ νš¨μ„±, aria-invalid, 미리보기 ν…μŠ€νŠΈ, 프리셋 선택 μƒνƒœλ₯Ό μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€. μ΄ˆκΈ°ν™” ν›„ μ¦‰μ‹œ λ°˜ν™˜ν•©λ‹ˆλ‹€. 숫자 μž…λ ₯값이 λΉ„μ›Œμ§ˆ λ•Œ μœ νš¨μ„± μƒνƒœλ₯Ό μ΄ˆκΈ°ν™”ν•˜λŠ” 지침을 λ¬Έμ„œμ— μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • ContextualWisdomLab/codec-carver#58: saas_web.py의 target_bytes μž…λ ₯κ³Ό 미리보기 및 μœ νš¨μ„± μƒνƒœλ₯Ό ν•¨κ»˜ μˆ˜μ •ν•©λ‹ˆλ‹€.
  • ContextualWisdomLab/codec-carver#301: λ™μΌν•œ target_bytes 및 batch_target_bytes 빈 μž…λ ₯ μ΄ˆκΈ°ν™”λ₯Ό ν™•μž₯ν•©λ‹ˆλ‹€.
  • ContextualWisdomLab/codec-carver#305: 두 μž…λ ₯ μ²˜λ¦¬κΈ°μ—μ„œ 빈 μž…λ ₯의 μœ νš¨μ„±, 미리보기, 프리셋 μƒνƒœλ₯Ό μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€.
πŸš₯ 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 제λͺ©μ€ 숫자 μž…λ ₯ ν•„λ“œμ˜ 빈 λ¬Έμžμ—΄ 처리 둜직 κ°œμ„ μ΄λΌλŠ” μ£Όμš” λ³€κ²½ 사항을 μ •ν™•ν•˜κ²Œ μš”μ•½ν•©λ‹ˆλ‹€.
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 palette-ux-empty-string-handling-1666906190712593174

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: 2

πŸ€– 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 @.jules/palette.md:
- Around line 77-79: Update the guidance in the β€œμˆ«μž μž…λ ₯ ν•„λ“œμ˜ 빈 λ¬Έμžμ—΄ μƒνƒœ μ²˜λ¦¬β€ section
to distinguish native ValidityState checks from application-managed state:
remove the claim that a previous negative value leaves rangeUnderflow active or
interferes with required validation, and clarify that only setCustomValidity()
customError and aria-invalid persist until explicitly reset.

In `@saas_web.py`:
- Around line 244-252: Ensure the batch-form script initializes only after the
batch form elements exist by moving it after both forms or deferring all DOM
queries and event registration until DOMContentLoaded. Update the lookups for
batch_preset_buttons_container and batch_target_bytes so the input handlers
covering both affected ranges register without null errors. Extend
tests/test_saas_web.py with browser-level coverage verifying empty-input state
reset behavior.
πŸͺ„ Autofix (Beta)

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: 43a48734-b2b5-4dd4-a51c-8d7495ad3212

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 5a92586 and b9a472f.

πŸ“’ Files selected for processing (2)
  • .jules/palette.md
  • saas_web.py

Comment thread .jules/palette.md
Comment on lines +77 to +79
## 2024-05-24 - 숫자 μž…λ ₯ ν•„λ“œμ˜ 빈 λ¬Έμžμ—΄ μƒνƒœ 처리 (UX κ°œμ„ )
**ν•™μŠ΅:** HTML5 `<input type="number">`μ—μ„œ μ‚¬μš©μžκ°€ 값을 λͺ¨λ‘ μ§€μ›Œ 빈 λ¬Έμžμ—΄(`''`)이 λ˜μ—ˆμ„ λ•Œ, μ‹œκ°μ μœΌλ‘œλŠ” ν…μŠ€νŠΈκ°€ μ§€μ›Œμ§€λ”λΌλ„ λͺ…μ‹œμ μœΌλ‘œ μž¬μ„€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ λΈŒλΌμš°μ € 내뢀에 μ΄μ „μ˜ 잘λͺ»λœ μƒνƒœ(예: 음수)κ°€ μœ μ§€λ˜μ–΄ `required`와 같은 κΈ°λ³Έ μ œμ•½ 쑰건 처리λ₯Ό λ°©ν•΄ν•  수 μžˆλ‹€.
**μ‹€ν–‰:** 인라인 μœ νš¨μ„± 검사λ₯Ό κ΅¬ν˜„ν•  λ•Œ `if (this.value === '')` 블둝을 톡해 `this.setCustomValidity('')` 및 `this.removeAttribute('aria-invalid')`λ₯Ό λͺ…μ‹œμ μœΌλ‘œ ν˜ΈμΆœν•˜μ—¬ 였λ₯˜ μƒνƒœλ₯Ό 깨끗이 μ΄ˆκΈ°ν™”ν•΄μ•Ό μ „μ œ 였λ₯˜ 쑰건을 λ°©μ§€ν•  수 μžˆλ‹€.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ“ Maintainability & Code Quality | 🟑 Minor | ⚑ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- target file ---'
sed -n '65,90p' .jules/palette.md
printf '%s\n' '--- related validity terms ---'
rg -n -C 3 'setCustomValidity|aria-invalid|rangeUnderflow|required|input type="number"|빈 λ¬Έμžμ—΄' .jules . --glob '!node_modules' --glob '!dist' --glob '!build' | head -200

Repository: ContextualWisdomLab/codec-carver

Length of output: 20230


🌐 Web query:

HTML constraint validation ValidityState rangeUnderflow current value setCustomValidity persistence aria-invalid specification

πŸ’‘ Result:

HTML Constraint Validation and aria-invalid work as follows: ValidityState.rangeUnderflow The rangeUnderflow property is a read-only boolean [1][2]. It returns true if an input element's value is less than the minimum value specified by its min attribute [1][3]. It applies to numeric and date/time input types (e.g., number, range, date, time) that support the min attribute [1][3]. setCustomValidity Persistence The setCustomValidity method is highly persistent [4]. When you call this method with a non-empty string, it sets the ValidityState.customError flag to true, which marks the element as invalid [5][4]. Crucially, this state does not reset automatically, even if the underlying constraint violation (like rangeUnderflow) is resolved [6][4]. To correctly use setCustomValidity, you must manually clear it by calling setCustomValidity('') (an empty string) [5][6]. A best practice is to clear the custom validity at the start of every validation cycle (e.g., inside an oninput or onchange event handler) before evaluating your validation logic [4]. If you do not clear it, the element will remain stuck in an invalid state regardless of the actual input value [6][4]. aria-invalid Specification The aria-invalid attribute indicates that an element's value does not conform to the application's expected format [7]. While HTML has built-in constraint validation (which uses:invalid CSS pseudo-classes), aria-invalid is an ARIA attribute that must be managed programmatically [8][7]. Key specifications and guidelines include: - Do not set aria-invalid="true" before the user has attempted to interact with the field or submit the form [8][7]. Applying it immediately on page load can create a poor experience for users [7][9]. - aria-invalid and native HTML validation are distinct systems [9]. Native browser validation (such as rangeUnderflow) does not automatically toggle the aria-invalid attribute [10][9]. - If you are building custom validation, you should manually update aria-invalid="true" when an error is detected and aria-invalid="false" (or remove the attribute) when the input is valid [8][7]. - Accessibility specifications recommend using aria-invalid in conjunction with an error message container identified by aria-errormessage [10]. In summary, native HTML validation (ValidityState) and ARIA attributes (aria-invalid) operate independently, and both require careful JavaScript management to ensure they are synchronized correctly with the user's input [7][10].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re

source = Path("saas_web.py").read_text()
for field in ("target_bytes", "batch_target_bytes"):
    match = re.search(
        rf"document\.getElementById\('{field}'\)\.addEventListener\('input', function\(e\) \{{(.*?)\n\s*\}}\);",
        source,
        re.S,
    )
    if not match:
        raise SystemExit(f"missing validation handler for {field}")
    handler = match.group(1)
    empty = re.search(r"if \(this\.value === ''\) \{(.*?)\n\s*\}", handler, re.S)
    if not empty:
        raise SystemExit(f"missing empty-value branch for {field}")
    branch = empty.group(1)
    required = ("this.setCustomValidity('');" in branch and
                "this.removeAttribute('aria-invalid');" in branch)
    print(f"{field}: clears setCustomValidity and aria-invalid for empty value: {required}")
    if not required:
        raise SystemExit(1)
PY

Repository: ContextualWisdomLab/codec-carver

Length of output: 332


λ„€μ΄ν‹°λΈŒ μœ νš¨μ„± μƒνƒœμ™€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μƒνƒœλ₯Ό κ΅¬λΆ„ν•˜μ„Έμš”.

ValidityState.rangeUnderflowλŠ” 이전 값이 μ•„λ‹ˆλΌ ν˜„μž¬ κ°’κ³Ό min을 κΈ°μ€€μœΌλ‘œ κ³„μ‚°λ©λ‹ˆλ‹€. 빈 κ°’μ—μ„œ 이전 음수의 λ„€μ΄ν‹°λΈŒ 였λ₯˜κ°€ μœ μ§€λ˜μ–΄ required 검사λ₯Ό λ°©ν•΄ν•˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. 반면 setCustomValidity()둜 μ„€μ •ν•œ customError와 aria-invalidλŠ” μ½”λ“œκ°€ μ΄ˆκΈ°ν™”ν•  λ•ŒκΉŒμ§€ μœ μ§€λ  수 μžˆμŠ΅λ‹ˆλ‹€. Line 78의 원인을 이 λ‚΄μš©μœΌλ‘œ μˆ˜μ •ν•˜μ„Έμš”.

πŸ€– 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 @.jules/palette.md around lines 77 - 79, Update the guidance in the β€œμˆ«μž μž…λ ₯
ν•„λ“œμ˜ 빈 λ¬Έμžμ—΄ μƒνƒœ μ²˜λ¦¬β€ section to distinguish native ValidityState checks from
application-managed state: remove the claim that a previous negative value
leaves rangeUnderflow active or interferes with required validation, and clarify
that only setCustomValidity() customError and aria-invalid persist until
explicitly reset.

Comment thread saas_web.py
Comment on lines +244 to +252
if (this.value === '') {
this.setCustomValidity('');
this.removeAttribute('aria-invalid');
preview.innerText = '';
const buttons = document.querySelectorAll('#preset_buttons_container .preset-btn');
buttons.forEach(btn => btn.setAttribute('aria-pressed', 'false'));
return;
}
const val = parseInt(this.value, 10);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚑ Quick win

이벀트 ν•Έλ“€λŸ¬κ°€ λ“±λ‘λ˜λ„λ‘ 슀크립트 μ‹€ν–‰ μˆœμ„œλ₯Ό μˆ˜μ •ν•˜μ„Έμš”.

배치 폼은 Lines 400-423μ—μ„œ 슀크립트 뒀에 μ •μ˜λ©λ‹ˆλ‹€. λ”°λΌμ„œ Line 213의 document.getElementById('batch_preset_buttons_container')λŠ” null을 λ°˜ν™˜ν•˜κ³  .addEventListenerμ—μ„œ TypeErrorκ°€ λ°œμƒν•©λ‹ˆλ‹€. 슀크립트 싀행이 μ€‘λ‹¨λ˜λ―€λ‘œ Lines 244-252와 279-287의 input ν•Έλ“€λŸ¬κ°€ λ“±λ‘λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. Line 277의 batch_target_bytes μ‘°νšŒλ„ 같은 DOM μˆœμ„œ 문제λ₯Ό κ°€μ§‘λ‹ˆλ‹€.

슀크립트λ₯Ό 두 폼 λ’€λ‘œ μ΄λ™ν•˜κ±°λ‚˜ λͺ¨λ“  DOM μ‘°νšŒμ™€ 이벀트 등둝을 DOMContentLoaded 이후에 μˆ˜ν–‰ν•˜μ„Έμš”. ν˜„μž¬ tests/test_saas_web.py의 ν…ŒμŠ€νŠΈλŠ” HTML λ¬Έμžμ—΄λ§Œ κ²€μ‚¬ν•˜λ―€λ‘œ, μ‹€μ œ λΈŒλΌμš°μ €μ—μ„œ 빈 μž…λ ₯ μ‹œ μƒνƒœ μ΄ˆκΈ°ν™”λ₯Ό κ²€μ¦ν•˜λŠ” ν…ŒμŠ€νŠΈλ„ μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€.

Also applies to: 279-287

πŸ€– 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 `@saas_web.py` around lines 244 - 252, Ensure the batch-form script initializes
only after the batch form elements exist by moving it after both forms or
deferring all DOM queries and event registration until DOMContentLoaded. Update
the lookups for batch_preset_buttons_container and batch_target_bytes so the
input handlers covering both affected ranges register without null errors.
Extend tests/test_saas_web.py with browser-level coverage verifying empty-input
state reset behavior.

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