From ad247f2fc11415fa4e54089b0e53fde30127f517 Mon Sep 17 00:00:00 2001 From: yangdx Date: Wed, 24 Sep 2025 19:59:56 +0800 Subject: [PATCH] refactor: improve accessibility and i18n for search components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Replace label with ariaLabel prop • Add searchPlaceholder support • Use i18n keys for messages • Improve aria-label attributes • Standardize noResultsMessage fallback --- .../src/components/graph/GraphLabels.tsx | 6 ++++-- .../src/components/graph/GraphSearch.tsx | 3 ++- lightrag_webui/src/components/ui/AsyncSearch.tsx | 9 +++++---- lightrag_webui/src/components/ui/AsyncSelect.tsx | 14 +++++++++----- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/lightrag_webui/src/components/graph/GraphLabels.tsx b/lightrag_webui/src/components/graph/GraphLabels.tsx index 76a7757b..7ec2b6f5 100644 --- a/lightrag_webui/src/components/graph/GraphLabels.tsx +++ b/lightrag_webui/src/components/graph/GraphLabels.tsx @@ -185,9 +185,11 @@ const GraphLabels = () => { renderOption={(item) =>
{item}
} getOptionValue={(item) => item} getDisplayValue={(item) =>
{item}
} - notFound={
No labels found
} - label={t('graphPanel.graphLabels.label')} + notFound={
{t('graphPanel.graphLabels.noLabels')}
} + ariaLabel={t('graphPanel.graphLabels.label')} placeholder={t('graphPanel.graphLabels.placeholder')} + searchPlaceholder={t('graphPanel.graphLabels.placeholder')} + noResultsMessage={t('graphPanel.graphLabels.noLabels')} value={label !== null ? label : '*'} onChange={(newLabel) => { const currentLabel = useSettingsStore.getState().queryLabel; diff --git a/lightrag_webui/src/components/graph/GraphSearch.tsx b/lightrag_webui/src/components/graph/GraphSearch.tsx index 0b7c2577..69fabb28 100644 --- a/lightrag_webui/src/components/graph/GraphSearch.tsx +++ b/lightrag_webui/src/components/graph/GraphSearch.tsx @@ -215,8 +215,9 @@ export const GraphSearchInput = ({ onFocus={(id) => { if (id !== messageId && onFocus) onFocus(id ? { id, type: 'nodes' } : null) }} - label={'item'} + ariaLabel={t('graphPanel.search.placeholder')} placeholder={t('graphPanel.search.placeholder')} + noResultsMessage={t('graphPanel.search.placeholder')} /> ) } diff --git a/lightrag_webui/src/components/ui/AsyncSearch.tsx b/lightrag_webui/src/components/ui/AsyncSearch.tsx index 7b71fd77..d2c6c59d 100644 --- a/lightrag_webui/src/components/ui/AsyncSearch.tsx +++ b/lightrag_webui/src/components/ui/AsyncSearch.tsx @@ -41,8 +41,8 @@ export interface AsyncSearchProps { onChange: (value: string) => void /** Callback when focus changes */ onFocus: (value: string) => void - /** Label for the select field */ - label: string + /** Accessibility label for the search field */ + ariaLabel?: string /** Placeholder text when no selection */ placeholder?: string /** Disable the entire select */ @@ -67,7 +67,7 @@ export function AsyncSearch({ getOptionValue, notFound, loadingSkeleton, - label, + ariaLabel, placeholder = 'Select...', value, onChange, @@ -179,6 +179,7 @@ export function AsyncSearch({ placeholder={placeholder} value={searchTerm} className="max-h-8" + aria-label={ariaLabel} onFocus={handleFocus} onValueChange={(value) => { setSearchTerm(value) @@ -198,7 +199,7 @@ export function AsyncSearch({ !error && options.length === 0 && (notFound || ( - {noResultsMessage ?? `No ${label.toLowerCase()} found.`} + {noResultsMessage || 'No results found.'} ))} {options.map((option, idx) => ( diff --git a/lightrag_webui/src/components/ui/AsyncSelect.tsx b/lightrag_webui/src/components/ui/AsyncSelect.tsx index ea5d4de2..bed0d290 100644 --- a/lightrag_webui/src/components/ui/AsyncSelect.tsx +++ b/lightrag_webui/src/components/ui/AsyncSelect.tsx @@ -43,10 +43,12 @@ export interface AsyncSelectProps { value: string /** Callback when selection changes */ onChange: (value: string) => void - /** Label for the select field */ - label: string + /** Accessibility label for the select field */ + ariaLabel?: string /** Placeholder text when no selection */ placeholder?: string + /** Display text for search placeholder */ + searchPlaceholder?: string /** Disable the entire select */ disabled?: boolean /** Custom width for the popover * @@ -76,8 +78,9 @@ export function AsyncSelect({ getDisplayValue, notFound, loadingSkeleton, - label, + ariaLabel, placeholder = 'Select...', + searchPlaceholder, value, onChange, disabled = false, @@ -200,6 +203,7 @@ export function AsyncSelect({ variant="outline" role="combobox" aria-expanded={open} + aria-label={ariaLabel} className={cn( 'justify-between', disabled && 'cursor-not-allowed opacity-50', @@ -223,7 +227,7 @@ export function AsyncSelect({
{ setSearchTerm(value) @@ -244,7 +248,7 @@ export function AsyncSelect({ options.length === 0 && (notFound || ( - {noResultsMessage ?? `No ${label.toLowerCase()} found.`} + {noResultsMessage || 'No results found.'} ))}