This commit is contained in:
Shumit Taher 2025-11-08 21:26:26 +00:00 committed by GitHub
commit 95e59cdcc1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 69 additions and 15 deletions

View file

@ -294,6 +294,7 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)**
**`timeout`** | `number` | _Optional_ | Request timeout in milliseconds, defaults to ½ a second (`500`)
**`ignoreErrors`** | `boolean` | _Optional_ | Prevent an error message being displayed, if a network request or something else fails. Useful for false-positives
**`label`** | `string` | _Optional_ | Add custom label to a given widget. Useful for identification, if there are multiple of the same type of widget in a single section
**`category`** | string | _Optional_ | Free-text category for this widget (e.g., Monitoring, CI/CD). Used by category filtering/search. Up to the user whatever category they want to set for a widget.
**[⬆️ Back to Top](#configuring)**
@ -317,6 +318,7 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)**
**`hideForGuests`** | `boolean` | _Optional_ | Current section will be visible for logged in users, but not for guests (see `appConfig.enableGuestAccess`). Defaults to `false`
**`hideForKeycloakUsers`** | `object` | _Optional_ | Current section will be visible to all keycloak users, except for those configured via these groups and roles. See `hideForKeycloakUsers`
**`showForKeycloakUsers`** | `object` | _Optional_ | Current section will be hidden from all keycloak users, except for those configured via these groups and roles. See `showForKeycloakUsers`
**`widgetCategories`** | string[] | _Optional_ | Free-text tags for this section, used for category filtering/search of widgets `section.widgets` from within the UI. Editable in the Edit Section modal. Example: ["DevOps", "Monitoring"]. This will work only if corrosponding widget category is setup in the widgets 'category' field.
**[⬆️ Back to Top](#configuring)**

View file

@ -69,6 +69,7 @@ export default {
cols: displayDataSchema.cols,
collapsed: displayDataSchema.collapsed,
hideForGuests: displayDataSchema.hideForGuests,
widgetCategories: displayDataSchema.widgetCategories,
},
},
},

View file

@ -103,7 +103,11 @@ const HomeMixin = {
return [];
}
const visibleTiles = allTiles.filter((tile) => checkItemVisibility(tile));
return searchTiles(visibleTiles, this.searchValue);
return searchTiles(visibleTiles, this.searchValue, this.areWidgets(allTiles));
},
/* Checks if titles are widgets */
areWidgets(allTiles) {
return Array.isArray(allTiles) && allTiles.length > 0 && !('title' in allTiles[0]);
},
/* Checks if any sections or items use icons from a given CDN */
checkIfIconLibraryNeeded(prefix) {

View file

@ -825,6 +825,16 @@
"default": 1,
"description": "The amount of space that the section spans horizontally"
},
"widgetCategories": {
"type": "array",
"title": "Widget Categories",
"description": "Tags for this section (add/remove text tags).",
"items": {
"type": "string"
},
"uniqueItems": false,
"default": []
},
"sectionLayout": {
"title": "Layout Type",
"type": "string",
@ -1170,6 +1180,11 @@
"title": "Widget Options",
"type": "object",
"description": "Configuration options for widget. Varies depending on widget type, see docs for all options"
},
"category": {
"title": "Category",
"type": "string",
"description": "Single category tag."
}
}
}

View file

@ -35,22 +35,31 @@ const filterHelper = (compareStr, searchStr) => {
* @param {array} allTiles An array of tiles
* @param {string} searchTerm The users search term
* @returns A filtered array of tiles
* if widgets are sent as allTiles, then the search is done based on options.category
*/
export const searchTiles = (allTiles, searchTerm) => {
export const searchTiles = (allTiles, searchTerm, isWidgets) => {
if (!searchTerm) return allTiles; // If no search term, then return all
if (!allTiles) return []; // If no data, then skip
return allTiles.filter((tile) => {
const {
title, description, provider, url, tags,
} = tile;
return filterHelper(title, searchTerm)
|| filterHelper(provider, searchTerm)
|| filterHelper(description, searchTerm)
|| filterHelper(tags, searchTerm)
|| filterHelper(getDomainFromUrl(url), searchTerm);
});
if (!isWidgets) {
return allTiles.filter((tile) => {
const {
title, description, provider, url, tags,
} = tile;
return filterHelper(title, searchTerm)
|| filterHelper(provider, searchTerm)
|| filterHelper(description, searchTerm)
|| filterHelper(tags, searchTerm)
|| filterHelper(getDomainFromUrl(url), searchTerm);
});
} else {
return allTiles.filter((tile) => {
const {
category,
} = tile;
return filterHelper(category, searchTerm);
});
}
};
/* From a list of search bangs, return the URL associated with it */
export const getSearchEngineFromBang = (searchQuery, bangList) => {
const bangNames = Object.keys(bangList);

View file

@ -29,13 +29,15 @@
:displayData="getDisplayData(section)"
:groupId="makeSectionId(section)"
:items="section.filteredItems"
:widgets="section.widgets"
:widgets="section.filteredWidgets"
:searchTerm="searchValue"
:itemSize="itemSizeBound"
@itemClicked="finishedSearching()"
@change-modal-visibility="updateModalVisibility"
:isWide="!!singleSectionView || layoutOrientation === 'horizontal'"
:class="(searchValue && section.filteredItems.length === 0) ? 'no-results' : ''"
:class="(searchValue &&
(section.filteredItems.length === 0 &&
section.filteredWidgets.length === 0)) ? 'no-results' : ''"
/>
</template>
<!-- Show add new section button, in edit mode -->
@ -102,6 +104,15 @@ export default {
return sections.map((_section) => {
const section = _section;
section.filteredItems = this.filterTiles(section.items, this.searchValue);
const searchedWidgets = this.filterTiles(section.widgets, this.searchValue);
const widgetCategoriesArray = this.normalizeWidgetCats(
this.getDisplayData(section).widgetCategories,
);
section.filteredWidgets = this.filterWidgetsByCategories(
searchedWidgets, widgetCategoriesArray,
);
return section;
});
},
@ -123,6 +134,18 @@ export default {
},
},
methods: {
/* returns only widgets that have category that are present in
widgetCategories array in section config displayData */
filterWidgetsByCategories(widgets, cats) {
if (!cats.length) return widgets || [];
return (widgets || []).filter(w => (typeof w.category === 'string'
&& cats.includes(w.category.toLowerCase().trim())));
},
/* Normalization of widget categories text inputs by user */
normalizeWidgetCats(cats) {
if (!Array.isArray(cats)) return [];
return cats.map(c => String(c).toLowerCase().trim()).filter(Boolean);
},
/* Clears input field, once a searched item is opened */
finishedSearching() {
if (this.$refs.filterComp) this.$refs.filterComp.clearFilterInput();