- {dirty ? t('system_info.version_current_missing') : loading ? t('common.loading') : t('system_info.version_is_latest')}
+ } else {
+ // Find previous match before cursor
+ for (let i = matches.length - 1; i >= 0; i--) {
+ if (matches[i] < cursorPos) {
+ currentIndex = i;
+ break;
+ }
+ // If no match before cursor, wrap to last
+ if (i === 0) {
+ currentIndex = matches.length - 1;
+ }
+ }
+ }
+
+ const matchPos = matches[currentIndex];
+ setSearchResults({ current: currentIndex + 1, total: matches.length });
+
+ // Scroll to and select the match
+ view.dispatch({
+ selection: { anchor: matchPos, head: matchPos + query.length },
+ scrollIntoView: true
+ });
+ view.focus();
+ }, []);
+
+ const handleSearchChange = useCallback((value: string) => {
+ setSearchQuery(value);
+ if (value) {
+ performSearch(value);
+ } else {
+ setSearchResults({ current: 0, total: 0 });
+ }
+ }, [performSearch]);
+
+ const handleSearchKeyDown = useCallback((e: React.KeyboardEvent) => {
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ performSearch(searchQuery, e.shiftKey ? 'prev' : 'next');
+ }
+ }, [searchQuery, performSearch]);
+
+ const handlePrevMatch = useCallback(() => {
+ performSearch(searchQuery, 'prev');
+ }, [searchQuery, performSearch]);
+
+ const handleNextMatch = useCallback(() => {
+ performSearch(searchQuery, 'next');
+ }, [searchQuery, performSearch]);
+
+ // CodeMirror extensions
+ const extensions = useMemo(() => [
+ yaml(),
+ search(),
+ highlightSelectionMatches(),
+ keymap.of(searchKeymap)
+ ], []);
+
+ // Status text
+ const getStatusText = () => {
+ if (disableControls) return t('config_management.status_disconnected');
+ if (loading) return t('config_management.status_loading');
+ if (error) return t('config_management.status_load_failed');
+ if (saving) return t('config_management.status_saving');
+ if (dirty) return t('config_management.status_dirty');
+ return t('config_management.status_loaded');
+ };
+
+ const getStatusClass = () => {
+ if (error) return styles.error;
+ if (dirty) return styles.modified;
+ if (!loading && !saving) return styles.saved;
+ return '';
+ };
+
+ return (
+
+
{t('config_management.title')}
+
{t('config_management.description')}
+
+
+
+ {/* Search bar */}
+
+
+ handleSearchChange(e.target.value)}
+ onKeyDown={handleSearchKeyDown}
+ placeholder={t('config_management.search_placeholder', { defaultValue: '搜索配置内容... (Enter 下一个, Shift+Enter 上一个)' })}
+ disabled={disableControls || loading}
+ className={styles.searchInput}
+ />
+ {searchQuery && (
+
+ {searchResults.total > 0
+ ? `${searchResults.current} / ${searchResults.total}`
+ : t('config_management.search_no_results', { defaultValue: '无结果' })}
+
+ )}
+
+
+
+
+
+
+
+ {/* Editor */}
+ {error &&
{error}
}
+
+
+
+
+ {/* Controls */}
+
+
+ {getStatusText()}
+
+
+
+
+
+
-
-
+
+
);
}
diff --git a/src/types/style.d.ts b/src/types/style.d.ts
index b201206..872810a 100644
--- a/src/types/style.d.ts
+++ b/src/types/style.d.ts
@@ -2,3 +2,6 @@ declare module '*.module.scss' {
const classes: Record