From 930c7ffe7da6bc1d655db837feaa8a6bd2a06ac3 Mon Sep 17 00:00:00 2001 From: Jan Faracik <43062514+janfaracik@users.noreply.github.com> Date: Mon, 9 Dec 2024 22:19:12 +0000 Subject: [PATCH] Overhaul search with a Command Palette (#7569) Co-authored-by: Wadeck Follonier Co-authored-by: Tim Jacomb <21194782+timja@users.noreply.github.com> Co-authored-by: Alexander Brandes Co-authored-by: Tim Jacomb --- core/src/main/java/hudson/Functions.java | 10 + core/src/main/java/hudson/model/Job.java | 2 +- core/src/main/java/hudson/search/Search.java | 15 +- .../java/hudson/search/SuggestedItem.java | 2 +- core/src/main/java/jenkins/model/Jenkins.java | 4 +- .../jenkins/views/JenkinsHeader/search-box.js | 6 - .../lib/layout/command-palette.jelly | 47 +++++ .../lib/layout/header/searchbox.jelly | 38 ++-- .../main/resources/lib/layout/layout.jelly | 1 + eslint.config.cjs | 1 - src/main/js/api/search.js | 10 + src/main/js/app.js | 2 + .../components/command-palette/datasources.js | 29 +++ .../js/components/command-palette/index.js | 155 +++++++++++++++ .../js/components/command-palette/models.js | 27 +++ .../js/components/command-palette/symbols.js | 3 + src/main/js/keyboard-shortcuts.js | 24 +-- src/main/scss/abstracts/_mixins.scss | 1 + src/main/scss/abstracts/_theme.scss | 13 ++ .../scss/components/_command-palette.scss | 176 ++++++++++++++++++ src/main/scss/components/_index.scss | 1 + src/main/scss/components/_page-header.scss | 11 ++ src/main/scss/form/_search-bar.scss | 44 +++-- .../hudson/model/AbstractProjectTest.java | 1 + .../test/java/hudson/search/SearchTest.java | 76 +++----- .../hudson/widgets/HistoryWidgetTest.java | 4 +- .../test/java/jenkins/model/JenkinsTest.java | 3 +- .../main/webapp/scripts/hudson-behavior.js | 57 +----- 28 files changed, 600 insertions(+), 163 deletions(-) delete mode 100644 core/src/main/resources/jenkins/views/JenkinsHeader/search-box.js create mode 100644 core/src/main/resources/lib/layout/command-palette.jelly create mode 100644 src/main/js/api/search.js create mode 100644 src/main/js/components/command-palette/datasources.js create mode 100644 src/main/js/components/command-palette/index.js create mode 100644 src/main/js/components/command-palette/models.js create mode 100644 src/main/js/components/command-palette/symbols.js create mode 100644 src/main/scss/components/_command-palette.scss diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index 64add7b35193..67801475233d 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -62,6 +62,7 @@ import hudson.model.View; import hudson.scm.SCM; import hudson.scm.SCMDescriptor; +import hudson.search.SearchFactory; import hudson.search.SearchableModelObject; import hudson.security.ACL; import hudson.security.AccessControlled; @@ -2578,6 +2579,11 @@ public static String generateItemId() { return String.valueOf(Math.floor(Math.random() * 3000)); } + @Restricted(NoExternalUse.class) + public static ExtensionList getSearchFactories() { + return SearchFactory.all(); + } + /** * @param keyboardShortcut the shortcut to be translated * @return the translated shortcut, e.g. CMD+K to ⌘+K for macOS, CTRL+K for Windows @@ -2596,6 +2602,10 @@ public static String translateModifierKeysForUsersPlatform(String keyboardShortc @Restricted(NoExternalUse.class) public static String formatMessage(String format, Object args) { + if (format == null) { + return args.toString(); + } + return MessageFormat.format(format, args); } } diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index d22c25e98e3d..7d140656e363 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -541,7 +541,7 @@ public void find(String token, List result) { public void suggest(String token, List result) { find(token, result); } - }).add("configure", "config", "configure"); + }); } @Override diff --git a/core/src/main/java/hudson/search/Search.java b/core/src/main/java/hudson/search/Search.java index 7773d9e9d696..9bd624e34742 100644 --- a/core/src/main/java/hudson/search/Search.java +++ b/core/src/main/java/hudson/search/Search.java @@ -158,7 +158,7 @@ public void doSuggestOpenSearch(StaplerRequest2 req, StaplerResponse2 rsp, @Quer public void doSuggest(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter String query) throws IOException, ServletException { Result r = new Result(); for (SuggestedItem item : getSuggestions(req, query)) - r.suggestions.add(new Item(item.getPath())); + r.suggestions.add(new Item(item.getPath(), item.getUrl())); rsp.serveExposedBean(req, r, Flavor.JSON); } @@ -252,12 +252,25 @@ public static class Result { @ExportedBean(defaultVisibility = 999) public static class Item { + @Exported @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "read by Stapler") public String name; + private final String url; + public Item(String name) { + this(name, null); + } + + public Item(String name, String url) { this.name = name; + this.url = url; + } + + @Exported + public String getUrl() { + return url; } } diff --git a/core/src/main/java/hudson/search/SuggestedItem.java b/core/src/main/java/hudson/search/SuggestedItem.java index 9ba455270e58..6911d002fe50 100644 --- a/core/src/main/java/hudson/search/SuggestedItem.java +++ b/core/src/main/java/hudson/search/SuggestedItem.java @@ -62,7 +62,7 @@ private void getPath(StringBuilder buf) { buf.append(item.getSearchName()); else { parent.getPath(buf); - buf.append(' ').append(item.getSearchName()); + buf.append(" » ").append(item.getSearchName()); } } diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index bedbea0af7c4..eee96b5bca05 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -2346,9 +2346,7 @@ public String getSearchUrl() { public SearchIndexBuilder makeSearchIndex() { SearchIndexBuilder builder = super.makeSearchIndex(); if (hasPermission(ADMINISTER)) { - builder.add("configure", "config", "configure") - .add("manage") - .add("log"); + builder.add("manage", Messages.ManageJenkinsAction_DisplayName()); } builder.add(new CollectionSearchIndex() { @Override diff --git a/core/src/main/resources/jenkins/views/JenkinsHeader/search-box.js b/core/src/main/resources/jenkins/views/JenkinsHeader/search-box.js deleted file mode 100644 index 91e805c4ceaf..000000000000 --- a/core/src/main/resources/jenkins/views/JenkinsHeader/search-box.js +++ /dev/null @@ -1,6 +0,0 @@ -(function () { - var element = document.getElementById("search-box-completion"); - if (element) { - createSearchBox(element.getAttribute("data-search-url")); - } -})(); diff --git a/core/src/main/resources/lib/layout/command-palette.jelly b/core/src/main/resources/lib/layout/command-palette.jelly new file mode 100644 index 000000000000..3d454f88a8c1 --- /dev/null +++ b/core/src/main/resources/lib/layout/command-palette.jelly @@ -0,0 +1,47 @@ + + + + + + The command palette overlay + + +
+ + +
+
+ +
+
+
+
+
+
+ diff --git a/core/src/main/resources/lib/layout/header/searchbox.jelly b/core/src/main/resources/lib/layout/header/searchbox.jelly index 916f5ad49c22..033dc2ab0407 100644 --- a/core/src/main/resources/lib/layout/header/searchbox.jelly +++ b/core/src/main/resources/lib/layout/header/searchbox.jelly @@ -1,25 +1,27 @@ - -