Skip to content

Commit

Permalink
Feat: Provide filtering capabilities for scalers (kedacore#1400)
Browse files Browse the repository at this point in the history
* Feat: Provide filtering capabilities for scalers

Signed-off-by: thisisobate <[email protected]>

* chore: provide filter button on mobile

Signed-off-by: thisisobate <[email protected]>

* chore: reduce spacing between filter and scaler cards

Signed-off-by: thisisobate <[email protected]>

* chore: improve filter logic to use new model

Signed-off-by: thisisobate <[email protected]>

* chore: reorder filter options

Signed-off-by: thisisobate <[email protected]>

* chore: nit fix

Signed-off-by: thisisobate <[email protected]>

---------

Signed-off-by: thisisobate <[email protected]>
Co-authored-by: Tom Kerkhove <[email protected]>
Signed-off-by: Ranjith Gopal <[email protected]>
  • Loading branch information
2 people authored and Ranjith Gopal committed Jun 27, 2024
1 parent d7e6f24 commit 7d51c74
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 180 deletions.
28 changes: 28 additions & 0 deletions assets/sass/style.sass
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,31 @@ hr
@media screen and (min-width: 769px)
.md-height-desktop
height: 9rem

.filter-icon
display: none

.filter-options
display: inline-block

.filter-pane
padding-left: 0
padding-top: 20px

@media screen and (max-width: 769px)
.filter-icon
padding: 0.5rem
cursor: pointer
border: 1px solid #DBDBDB
font-size: 18px
border-radius: 0.4rem
display: inline-block
&:hover
border: 1px solid #000000

.filter-options
display: none

.filter-pane
padding-left: 20px
padding-top: 10px
4 changes: 2 additions & 2 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ notAlternative = true

# parameters for lunr search
[params.lunr]
vars = ["title", "maintainer", "description", "availability"]
params = ["availability", "maintainer"]
vars = ["title", "maintainer", "description", "availability", "category", "type"]
params = ["availability", "maintainer", "category", "type"]

# "Highlighted Samples" section on the main page
[[params.samples]]
Expand Down
4 changes: 2 additions & 2 deletions layouts/_default/list.lunr.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{- $index := slice -}}
{{- range $scalers := where site.RegularPages ".CurrentSection.Title" "Scalers" -}}
{{- $index = $index | append (dict "title" $scalers.Title "version" (index (first 3 (split (delimit (split $scalers.RelPermalink "/") "," "") ",")) 2) "href" $scalers.RelPermalink "availability" $scalers.Params.availability "description" ($scalers.Description | markdownify) "maintainer" $scalers.Params.maintainer ) -}}
{{- $index = $index | append (dict "title" $scalers.Title "version" (index (first 3 (split (delimit (split $scalers.RelPermalink "/") "," "") ",")) 2) "href" $scalers.RelPermalink "availability" $scalers.Params.availability "description" ($scalers.Description | markdownify) "maintainer" $scalers.Params.maintainer "category" $scalers.Params.category "type" "built-in" ) -}}
{{- end -}}

{{- $index | jsonify -}}
{{- $index | jsonify -}}
234 changes: 92 additions & 142 deletions layouts/partials/javascript.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,36 +50,7 @@
});
</script>

{{/* Scalers filter */}}
<script type="text/javascript">
const builtInScalers = document.querySelectorAll("#built-in-scalers");
const externalScalers = document.getElementById("external-scalers");
const btnFocusOnMount = document.getElementById("btn-focus-on-mount");
const builtInSearchResultCount = document.querySelector(".results");
const externalSearchResultCount = document.querySelector(".external-results");
let btns = document.getElementsByClassName("filterBtn");

for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function () {
let filterValue = btns[i].value.toLowerCase();
if (filterValue === "built-in-scalers") {
builtInScalers.forEach((node) => (node.style.display = "flex"));
externalScalers.style.display = "none";
builtInSearchResultCount.style.display = "block";
externalSearchResultCount.style.display = "none";
} else if (filterValue === "external-scalers") {
// remove focus when changed
btnFocusOnMount.classList.remove("is-focused");
builtInScalers.forEach((node) => (node.style.display = "none"));
externalScalers.style.display = "inline";
builtInSearchResultCount.style.display = "none";
externalSearchResultCount.style.display = "block";
}
});
}
</script>

