aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx
diff options
context:
space:
mode:
authorJay <jeremy.davis@sonarsource.com>2021-09-13 15:55:09 +0200
committersonartech <sonartech@sonarsource.com>2021-09-13 20:03:33 +0000
commit80e5b85977523f14c1bb14ea90cb0cc73f4aa59d (patch)
tree5dd8e82ee6656145efbd8c73e40e4726b4f1cb95 /server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx
parent31013914e9b61d4d40ec71cbaaf7f852465a6aec (diff)
downloadsonarqube-80e5b85977523f14c1bb14ea90cb0cc73f4aa59d.tar.gz
sonarqube-80e5b85977523f14c1bb14ea90cb0cc73f4aa59d.zip
SONAR-15366 Add Settings Search feature
Diffstat (limited to 'server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx')
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx103
1 files changed, 103 insertions, 0 deletions
diff --git a/server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx
new file mode 100644
index 00000000000..c52febbcb5c
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx
@@ -0,0 +1,103 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as classNames from 'classnames';
+import * as React from 'react';
+import { Link } from 'react-router';
+import { DropdownOverlay } from '../../../components/controls/Dropdown';
+import OutsideClickHandler from '../../../components/controls/OutsideClickHandler';
+import SearchBox from '../../../components/controls/SearchBox';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { scrollToElement } from '../../../helpers/scrolling';
+import { SettingCategoryDefinition } from '../../../types/settings';
+import { buildSettingLink, isRealSettingKey } from '../utils';
+
+export interface SettingsSearchRendererProps {
+ className?: string;
+ results?: SettingCategoryDefinition[];
+ searchQuery: string;
+ selectedResult?: string;
+ showResults: boolean;
+ onClickOutside: () => void;
+ onMouseOverResult: (key: string) => void;
+ onSearchInputChange: (query: string) => void;
+ onSearchInputFocus: () => void;
+ onSearchInputKeyDown: (event: React.KeyboardEvent) => void;
+}
+
+export default function SettingsSearchRenderer(props: SettingsSearchRendererProps) {
+ const { className, results, searchQuery, selectedResult, showResults } = props;
+
+ const scrollableNodeRef = React.useRef(null);
+ const selectedNodeRef = React.useRef<HTMLLIElement>(null);
+
+ React.useEffect(() => {
+ const parent = scrollableNodeRef.current;
+ const selectedNode = selectedNodeRef.current;
+ if (selectedNode && parent) {
+ scrollToElement(selectedNode, { topOffset: 30, bottomOffset: 30, parent });
+ }
+ });
+
+ return (
+ <OutsideClickHandler onClickOutside={props.onClickOutside}>
+ <div className={classNames('dropdown', className)}>
+ <SearchBox
+ onChange={props.onSearchInputChange}
+ onFocus={props.onSearchInputFocus}
+ onKeyDown={props.onSearchInputKeyDown}
+ placeholder={translate('settings.search.placeholder')}
+ value={searchQuery}
+ />
+ {showResults && (
+ <DropdownOverlay noPadding={true}>
+ <ul className="settings-search-results menu" ref={scrollableNodeRef}>
+ {results && results.length > 0 ? (
+ results.map(r => (
+ <li
+ key={r.key}
+ className={classNames('spacer-bottom spacer-top', {
+ active: selectedResult === r.key
+ })}
+ ref={selectedResult === r.key ? selectedNodeRef : undefined}>
+ <Link
+ onClick={props.onClickOutside}
+ onMouseEnter={() => props.onMouseOverResult(r.key)}
+ to={buildSettingLink(r)}>
+ <div className="settings-search-result-title display-flex-space-between">
+ <h3>{r.name || r.subCategory}</h3>
+ </div>
+ {isRealSettingKey(r.key) && (
+ <div className="note spacer-top">
+ {translateWithParameters('settings.key_x', r.key)}
+ </div>
+ )}
+ </Link>
+ </li>
+ ))
+ ) : (
+ <div className="big-padded">{translate('no_results')}</div>
+ )}
+ </ul>
+ </DropdownOverlay>
+ )}
+ </div>
+ </OutsideClickHandler>
+ );
+}