mirror of
https://github.com/Lissy93/dashy.git
synced 2025-12-20 15:35:07 +01:00
Merge c6a2dbd21b into 996de036e8
This commit is contained in:
commit
95e59cdcc1
6 changed files with 69 additions and 15 deletions
|
|
@ -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)**
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ export default {
|
|||
cols: displayDataSchema.cols,
|
||||
collapsed: displayDataSchema.collapsed,
|
||||
hideForGuests: displayDataSchema.hideForGuests,
|
||||
widgetCategories: displayDataSchema.widgetCategories,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in a new issue