{{/* In-built Scalers Search */}}
{{/* Scaler Search and filter */}}
<script src="https://unpkg.com/lunr/lunr.js"></script>
<script>
window.addEventListener(
Expand All @@ -94,144 +65,115 @@
const form = document.getElementById("search");
const input = document.getElementById("search-input");
const target = document.querySelector(".is-search-result");
const externalTarget = document.querySelector(
".is-external-search-result"
);
const filterIcon = document.querySelector(".filter-icon");
const filterOptions = document.querySelector(".filter-options");
const searchResultCount = document.querySelector(".results");
const externalSearchResultCount =
document.querySelector(".external-results");
const template = document.getElementById("is-search-template");
const isExternalScalers = document.getElementById("external-scalers");
const isBuiltInScalers = document.getElementById("built-in-scalers");
const externalBanner = document.getElementById("external-banner");
const groups = document.getElementsByClassName(
"artifacthub-widget-group"
);
const interval = 500;
let query = input.value.trim();
let parse = {};
let searchQueue = [];
let checkboxes = document.querySelectorAll(
'input[name="resource_filter"]'
);

// fetch all scalers on inital load
if (!query) {
initSearchIndex();
externalScalersIndex();
}

// logic for input search
input.addEventListener(
"input",
function (event) {
event.preventDefault();
clearTimeout(debounceTimer);
const keywords = input.value.trim();

// disable all buttons during search by default
const filterBtns = document.querySelectorAll(".filterBtn");
filterBtns.forEach((btn) => (btn.disabled = true));

if (!keywords) {
// enable all buttons when input search is empty
const filterBtns = document.querySelectorAll(".filterBtn");
filterBtns.forEach((btn) => (btn.disabled = false));
}

query = keywords;
if (isExternalScalers.style.display === "inline") {
// hide banner during scaler search
externalBanner.style.display = "none";
if (query === "") {
externalBanner.style.display = "block";
}
let externalSearchUrl = new URL(
"https://artifacthub.io/api/v1/packages/search"
);
externalSearchUrl.search = new URLSearchParams({
kind: "8",
sort: "relevance",
ts_query_web: query !== "" ? query : "",
});
debounceTimer = setTimeout(() => {
groups[0].dataset.url = externalSearchUrl;
externalScalersIndex();
}, interval);

// clear out all the scaler item card when external scalers are being searched
while (externalTarget.firstChild.nextSibling) {
externalTarget.removeChild(
externalTarget.firstChild.nextSibling.nextSibling
.nextElementSibling
);
}
return;
}

debounceTimer = setTimeout(initSearchIndex, interval);

// clear out all the scaler item card when in-built scalers are being searched
// clear out all the scaler item card during search
while (target.firstChild.nextSibling) {
target.removeChild(template.nextSibling.nextElementSibling);
}
},
false
);

async function externalScalersIndex() {
const externalScalerUrl = groups[0].dataset.url;
const results = await fetch(externalScalerUrl)
.then((response) => response.json())
.then((data) => {
return data.packages;
})
.catch((err) => console.error("error:", err));

if ("content" in template) {
// show result count
const title = document.createElement("h3");
title.id = "external-search-results";
title.className = "subtitle is-size-3 external-search-results";
// logic for category filter
checkboxes.forEach((checkbox) => {
checkbox.addEventListener("change", function (event) {
if (checkbox.checked) {
const inputValue = event.target.value.split(" ");
// for single queries with spacing, use the first word
const inputQuery = inputValue[0];
searchQueue.push(inputQuery);
query = searchQueue.join(" ");
initSearchIndex();
}

if (!checkbox.checked){
const inputValue = event.target.value.split(" ");
// for single queries with spacing, use the first word
const inputQuery = inputValue[0];
searchQueue = searchQueue.filter(
(word) => word != inputQuery
);
query = searchQueue.join(" ");
initSearchIndex();
}

if (results.length == 0)
title.textContent = `No results found for "${query}"`;
else if (results.length == 1)
title.textContent = `Found one result for "${query}"`;
else if (results.length > 1 && query === "")
title.textContent = `${results.length} scalers available`;
else
title.textContent = `Found ${results.length} results for "${query}"`;
externalSearchResultCount.replaceChildren(title);
// clear out all the scaler item card during search
while (target.firstChild.nextSibling) {
target.removeChild(template.nextSibling.nextElementSibling);
}
});
});

// show the matched result
results.forEach(function (result) {
const element = template.content.cloneNode(true);
element.querySelector(".scaler-title").textContent =
result.display_name;
element
.querySelector(".scaler-title")
.setAttribute("href", "https://artifacthub.io/packages/keda-scaler/" + result.repository.name + "/" + result.normalized_name);
result.description &&
(element.querySelector(".description").textContent =
result.description);
result.repository.organization_name &&
(element.querySelector(".maintainer").textContent =
result.repository.organization_name);
result.repository.user_alias &&
(element.querySelector(".maintainer").textContent =
result.repository.user_alias);
result.version &&
(element.querySelector(
".availability"
).textContent = `v${result.version}`);
externalTarget.appendChild(element);
}, this);
// show filter options on mobile
filterIcon.addEventListener("click", function () {
if (filterOptions.style.display === "") {
filterOptions.style.display = "none";
}

if (filterOptions.style.display === "none") {
filterOptions.style.display = "flex";
}else {
filterOptions.style.display = "none";
}
}
});

async function initSearchIndex() {
const scalers = await fetch("/index.json", { method: "GET" })
const builtInScalers = await fetch("/index.json", { method: "GET" })
.then((response) => response.json())
.then((data) => {
return data;
})
.catch((err) => console.error("error:", err));

const externalScalerUrl = "https://artifacthub.io/api/v1/packages/search?offset=0&limit=20&facets=false&kind=8&deprecated=false&sort=relevance";
const externalScalersData = await fetch(externalScalerUrl)
.then((response) => response.json())
.then((data) => {
return data.packages;
})
.catch((err) => console.error("error:", err));

const externalScalers = externalScalersData.map(scaler => ({
type: 'external',
availability: `v${scaler.version}+`,
title: scaler.display_name,
maintainer: scaler.repository.organization_name ?? scaler.repository.user_alias,
href: "https://artifacthub.io/packages/keda-scaler/" + scaler.repository.name + "/" + scaler.normalized_name,
version: currentVersion,
description: scaler.description,
category: null,
}));

const scalers = [...builtInScalers, ...externalScalers];

index = lunr(function () {
const documents = scalers;

Expand All @@ -254,6 +196,12 @@
this.field("availability", {
boost: 5,
});
this.field("category", {
boost: 10,
});
this.field("type", {
boost: 20,
});

documents.forEach(function (doc) {
if (doc.version === currentVersion) {
Expand All @@ -264,6 +212,8 @@
maintainer: doc.maintainer,
description: doc.description,
availability: doc.availability,
category: doc.category,
type: doc.type,
};
}
}, this);
Expand Down Expand Up @@ -308,19 +258,19 @@
results.forEach(function (result) {
const doc = parse[result.ref];
const element = template.content.cloneNode(true);
element.querySelector(".scaler-title").textContent = doc.title;
element
.querySelector(".scaler-title")
.setAttribute("href", doc.href);
doc.description &&
(element.querySelector(".description").textContent =
doc.description);
doc.maintainer &&
(element.querySelector(".maintainer").textContent =
doc.maintainer);
doc.availability &&
(element.querySelector(".availability").textContent =
doc.availability);
element.querySelector(".scaler-title").textContent = doc.title;
element
.querySelector(".scaler-title")
.setAttribute("href", doc.href);
doc.description &&
(element.querySelector(".description").textContent =
doc.description);
doc.maintainer &&
(element.querySelector(".maintainer").textContent =
doc.maintainer);
doc.availability &&
(element.querySelector(".availability").textContent =
doc.availability);
target.appendChild(element);
}, this);
}
Expand Down
Loading

0 comments on commit 7d51c74

Please sign in to comment.