diff --git a/CHANGELOG.d/1131-dashboard-upload-proxy.md b/CHANGELOG.d/1131-dashboard-upload-proxy.md new file mode 100644 index 00000000..46d896fe --- /dev/null +++ b/CHANGELOG.d/1131-dashboard-upload-proxy.md @@ -0,0 +1,2 @@ +### Changed +- (Dashboard) 헤더의 findings 파일 선택 컨트롤을 기존 `primary-action` 버튼으로 표시하고, 실제 파일 선택은 숨긴 네이티브 파일 입력이 계속 담당하도록 정리했습니다. diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html index 132bc31b..078a72bd 100644 --- a/scanner/dashboard/index.html +++ b/scanner/dashboard/index.html @@ -93,7 +93,8 @@ AppGuardrail no findings loaded - + +

@@ -324,7 +325,9 @@

Dashboard

render(); } +const headerBrowseFindings = document.getElementById('header-browse-findings'); const fileInput = document.getElementById('file'); +headerBrowseFindings.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', () => { const selectedFile = fileInput.files?.[0]; fileInput.value = ''; diff --git a/tests/test_dashboard_core.py b/tests/test_dashboard_core.py index 75a5809f..be738615 100644 --- a/tests/test_dashboard_core.py +++ b/tests/test_dashboard_core.py @@ -77,7 +77,7 @@ def test_dashboard_rows_are_keyboard_accessible(): assert 'tabindex="0" role="button"' in html assert 'title="View details for finding"' in html assert "tbody tr:focus-visible" in html - assert "aria-label=\"Upload findings file\"" in html + assert ">Upload findings file" in html assert "aria-label=\"Search findings\"" in html assert "aria-label=\"Filter by severity\"" in html assert "tr.addEventListener('keydown'" in html diff --git a/tests/test_dashboard_upload_proxy_contract.py b/tests/test_dashboard_upload_proxy_contract.py new file mode 100644 index 00000000..06220881 --- /dev/null +++ b/tests/test_dashboard_upload_proxy_contract.py @@ -0,0 +1,20 @@ +"""Regression contract for the dashboard header findings-file picker proxy.""" + +from scanner.cli.appguardrail import dashboard_index_path + + +def test_header_upload_proxy_preserves_native_file_input_contract(): + """Visible button activation delegates to the hidden native picker boundary.""" + html = dashboard_index_path().read_text(encoding="utf-8") + + assert '' in html + assert ( + '' in html + ) + assert "const headerBrowseFindings = document.getElementById('header-browse-findings');" in html + assert "const fileInput = document.getElementById('file');" in html + assert "headerBrowseFindings.addEventListener('click', () => fileInput.click());" in html + assert "const selectedFile = fileInput.files?.[0];" in html + assert "fileInput.value = '';" in html + assert "if(!selectedFile) return;" in html