diff --git a/war/src/main/js/api/search.js b/war/src/main/js/api/search.js index 900a3d2a0add..b19f956536b9 100644 --- a/war/src/main/js/api/search.js +++ b/war/src/main/js/api/search.js @@ -2,7 +2,9 @@ * @param {string} searchTerm */ async function search(searchTerm) { - const address = document.getElementById("page-header").dataset.searchUrl.escapeHTML(); + const address = document + .getElementById("page-header") + .dataset.searchUrl.escapeHTML(); return fetch(`${address}?query=${searchTerm}`); } diff --git a/war/src/main/js/api/symbols.js b/war/src/main/js/api/symbols.js index c68cab6c7425..8f7da30393c9 100644 --- a/war/src/main/js/api/symbols.js +++ b/war/src/main/js/api/symbols.js @@ -1,7 +1,11 @@ import jenkins from "@/util/jenkins"; export function getSymbol(symbol, handler) { - jenkins.get("/symbols?symbol=" + symbol, function(res) { - handler(res.data["symbol"]) - }, {async: false}); + jenkins.get( + "/symbols?symbol=" + symbol, + function (res) { + handler(res.data["symbol"]); + }, + { async: false } + ); } diff --git a/war/src/main/js/components/command-palette/command-palette.js b/war/src/main/js/components/command-palette/command-palette.js index 50207c294746..558e6cf9d743 100644 --- a/war/src/main/js/components/command-palette/command-palette.js +++ b/war/src/main/js/components/command-palette/command-palette.js @@ -1,42 +1,50 @@ -import {LinkResult} from "@/components/command-palette/models" -import {JenkinsSearchSource, SidebarSource} from "./datasources" -import Helpers from './helpers' -import debounce from "lodash/debounce" - -const datasources = [JenkinsSearchSource, SidebarSource] - -window.addEventListener('load', () => { - const i18n = document.getElementById("command-palette-i18n") - const headerCommandPaletteButton = document.getElementById("button-open-command-palette") - const commandPalette = document.getElementById("command-palette") - const commandPaletteWrapper = commandPalette.querySelector(".jenkins-command-palette__wrapper") - const commandPaletteInput = document.getElementById("command-bar") - const commandPaletteSearchBarContainer = commandPalette.querySelector(".jenkins-command-palette__search") - const searchResults = document.getElementById("search-results") - const searchResultsContainer = document.getElementById("search-results-container") - - const hoverClass = "jenkins-command-palette__results__item--hover" +import { LinkResult } from "@/components/command-palette/models"; +import { JenkinsSearchSource, SidebarSource } from "./datasources"; +import Helpers from "./helpers"; +import debounce from "lodash/debounce"; + +const datasources = [JenkinsSearchSource, SidebarSource]; + +window.addEventListener("load", () => { + const i18n = document.getElementById("command-palette-i18n"); + const headerCommandPaletteButton = document.getElementById( + "button-open-command-palette" + ); + const commandPalette = document.getElementById("command-palette"); + const commandPaletteWrapper = commandPalette.querySelector( + ".jenkins-command-palette__wrapper" + ); + const commandPaletteInput = document.getElementById("command-bar"); + const commandPaletteSearchBarContainer = commandPalette.querySelector( + ".jenkins-command-palette__search" + ); + const searchResults = document.getElementById("search-results"); + const searchResultsContainer = document.getElementById( + "search-results-container" + ); + + const hoverClass = "jenkins-command-palette__results__item--hover"; // Events headerCommandPaletteButton.addEventListener("click", async function () { if (commandPalette.hasAttribute("open")) { - hideCommandPalette() + hideCommandPalette(); } else { - await showCommandPalette() + await showCommandPalette(); } - }) + }); commandPaletteWrapper.addEventListener("click", function (e) { if (e.target !== e.currentTarget) { - return + return; } - hideCommandPalette() - }) + hideCommandPalette(); + }); async function renderResults() { - const query = commandPaletteInput.value - let results + const query = commandPaletteInput.value; + let results; if (query.length === 0) { results = [ @@ -45,137 +53,152 @@ window.addEventListener('load', () => { i18n.dataset.getHelp, undefined, "Help", - document.getElementById("page-header").dataset.searchHelpUrl.escapeHTML(), + document + .getElementById("page-header") + .dataset.searchHelpUrl.escapeHTML(), true - ) - ] + ), + ]; } else { - await Promise.all(datasources.map(ds => ds.execute(query))).then(response => { - results = response.flat() - }) + await Promise.all(datasources.map((ds) => ds.execute(query))).then( + (response) => { + results = response.flat(); + } + ); } - results = Helpers.groupResultsByCategory(results) + results = Helpers.groupResultsByCategory(results); // Clear current search results - searchResults.innerHTML = "" + searchResults.innerHTML = ""; if (query.length === 0 || Object.keys(results).length > 0) { for (const [category, items] of Object.entries(results)) { - const heading = document.createElement("p") - heading.className = "jenkins-command-palette__results__heading" - heading.innerText = category - searchResults.append(heading) + const heading = document.createElement("p"); + heading.className = "jenkins-command-palette__results__heading"; + heading.innerText = category; + searchResults.append(heading); items.forEach(function (obj) { - const renderedObject = obj.render() + const renderedObject = obj.render(); - let link = document.createElement("DIV") + let link = document.createElement("DIV"); if (renderedObject instanceof HTMLElement) { - link = renderedObject + link = renderedObject; } else { - link.innerHTML = renderedObject - link = link.firstChild + link.innerHTML = renderedObject; + link = link.firstChild; } - link.addEventListener("mouseenter", e => itemMouseEnter(e)) - searchResults.append(link) - }) + link.addEventListener("mouseenter", (e) => itemMouseEnter(e)); + searchResults.append(link); + }); } - updateSelectedItem(0) + updateSelectedItem(0); } else { - const label = document.createElement("p") - label.className = "jenkins-command-palette__info" - label.innerHTML = "" + i18n.dataset.noResultsFor.escapeHTML() + " " + commandPaletteInput.value.escapeHTML() - searchResults.append(label) + const label = document.createElement("p"); + label.className = "jenkins-command-palette__info"; + label.innerHTML = + "" + + i18n.dataset.noResultsFor.escapeHTML() + + " " + + commandPaletteInput.value.escapeHTML(); + searchResults.append(label); } - searchResultsContainer.style.height = searchResults.offsetHeight + "px" - commandPaletteSearchBarContainer.classList.remove("jenkins-search--loading") + searchResultsContainer.style.height = searchResults.offsetHeight + "px"; + commandPaletteSearchBarContainer.classList.remove( + "jenkins-search--loading" + ); } commandPaletteInput.addEventListener("input", () => { - commandPaletteSearchBarContainer.classList.add("jenkins-search--loading") - debounce(renderResults, 300)() - }) + commandPaletteSearchBarContainer.classList.add("jenkins-search--loading"); + debounce(renderResults, 300)(); + }); commandPaletteInput.addEventListener("keyup", function (event) { - const maxLength = searchResults.getElementsByTagName("a").length - let selectedIndex = -1 - let hoveredItem = document.querySelector("." + hoverClass) + const maxLength = searchResults.getElementsByTagName("a").length; + let selectedIndex = -1; + let hoveredItem = document.querySelector("." + hoverClass); if (hoveredItem) { - selectedIndex = [...hoveredItem.parentElement.getElementsByTagName("a")].indexOf(hoveredItem) + selectedIndex = [ + ...hoveredItem.parentElement.getElementsByTagName("a"), + ].indexOf(hoveredItem); } switch (event.code) { case "Enter": if (hoveredItem) { - window.location.href = hoveredItem.href + window.location.href = hoveredItem.href; } - return false + return false; case "ArrowUp": if (selectedIndex !== -1) { if (selectedIndex - 1 < 0) { - selectedIndex = maxLength - 1 + selectedIndex = maxLength - 1; } else { - selectedIndex-- + selectedIndex--; } - updateSelectedItem(selectedIndex, selectedIndex + 1 >= maxLength) + updateSelectedItem(selectedIndex, selectedIndex + 1 >= maxLength); } - return false + return false; case "ArrowDown": if (selectedIndex !== -1) { if (selectedIndex + 1 >= maxLength) { - selectedIndex = 0 + selectedIndex = 0; } else { - selectedIndex++ + selectedIndex++; } - updateSelectedItem(selectedIndex, selectedIndex + 1 >= maxLength) + updateSelectedItem(selectedIndex, selectedIndex + 1 >= maxLength); } - return false + return false; } - }) + }); // Helper methods for visibility of command palette async function showCommandPalette() { - commandPalette.showModal() - commandPaletteInput.focus() - commandPaletteInput.setSelectionRange(commandPaletteInput.value.length, commandPaletteInput.value.length) - - await renderResults() + commandPalette.showModal(); + commandPaletteInput.focus(); + commandPaletteInput.setSelectionRange( + commandPaletteInput.value.length, + commandPaletteInput.value.length + ); + + await renderResults(); } function hideCommandPalette() { - commandPalette.close() + commandPalette.close(); } function itemMouseEnter(item) { - let hoveredItems = document.querySelector("." + hoverClass) + let hoveredItems = document.querySelector("." + hoverClass); if (hoveredItems) { - hoveredItems.classList.remove(hoverClass) + hoveredItems.classList.remove(hoverClass); } - item.target.classList.add(hoverClass) + item.target.classList.add(hoverClass); } function updateSelectedItem(index, scrollIntoView = false) { - const maxLength = searchResults.getElementsByTagName("a").length - const hoveredItem = document.querySelector("." + hoverClass) + const maxLength = searchResults.getElementsByTagName("a").length; + const hoveredItem = document.querySelector("." + hoverClass); if (hoveredItem) { - hoveredItem.classList.remove(hoverClass) + hoveredItem.classList.remove(hoverClass); } if (index < maxLength) { - const element = [...searchResults.getElementsByTagName("a")][index] - element.classList.add(hoverClass) + const element = [...searchResults.getElementsByTagName("a")][index]; + element.classList.add(hoverClass); if (scrollIntoView) { - element.scrollIntoView() + element.scrollIntoView(); } } } -}) +}); diff --git a/war/src/main/js/components/command-palette/datasources.js b/war/src/main/js/components/command-palette/datasources.js index bff857587bf6..3b425454e8db 100644 --- a/war/src/main/js/components/command-palette/datasources.js +++ b/war/src/main/js/components/command-palette/datasources.js @@ -1,26 +1,49 @@ -import {LinkResult} from "./models"; +import { LinkResult } from "./models"; import Search from "@/api/search"; export const JenkinsSearchSource = { async execute(query) { - const rootUrl = document.getElementById("page-header").dataset.rootUrl.escapeHTML(); + const rootUrl = document + .getElementById("page-header") + .dataset.rootUrl.escapeHTML(); const response = await Search.search(query); - return await response.json().then(data => { - return [...data["suggestions"]].map(e => new LinkResult(e.icon, e.name, e.description, e.category, - e.url.startsWith("/") ? `${rootUrl}${e.url}` : `${rootUrl}`)); + return await response.json().then((data) => { + return [...data["suggestions"]].map( + (e) => + new LinkResult( + e.icon, + e.name, + e.description, + e.category, + e.url.startsWith("/") ? `${rootUrl}${e.url}` : `${rootUrl}` + ) + ); }); - } -} + }, +}; export const SidebarSource = { async execute(query) { const sidebarLinks = document.querySelectorAll(".task-link"); return [...sidebarLinks] - .filter(link => link.dataset.post !== "true") - .filter(link => !link.classList.contains("task-link--active")) - .filter(link => link.querySelector(".task-link-text").textContent.toLowerCase().includes(query.toLowerCase())) - .map(link => new LinkResult(undefined, link.querySelector(".task-link-text").textContent, undefined, - "Sidebar", link.href)); - } -} + .filter((link) => link.dataset.post !== "true") + .filter((link) => !link.classList.contains("task-link--active")) + .filter((link) => + link + .querySelector(".task-link-text") + .textContent.toLowerCase() + .includes(query.toLowerCase()) + ) + .map( + (link) => + new LinkResult( + undefined, + link.querySelector(".task-link-text").textContent, + undefined, + "Sidebar", + link.href + ) + ); + }, +}; diff --git a/war/src/main/js/components/command-palette/helpers.js b/war/src/main/js/components/command-palette/helpers.js index 44f3e28934b0..d6c6e69b19db 100644 --- a/war/src/main/js/components/command-palette/helpers.js +++ b/war/src/main/js/components/command-palette/helpers.js @@ -1,10 +1,11 @@ // Group results by 'category' field into map function groupResultsByCategory(array) { - return array - .reduce((hash, obj) => { - if (obj.category === undefined) return hash - return Object.assign(hash, {[obj.category]: (hash[obj.category] || []).concat(obj)}) - }, {}) + return array.reduce((hash, obj) => { + if (obj.category === undefined) {return hash;} + return Object.assign(hash, { + [obj.category]: (hash[obj.category] || []).concat(obj), + }); + }, {}); } -export default {groupResultsByCategory: groupResultsByCategory}; +export default { groupResultsByCategory: groupResultsByCategory }; diff --git a/war/src/main/js/components/command-palette/models.js b/war/src/main/js/components/command-palette/models.js index 6f829a28f3b5..7db1dc9e827d 100644 --- a/war/src/main/js/components/command-palette/models.js +++ b/war/src/main/js/components/command-palette/models.js @@ -1,5 +1,5 @@ import * as Symbols from "./symbols"; -import {getSymbol} from "@/api/symbols"; +import { getSymbol } from "@/api/symbols"; export class LinkResult { constructor(icon, label, description, category, url, isExternal) { @@ -14,16 +14,22 @@ export class LinkResult { let icon2; getSymbol(this.icon, (e) => { - icon2 = e - }) + icon2 = e; + }); - // this.icon.includes("symbol-") ? getSymbol(this.icon, (e) => {icon = e}) : `` + // this.icon.includes("symbol-") ? getSymbol(this.icon, (e) => {icon = e}) : `` - return ` + return `
${icon2}
${this.label} - ${this.description ? `${this.description}` : ``} + ${ + this.description + ? `${this.description}` + : `` + } ${this.isExternal ? Symbols.EXTERNAL_LINK : Symbols.CHEVRON_RIGHT} -
` + `; } } diff --git a/war/src/main/less/modules/command-palette.less b/war/src/main/less/modules/command-palette.less index da05666f328c..6364820b30be 100644 --- a/war/src/main/less/modules/command-palette.less +++ b/war/src/main/less/modules/command-palette.less @@ -1,6 +1,7 @@ @media (prefers-color-scheme: light) { :root { - --command-palette-results-backdrop-filter: contrast(0.7) brightness(1.5) saturate(1.4) blur(20px); + --command-palette-results-backdrop-filter: contrast(0.7) brightness(1.5) + saturate(1.4) blur(20px); --command-palette-drop-shadow: 0 5px 60px rgba(5, 5, 30, 0.5); --command-palette-inset-shadow: inset 0 0 2px 2px rgba(white, 0.1); } @@ -14,7 +15,8 @@ @media (prefers-color-scheme: dark) { :root { - --command-palette-results-backdrop-filter: contrast(0.95) brightness(1.2) saturate(2) blur(30px); + --command-palette-results-backdrop-filter: contrast(0.95) brightness(1.2) + saturate(2) blur(30px); --command-palette-drop-shadow: 0 0 60px rgba(10, 10, 15, 0.65); --command-palette-inset-shadow: inset 0 0 0 1px hsla(250, 10%, 90%, 0.035); } diff --git a/war/src/main/less/modules/page-header.less b/war/src/main/less/modules/page-header.less index 045343512ac6..fa08fc540e88 100644 --- a/war/src/main/less/modules/page-header.less +++ b/war/src/main/less/modules/page-header.less @@ -48,25 +48,26 @@ a.page-header__brand-link { align-items: center; } -.page-header__hyperlinks a, .page-header__hyperlinks button { - --text-color: var(--header-link-color); - - display: inline-flex; - align-items: center; - background: transparent; - border: none; - outline: none; - - // need to override an existing rule - /* stylelint-disable declaration-block-no-shorthand-property-overrides */ - padding-right: 0.5rem; - padding: 0.5rem; - margin-right: 0 !important; - font-weight: bold; - border-radius: var(--header-item-border-radius); - color: var(--header-link-color); - cursor: pointer; - transition: 0.2s ease; +.page-header__hyperlinks a, +.page-header__hyperlinks button { + --text-color: var(--header-link-color); + + display: inline-flex; + align-items: center; + background: transparent; + border: none; + outline: none; + + // need to override an existing rule + /* stylelint-disable declaration-block-no-shorthand-property-overrides */ + padding-right: 0.5rem; + padding: 0.5rem; + margin-right: 0 !important; + font-weight: bold; + border-radius: var(--header-item-border-radius); + color: var(--header-link-color); + cursor: pointer; + transition: 0.2s ease; &:link, &:visited { @@ -88,10 +89,10 @@ a.page-header__brand-link { background-color: var(--header-link-bg-classic-active); } - svg { - width: 18px; - height: 18px; - } + svg { + width: 18px; + height: 18px; + } .jenkins-menu-dropdown-chevron { position: relative; diff --git a/war/webpack.config.js b/war/webpack.config.js index ea2cbe9b2af8..1d90f094e16d 100644 --- a/war/webpack.config.js +++ b/war/webpack.config.js @@ -30,7 +30,12 @@ module.exports = (env, argv) => ({ path.join(__dirname, "src/main/js/config-tabbar.js"), path.join(__dirname, "src/main/js/config-tabbar.less"), ], - "command-palette": [path.join(__dirname, "src/main/js/components/command-palette/command-palette.js")], + "command-palette": [ + path.join( + __dirname, + "src/main/js/components/command-palette/command-palette.js" + ), + ], "keyboard-shortcuts": [ path.join(__dirname, "src/main/js/keyboard-shortcuts.js"), ], @@ -179,7 +184,7 @@ module.exports = (env, argv) => ({ }, resolve: { alias: { - '@': path.resolve(__dirname, 'src/main/js'), + "@": path.resolve(__dirname, "src/main/js"), // Needed to be able to register helpers at runtime handlebars: "handlebars/runtime", },