From 18776bd8cb5680560bceba18309d0c5c04d59268 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Wed, 1 Jun 2022 20:33:02 +0200 Subject: [PATCH 01/13] Add CheckItemVisibility util templated from CheckSectionVisibility --- src/utils/CheckItemVisibility.js | 84 ++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/utils/CheckItemVisibility.js diff --git a/src/utils/CheckItemVisibility.js b/src/utils/CheckItemVisibility.js new file mode 100644 index 0000000000..4a1c0be30e --- /dev/null +++ b/src/utils/CheckItemVisibility.js @@ -0,0 +1,84 @@ +/** + * A helper function that checks if an item is visible based on current users permissions + * Checks an item displayData for hideForUsers, showForUsers and hideForGuests + * Returns a boolean that determines if the user has the required permissions + */ + +// Import helper functions from auth, to get current user, and check if guest +import { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth'; +import { localStorageKeys } from '@/utils/defaults'; + +/* Helper function, checks if a given testValue is found in the visibility list */ +const determineVisibility = (visibilityList, testValue) => { + let isFound = false; + visibilityList.forEach((visibilityItem) => { + if (visibilityItem.toLowerCase() === testValue.toLowerCase()) isFound = true; + }); + return isFound; +}; + +/* Helper function, determines if two arrays have any intersecting elements + (one or more items that are the same) */ +const determineIntersection = (source = [], target = []) => { + const intersections = source.filter(item => target.indexOf(item) !== -1); + return intersections.length > 0; +}; + +/* Returns false if this item should not be rendered for the current user/ guest */ +const isItemVisibleToUser = (displayData, currentUser, isGuest) => { + // Checks if user explicitly has access to a certain item + const checkVisibility = () => { + if (!currentUser) return true; + const hideForUsers = displayData.hideForUsers || []; + const cUsername = currentUser.user.toLowerCase(); + return !determineVisibility(hideForUsers, cUsername); + }; + // Checks if user is explicitly prevented from viewing a certain item + const checkHiddenability = () => { + if (!currentUser) return true; + const cUsername = currentUser.user.toLowerCase(); + const showForUsers = displayData.showForUsers || []; + if (showForUsers.length < 1) return true; + return determineVisibility(showForUsers, cUsername); + }; + const checkKeycloakVisibility = () => { + if (!displayData.hideForKeycloakUsers) return true; + + const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); + const hideForGroups = displayData.hideForKeycloakUsers.groups || []; + const hideForRoles = displayData.hideForKeycloakUsers.roles || []; + + return !(determineIntersection(hideForRoles, roles) + || determineIntersection(hideForGroups, groups)); + }; + const checkKeycloakHiddenability = () => { + if (!displayData.showForKeycloakUsers) return true; + + const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); + const showForGroups = displayData.showForKeycloakUsers.groups || []; + const showForRoles = displayData.showForKeycloakUsers.roles || []; + + return determineIntersection(showForRoles, roles) + || determineIntersection(showForGroups, groups); + }; + // Checks if the current user is a guest, and if item allows for guests + const checkIfHideForGuest = () => { + const hideForGuest = displayData.hideForGuests; + return !(hideForGuest && isGuest); + }; + return checkVisibility() + && checkHiddenability() + && checkIfHideForGuest() + && checkKeycloakVisibility() + && checkKeycloakHiddenability(); +}; + +/* Putting it all together, the function to export */ +const checkItemVisibility = (item) => { + const currentUser = getCurrentUser(); // Get current user object + const isGuest = isLoggedInAsGuest(); // Check if current user is a guest + const displayData = item.displayData || {}; + return isItemVisibleToUser(displayData, currentUser, isGuest); +}; + +export default checkItemVisibility; From 04774c23ed301600b48eea5519e8e67b8635fbb2 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Wed, 1 Jun 2022 20:50:33 +0200 Subject: [PATCH 02/13] Add displayData on items --- src/utils/ConfigSchema.json | 171 ++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/src/utils/ConfigSchema.json b/src/utils/ConfigSchema.json index dd3eb1e88e..e1d72b7e2c 100644 --- a/src/utils/ConfigSchema.json +++ b/src/utils/ConfigSchema.json @@ -778,6 +778,177 @@ "type": "string", "description": "The destination to navigate to when item is clicked, expressed as a valid URL, IP or hostname" }, + "displayData": { + "title": "Display Data", + "type": "object", + "additionalProperties": false, + "description": "Optional meta data for customizing a section", + "properties": { + "sortBy": { + "title": "Sort By", + "type": "string", + "enum": [ + "default", + "most-used", + "last-used", + "alphabetical", + "reverse-alphabetical", + "random" + ], + "default": "default", + "description": "How to sort items within the section. By default items are displayed in the order in which they are listed in within the config" + }, + "collapsed": { + "title": "Is Collapsed?", + "type": "boolean", + "default": false, + "description": "If true, section needs to be clicked to open" + }, + "cutToHeight": { + "title": "Cut to Height", + "type": "boolean", + "default": false, + "description": "By default, sections will fill available space. Set this option to true to match section height with content height" + }, + "color": { + "title": "Color", + "type": "string", + "description": "Hex code, or HTML color for section fill" + }, + "customStyles": { + "title": "Custom Styles", + "type": "string", + "description": "CSS overides for section container" + }, + "itemSize": { + "title": "Item Size", + "type": "string", + "enum": [ + "small", + "medium", + "large" + ], + "default": "medium", + "description": "Size of items within the section" + }, + "rows": { + "title": "Num Rows", + "type": "number", + "minimum": 1, + "maximum": 5, + "default": 1, + "description": "The amount of space that the section spans vertically" + }, + "cols": { + "title": "Num Cols", + "type": "number", + "minimum": 1, + "maximum": 5, + "default": 1, + "description": "The amount of space that the section spans horizontally" + }, + "sectionLayout": { + "title": "Layout Type", + "type": "string", + "enum": [ + "grid", + "auto" + ], + "default": "auto", + "description": "If set to grid, items have uniform width, and itemCount can be set" + }, + "itemCountX": { + "title": "Item Count X", + "type": "number", + "minimum": 1, + "maximum": 12, + "description": "Number of items per column" + }, + "itemCountY": { + "title": "Item Count Y", + "type": "number", + "minimum": 1, + "maximum": 12, + "description": "Number of items per row" + }, + "hideForUsers": { + "title": "Hide for Users", + "type": "array", + "description": "Section will be visible to all users, except for those specified in this list", + "items": { + "type": "string", + "description": "Username for the user that will not be able to view this section" + } + }, + "showForUsers": { + "title": "Show for Users", + "type": "array", + "description": "Section will be hidden from all users, except for those specified in this list", + "items": { + "type": "string", + "description": "Username for the user that will have access to this section" + } + }, + "hideForGuests": { + "title": "Hide for Guests?", + "type": "boolean", + "default": false, + "description": "If set to true, section will be visible for logged in users, but not for guests" + }, + "showForKeycloakUsers": { + "title": "Show for select Keycloak groups or roles", + "type": "object", + "description": "Configure the Keycloak groups or roles that will have access to this section", + "additionalProperties": false, + "properties": { + "groups": { + "title": "Show for Groups", + "type": "array", + "description": "Section will be hidden from all users except those with one or more of these groups", + "items": { + "type": "string", + "description": "Name of the group that will be able to view this section" + } + }, + "roles": { + "title": "Show for Roles", + "type": "array", + "description": "Section will be hidden from all users except those with one or more of these roles", + "items": { + "type": "string", + "description": "Name of the role that will be able to view this section" + } + } + } + }, + "hideForKeycloakUsers": { + "title": "Hide for select Keycloak groups or roles", + "type": "object", + "description": "Configure the Keycloak groups or roles that will not have access to this section", + "additionalProperties": false, + "properties": { + "groups": { + "title": "Hide for Groups", + "type": "array", + "description": "Section will be hidden from users with any of these groups", + "items": { + "type": "string", + "description": "name of the group that will not be able to view this section" + } + }, + "roles": { + "title": "Hide for Roles", + "type": "array", + "description": "Section will be hidden from users with any of roles", + "items": { + "type": "string", + "description": "name of the role that will not be able to view this section" + } + } + } + } + } + }, "target": { "title": "Opening Method", "type": "string", From c33e03f4f5079bbee5b713fceb17a5878016b0b5 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Wed, 1 Jun 2022 21:13:00 +0200 Subject: [PATCH 03/13] Use item visibility to filterTiles --- src/mixins/HomeMixin.js | 8 ++++++-- src/utils/CheckItemVisibility.js | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/mixins/HomeMixin.js b/src/mixins/HomeMixin.js index 545f363185..9e1e6e0a8f 100644 --- a/src/mixins/HomeMixin.js +++ b/src/mixins/HomeMixin.js @@ -5,6 +5,7 @@ import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults'; import Keys from '@/utils/StoreMutations'; import { searchTiles } from '@/utils/Search'; +import { checkItemVisibility } from '@/utils/CheckItemVisibility'; const HomeMixin = { props: { @@ -64,8 +65,11 @@ const HomeMixin = { }, /* Returns only the tiles that match the users search query */ filterTiles(allTiles) { - if (!allTiles) return []; - return searchTiles(allTiles, this.searchValue); + if (!allTiles) { + return []; + } + const visibleTiles = allTiles.filter((tile) => checkItemVisibility(tile)); + return searchTiles(visibleTiles, this.searchValue); }, /* Checks if any sections or items use icons from a given CDN */ checkIfIconLibraryNeeded(prefix) { diff --git a/src/utils/CheckItemVisibility.js b/src/utils/CheckItemVisibility.js index 4a1c0be30e..a69a521de3 100644 --- a/src/utils/CheckItemVisibility.js +++ b/src/utils/CheckItemVisibility.js @@ -74,7 +74,7 @@ const isItemVisibleToUser = (displayData, currentUser, isGuest) => { }; /* Putting it all together, the function to export */ -const checkItemVisibility = (item) => { +export const checkItemVisibility = (item) => { const currentUser = getCurrentUser(); // Get current user object const isGuest = isLoggedInAsGuest(); // Check if current user is a guest const displayData = item.displayData || {}; From cd72ff06ec39b7e46299bf3ef4dcf22262a1a96f Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Wed, 1 Jun 2022 21:24:10 +0200 Subject: [PATCH 04/13] Add visible section items --- src/components/Workspace/SideBar.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/Workspace/SideBar.vue b/src/components/Workspace/SideBar.vue index 06443c0a8a..b8604c4976 100644 --- a/src/components/Workspace/SideBar.vue +++ b/src/components/Workspace/SideBar.vue @@ -13,7 +13,7 @@ @@ -36,6 +36,7 @@ import SideBarItem from '@/components/Workspace/SideBarItem.vue'; import SideBarSection from '@/components/Workspace/SideBarSection.vue'; import IconHome from '@/assets/interface-icons/application-home.svg'; import IconMinimalView from '@/assets/interface-icons/application-minimal.svg'; +import { checkItemVisibility } from '@/utils/CheckItemVisibility'; export default { name: 'SideBar', @@ -77,6 +78,12 @@ export default { }); }); }, + filterTiles(allTiles) { + if (!allTiles) { + return []; + } + return allTiles.filter((tile) => checkItemVisibility(tile)); + }, }, mounted() { if (this.sections.length === 1) { // If only 1 section, go ahead and open it From 3bc80cfaadc3c977d5ac32b53c911fefcaed2494 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Wed, 1 Jun 2022 21:25:28 +0200 Subject: [PATCH 05/13] Add comment --- src/components/Workspace/SideBar.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Workspace/SideBar.vue b/src/components/Workspace/SideBar.vue index b8604c4976..2cb7ca1f3a 100644 --- a/src/components/Workspace/SideBar.vue +++ b/src/components/Workspace/SideBar.vue @@ -78,6 +78,7 @@ export default { }); }); }, + /* Return a list with visible items on a section to the user or guest */ filterTiles(allTiles) { if (!allTiles) { return []; From d1706689a5dcece7808753c61c34281da0a2b972 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Wed, 1 Jun 2022 22:46:53 +0200 Subject: [PATCH 06/13] Fix: remove duplicate code --- src/utils/CheckItemVisibility.js | 69 +------------------------- src/utils/CheckSectionVisibility.js | 71 ++------------------------- src/utils/IsVisibleToUser.js | 76 +++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 135 deletions(-) create mode 100644 src/utils/IsVisibleToUser.js diff --git a/src/utils/CheckItemVisibility.js b/src/utils/CheckItemVisibility.js index a69a521de3..ff2206e832 100644 --- a/src/utils/CheckItemVisibility.js +++ b/src/utils/CheckItemVisibility.js @@ -6,79 +6,14 @@ // Import helper functions from auth, to get current user, and check if guest import { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth'; -import { localStorageKeys } from '@/utils/defaults'; - -/* Helper function, checks if a given testValue is found in the visibility list */ -const determineVisibility = (visibilityList, testValue) => { - let isFound = false; - visibilityList.forEach((visibilityItem) => { - if (visibilityItem.toLowerCase() === testValue.toLowerCase()) isFound = true; - }); - return isFound; -}; - -/* Helper function, determines if two arrays have any intersecting elements - (one or more items that are the same) */ -const determineIntersection = (source = [], target = []) => { - const intersections = source.filter(item => target.indexOf(item) !== -1); - return intersections.length > 0; -}; - -/* Returns false if this item should not be rendered for the current user/ guest */ -const isItemVisibleToUser = (displayData, currentUser, isGuest) => { - // Checks if user explicitly has access to a certain item - const checkVisibility = () => { - if (!currentUser) return true; - const hideForUsers = displayData.hideForUsers || []; - const cUsername = currentUser.user.toLowerCase(); - return !determineVisibility(hideForUsers, cUsername); - }; - // Checks if user is explicitly prevented from viewing a certain item - const checkHiddenability = () => { - if (!currentUser) return true; - const cUsername = currentUser.user.toLowerCase(); - const showForUsers = displayData.showForUsers || []; - if (showForUsers.length < 1) return true; - return determineVisibility(showForUsers, cUsername); - }; - const checkKeycloakVisibility = () => { - if (!displayData.hideForKeycloakUsers) return true; - - const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); - const hideForGroups = displayData.hideForKeycloakUsers.groups || []; - const hideForRoles = displayData.hideForKeycloakUsers.roles || []; - - return !(determineIntersection(hideForRoles, roles) - || determineIntersection(hideForGroups, groups)); - }; - const checkKeycloakHiddenability = () => { - if (!displayData.showForKeycloakUsers) return true; - - const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); - const showForGroups = displayData.showForKeycloakUsers.groups || []; - const showForRoles = displayData.showForKeycloakUsers.roles || []; - - return determineIntersection(showForRoles, roles) - || determineIntersection(showForGroups, groups); - }; - // Checks if the current user is a guest, and if item allows for guests - const checkIfHideForGuest = () => { - const hideForGuest = displayData.hideForGuests; - return !(hideForGuest && isGuest); - }; - return checkVisibility() - && checkHiddenability() - && checkIfHideForGuest() - && checkKeycloakVisibility() - && checkKeycloakHiddenability(); -}; +import { isVisibleToUser } from '@/utils/IsVisibleToUser'; /* Putting it all together, the function to export */ export const checkItemVisibility = (item) => { const currentUser = getCurrentUser(); // Get current user object const isGuest = isLoggedInAsGuest(); // Check if current user is a guest const displayData = item.displayData || {}; - return isItemVisibleToUser(displayData, currentUser, isGuest); + return isVisibleToUser(displayData, currentUser, isGuest); }; export default checkItemVisibility; diff --git a/src/utils/CheckSectionVisibility.js b/src/utils/CheckSectionVisibility.js index 555fadcd76..c549dea197 100644 --- a/src/utils/CheckSectionVisibility.js +++ b/src/utils/CheckSectionVisibility.js @@ -6,80 +6,15 @@ // Import helper functions from auth, to get current user, and check if guest import { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth'; -import { localStorageKeys } from '@/utils/defaults'; - -/* Helper function, checks if a given testValue is found in the visibility list */ -const determineVisibility = (visibilityList, testValue) => { - let isFound = false; - visibilityList.forEach((visibilityItem) => { - if (visibilityItem.toLowerCase() === testValue.toLowerCase()) isFound = true; - }); - return isFound; -}; - -/* Helper function, determines if two arrays have any intersecting elements - (one or more items that are the same) */ -const determineIntersection = (source = [], target = []) => { - const intersections = source.filter(item => target.indexOf(item) !== -1); - return intersections.length > 0; -}; - -/* Returns false if this section should not be rendered for the current user/ guest */ -const isSectionVisibleToUser = (displayData, currentUser, isGuest) => { - // Checks if user explicitly has access to a certain section - const checkVisibility = () => { - if (!currentUser) return true; - const hideForUsers = displayData.hideForUsers || []; - const cUsername = currentUser.user.toLowerCase(); - return !determineVisibility(hideForUsers, cUsername); - }; - // Checks if user is explicitly prevented from viewing a certain section - const checkHiddenability = () => { - if (!currentUser) return true; - const cUsername = currentUser.user.toLowerCase(); - const showForUsers = displayData.showForUsers || []; - if (showForUsers.length < 1) return true; - return determineVisibility(showForUsers, cUsername); - }; - const checkKeycloakVisibility = () => { - if (!displayData.hideForKeycloakUsers) return true; - - const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); - const hideForGroups = displayData.hideForKeycloakUsers.groups || []; - const hideForRoles = displayData.hideForKeycloakUsers.roles || []; - - return !(determineIntersection(hideForRoles, roles) - || determineIntersection(hideForGroups, groups)); - }; - const checkKeycloakHiddenability = () => { - if (!displayData.showForKeycloakUsers) return true; - - const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); - const showForGroups = displayData.showForKeycloakUsers.groups || []; - const showForRoles = displayData.showForKeycloakUsers.roles || []; - - return determineIntersection(showForRoles, roles) - || determineIntersection(showForGroups, groups); - }; - // Checks if the current user is a guest, and if section allows for guests - const checkIfHideForGuest = () => { - const hideForGuest = displayData.hideForGuests; - return !(hideForGuest && isGuest); - }; - return checkVisibility() - && checkHiddenability() - && checkIfHideForGuest() - && checkKeycloakVisibility() - && checkKeycloakHiddenability(); -}; +import { isVisibleToUser } from '@/utils/IsVisibleToUser'; /* Putting it all together, the function to export */ -const checkSectionVisibility = (sections) => { +export const checkSectionVisibility = (sections) => { const currentUser = getCurrentUser(); // Get current user object const isGuest = isLoggedInAsGuest(); // Check if current user is a guest return sections.filter((currentSection) => { const displayData = currentSection.displayData || {}; - return isSectionVisibleToUser(displayData, currentUser, isGuest); + return isVisibleToUser(displayData, currentUser, isGuest); }); }; diff --git a/src/utils/IsVisibleToUser.js b/src/utils/IsVisibleToUser.js new file mode 100644 index 0000000000..ea8343cf3a --- /dev/null +++ b/src/utils/IsVisibleToUser.js @@ -0,0 +1,76 @@ +/** + * A helper function that filters all the sections or an item based on current users permissions + * Checks each sections displayData for hideForUsers, showForUsers and hideForGuests + * Returns an array of sections that the current logged in user has permissions for + */ + +// Import helper functions from auth, to get current user, and check if guest +import { localStorageKeys } from '@/utils/defaults'; + +/* Helper function, checks if a given testValue is found in the visibility list */ +const determineVisibility = (visibilityList, testValue) => { + let isFound = false; + visibilityList.forEach((visibilityItem) => { + if (visibilityItem.toLowerCase() === testValue.toLowerCase()) isFound = true; + }); + return isFound; +}; + +/* Helper function, determines if two arrays have any intersecting elements + (one or more items that are the same) */ +const determineIntersection = (source = [], target = []) => { + const intersections = source.filter(item => target.indexOf(item) !== -1); + return intersections.length > 0; +}; + +/* Returns false if the displayData of a section/item + should not be rendered for the current user/ guest */ +export const isVisibleToUser = (displayData, currentUser, isGuest) => { + // Checks if user explicitly has access to a certain section + const checkVisibility = () => { + if (!currentUser) return true; + const hideForUsers = displayData.hideForUsers || []; + const cUsername = currentUser.user.toLowerCase(); + return !determineVisibility(hideForUsers, cUsername); + }; + // Checks if user is explicitly prevented from viewing a certain section/item + const checkHiddenability = () => { + if (!currentUser) return true; + const cUsername = currentUser.user.toLowerCase(); + const showForUsers = displayData.showForUsers || []; + if (showForUsers.length < 1) return true; + return determineVisibility(showForUsers, cUsername); + }; + const checkKeycloakVisibility = () => { + if (!displayData.hideForKeycloakUsers) return true; + + const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); + const hideForGroups = displayData.hideForKeycloakUsers.groups || []; + const hideForRoles = displayData.hideForKeycloakUsers.roles || []; + + return !(determineIntersection(hideForRoles, roles) + || determineIntersection(hideForGroups, groups)); + }; + const checkKeycloakHiddenability = () => { + if (!displayData.showForKeycloakUsers) return true; + + const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); + const showForGroups = displayData.showForKeycloakUsers.groups || []; + const showForRoles = displayData.showForKeycloakUsers.roles || []; + + return determineIntersection(showForRoles, roles) + || determineIntersection(showForGroups, groups); + }; + // Checks if the current user is a guest, and if section/item allows for guests + const checkIfHideForGuest = () => { + const hideForGuest = displayData.hideForGuests; + return !(hideForGuest && isGuest); + }; + return checkVisibility() + && checkHiddenability() + && checkIfHideForGuest() + && checkKeycloakVisibility() + && checkKeycloakHiddenability(); +}; + +export default isVisibleToUser; From f13d252443faace4d582360fbba319d2fa600c28 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Thu, 2 Jun 2022 08:10:42 +0200 Subject: [PATCH 07/13] Add basic documentation --- docs/authentication.md | 21 ++++++++++++++------- docs/configuring.md | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/docs/authentication.md b/docs/authentication.md index 4b8e0e67fd..5a0e267733 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -48,10 +48,10 @@ Once authentication is enabled, so long as there is no valid token in cookie sto With authentication setup, by default no access is allowed to your dashboard without first logging in with valid credentials. Guest mode can be enabled to allow for read-only access to a secured dashboard by any user, without the need to log in. A guest user cannot write any changes to the config file, but can apply modifications locally (stored in their browser). You can enable guest access, by setting `appConfig.auth.enableGuestAccess: true`. ### Granular Access -You can use the following properties to make certain sections only visible to some users, or hide sections from guests. -- `hideForUsers` - Section will be visible to all users, except for those specified in this list -- `showForUsers` - Section will be hidden from all users, except for those specified in this list -- `hideForGuests` - Section will be visible for logged in users, but not for guests +You can use the following properties to make certain sections or items only visible to some users, or hide sections and items from guests. +- `hideForUsers` - Section or Item will be visible to all users, except for those specified in this list +- `showForUsers` - Section or Item will be hidden from all users, except for those specified in this list +- `hideForGuests` - Section or Item will be visible for logged in users, but not for guests For Example: @@ -71,7 +71,9 @@ For Example: displayData: hideForGuests: true items: - ... + - title: Hide Me + displayData: + hideForUsers: [alicia, bob] ``` ### Permissions @@ -149,9 +151,9 @@ appConfig: Note that if you are using Keycloak V 17 or older, you will also need to set `legacySupport: true` (also under `appConfig.auth.keycloak`). This is because the API endpoint was updated in later versions. ### 4. Add groups and roles (Optional) -Keycloak allows you to assign users roles and groups. You can use these values to configure who can access various sections in Dashy. +Keycloak allows you to assign users roles and groups. You can use these values to configure who can access various sections or items in Dashy. Keycloak server administration and configuration is a deep topic; please refer to the [server admin guide](https://www.keycloak.org/docs/latest/server_admin/index.html#assigning-permissions-and-access-using-roles-and-groups) to see details about creating and assigning roles and groups. -Once you have groups or roles assigned to users you can configure access under each sections `displayData.showForKeycloakUser` and `displayData.hideForKeycloakUser`. +Once you have groups or roles assigned to users you can configure access under each section or item `displayData.showForKeycloakUser` and `displayData.hideForKeycloakUser`. Both show and hide configurations accept a list of `groups` and `roles` that limit access. If a users data matches one or more items in these lists they will be allowed or excluded as defined. ```yaml sections: @@ -161,6 +163,11 @@ sections: roles: ['canViewDevResources'] hideForKeycloakUsers: groups: ['ProductTeam'] + items: + - title: Not Visible for developers + displayData: + hideForKeycloakUsers: + groups: ['DevelopmentTeam'] ``` Depending on how you're hosting Dashy and Keycloak, you may also need to set some HTTP headers, to prevent a CORS error. This would typically be the `Access-Control-Allow-Origin [URL-of Dashy]` on your Keycloak instance. See the [Setting Headers](https://github.com/Lissy93/dashy/blob/master/docs/management.md#setting-headers) guide in the management docs for more info. diff --git a/docs/configuring.md b/docs/configuring.md index a2d88aaf83..f9895c5827 100644 --- a/docs/configuring.md +++ b/docs/configuring.md @@ -227,6 +227,20 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)** **[⬆️ Back to Top](#configuring)** + +### `item.displayData` _(optional)_ + +**Field** | **Type** | **Required**| **Description** +--- | --- | --- | --- +**`hideForUsers`** | `string[]` | _Optional_ | Current item will be visible to all users, except for those specified in this list +**`showForUsers`** | `string[]` | _Optional_ | Current item will be hidden from all users, except for those specified in this list +**`hideForGuests`** | `boolean` | _Optional_ | Current item will be visible for logged in users, but not for guests (see `appConfig.enableGuestAccess`). Defaults to `false` +**`hideForKeycloakUsers`** | `object` | _Optional_ | Current item will be visible to all keycloak users, except for those configured via these groups and roles. See `hideForKeycloakUsers` +**`showForKeycloakUsers`** | `object` | _Optional_ | Current item will be hidden from all keyclaok users, except for those configured via these groups and roles. See `showForKeycloakUsers` + +**[⬆️ Back to Top](#configuring)** + + ### `section.widget` _(optional)_ **Field** | **Type** | **Required**| **Description** From dfd3aabd275eca14e58f6b452503431f708a119b Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Thu, 2 Jun 2022 08:12:39 +0200 Subject: [PATCH 08/13] Fix typo on item.displayData and section.displayData for keycloak --- docs/configuring.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuring.md b/docs/configuring.md index f9895c5827..169614fef6 100644 --- a/docs/configuring.md +++ b/docs/configuring.md @@ -236,7 +236,7 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)** **`showForUsers`** | `string[]` | _Optional_ | Current item will be hidden from all users, except for those specified in this list **`hideForGuests`** | `boolean` | _Optional_ | Current item will be visible for logged in users, but not for guests (see `appConfig.enableGuestAccess`). Defaults to `false` **`hideForKeycloakUsers`** | `object` | _Optional_ | Current item will be visible to all keycloak users, except for those configured via these groups and roles. See `hideForKeycloakUsers` -**`showForKeycloakUsers`** | `object` | _Optional_ | Current item will be hidden from all keyclaok users, except for those configured via these groups and roles. See `showForKeycloakUsers` +**`showForKeycloakUsers`** | `object` | _Optional_ | Current item will be hidden from all keycloak users, except for those configured via these groups and roles. See `showForKeycloakUsers` **[⬆️ Back to Top](#configuring)** @@ -273,7 +273,7 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)** **`showForUsers`** | `string[]` | _Optional_ | Current section will be hidden from all users, except for those specified in this list **`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 keyclaok users, except for those configured via these groups and roles. See `showForKeycloakUsers` +**`showForKeycloakUsers`** | `object` | _Optional_ | Current section will be hidden from all keycloak users, except for those configured via these groups and roles. See `showForKeycloakUsers` **[⬆️ Back to Top](#configuring)** From 994435677c8530aba37956bdc9819a7ec814d3a7 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Thu, 2 Jun 2022 12:33:14 +0200 Subject: [PATCH 09/13] Expand section hideForKeycloakUsers and showForKeycloakUsers to add item --- docs/configuring.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/configuring.md b/docs/configuring.md index 169614fef6..754c76d414 100644 --- a/docs/configuring.md +++ b/docs/configuring.md @@ -36,7 +36,7 @@ The following file provides a reference of all supported configuration options. - [`keycloak`](#appconfigauthkeycloak-optional) - Auth config for Keycloak - [**`sections`**](#section) - List of sections - [`displayData`](#sectiondisplaydata-optional) - Section display settings - - [`show/hideForKeycloakUsers`](#sectiondisplaydatahideforkeycloakusers-and-sectiondisplaydatashowforkeycloakusers) - Set user controls + - [`show/hideForKeycloakUsers`](#sectiondisplaydatahideforkeycloakusers,-sectiondisplaydatashowforkeycloakusers,-itemdisplayDatahideForKeycloakUsers-and-itemdisplayDatashowForKeycloakUsers) - Set user controls - [`icon`](#sectionicon-and-sectionitemicon) - Icon for a section - [`items`](#sectionitem) - List of items - [`icon`](#sectionicon-and-sectionitemicon) - Icon for an item @@ -285,12 +285,12 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)** **[⬆️ Back to Top](#configuring)** -### `section.displayData.hideForKeycloakUsers` and `section.displayData.showForKeycloakUsers` +### `section.displayData.hideForKeycloakUsers`, `section.displayData.showForKeycloakUsers`, `item.displayData.hideForKeycloakUsers` and `item.displayData.showForKeycloakUsers` **Field** | **Type** | **Required**| **Description** --- |------------| --- | --- -**`groups`** | `string[]` | _Optional_ | Current Section will be hidden or shown based on the user having any of the groups in this list -**`roles`** | `string[]` | _Optional_ | Current Section will be hidden or shown based on the user having any of the roles in this list +**`groups`** | `string[]` | _Optional_ | Current Section or Item will be hidden or shown based on the user having any of the groups in this list +**`roles`** | `string[]` | _Optional_ | Current Section or Item will be hidden or shown based on the user having any of the roles in this list **[⬆️ Back to Top](#configuring)** From 82b2543d9c3b12443cb390f1f8dd32732d01fd3b Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Thu, 2 Jun 2022 12:42:59 +0200 Subject: [PATCH 10/13] Fix anchor link --- docs/configuring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuring.md b/docs/configuring.md index 754c76d414..835ba8f994 100644 --- a/docs/configuring.md +++ b/docs/configuring.md @@ -36,7 +36,7 @@ The following file provides a reference of all supported configuration options. - [`keycloak`](#appconfigauthkeycloak-optional) - Auth config for Keycloak - [**`sections`**](#section) - List of sections - [`displayData`](#sectiondisplaydata-optional) - Section display settings - - [`show/hideForKeycloakUsers`](#sectiondisplaydatahideforkeycloakusers,-sectiondisplaydatashowforkeycloakusers,-itemdisplayDatahideForKeycloakUsers-and-itemdisplayDatashowForKeycloakUsers) - Set user controls + - [`show/hideForKeycloakUsers`](#sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers) - Set user controls - [`icon`](#sectionicon-and-sectionitemicon) - Icon for a section - [`items`](#sectionitem) - List of items - [`icon`](#sectionicon-and-sectionitemicon) - Icon for an item From f4709195c6c9972cfbaee696519294a678cfaa29 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Thu, 2 Jun 2022 12:49:42 +0200 Subject: [PATCH 11/13] Add displayData to section.item --- docs/configuring.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/configuring.md b/docs/configuring.md index 835ba8f994..71800ad211 100644 --- a/docs/configuring.md +++ b/docs/configuring.md @@ -224,6 +224,7 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)** **`color`** | `string` | _Optional_ | An optional color for the text and font-awesome icon to be displayed in. Note that this will override the current theme and so may not display well **`backgroundColor`** | `string` | _Optional_ | An optional background fill color for the that given item. Again, this will override the current theme and so might not display well against the background **`provider`** | `string` | _Optional_ | The name of the provider for a given service, useful for when including hosted apps. In some themes, this is visible under the item name +**`displayData`** | `object` | _Optional_ | Meta-data to optionally overide display settings for a given item. See [`displayData`](#itemdisplaydata-optional) **[⬆️ Back to Top](#configuring)** From d0e25dfb523f3cc5c9f1045d1c7b5bc376ad1051 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Thu, 2 Jun 2022 12:49:46 +0200 Subject: [PATCH 12/13] Add contents urls --- docs/configuring.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/configuring.md b/docs/configuring.md index 71800ad211..18941b467e 100644 --- a/docs/configuring.md +++ b/docs/configuring.md @@ -40,6 +40,8 @@ The following file provides a reference of all supported configuration options. - [`icon`](#sectionicon-and-sectionitemicon) - Icon for a section - [`items`](#sectionitem) - List of items - [`icon`](#sectionicon-and-sectionitemicon) - Icon for an item + - [`displayData`](#itemdisplaydata-optional) - Item display settings + - [`show/hideForKeycloakUsers`](#sectiondisplaydatahideforkeycloakusers-sectiondisplaydatashowforkeycloakusers-itemdisplaydatahideforkeycloakusers-and-itemdisplaydatashowforkeycloakusers) - Set user controls - [`widgets`](#sectionwidget-optional) - List of widgets - [**Notes**](#notes) - [Editing Config through the UI](#editing-config-through-the-ui) From 8650b8cfb092efd689147daabda2134a9a261ea1 Mon Sep 17 00:00:00 2001 From: Alejandro Pinar Ruiz Date: Thu, 2 Jun 2022 14:12:39 +0200 Subject: [PATCH 13/13] Remove unused properties and fix descriptions --- src/utils/ConfigSchema.json | 119 +++++------------------------------- 1 file changed, 16 insertions(+), 103 deletions(-) diff --git a/src/utils/ConfigSchema.json b/src/utils/ConfigSchema.json index e1d72b7e2c..76ac40b6a6 100644 --- a/src/utils/ConfigSchema.json +++ b/src/utils/ConfigSchema.json @@ -782,141 +782,54 @@ "title": "Display Data", "type": "object", "additionalProperties": false, - "description": "Optional meta data for customizing a section", + "description": "Optional meta data for customizing an item", "properties": { - "sortBy": { - "title": "Sort By", - "type": "string", - "enum": [ - "default", - "most-used", - "last-used", - "alphabetical", - "reverse-alphabetical", - "random" - ], - "default": "default", - "description": "How to sort items within the section. By default items are displayed in the order in which they are listed in within the config" - }, - "collapsed": { - "title": "Is Collapsed?", - "type": "boolean", - "default": false, - "description": "If true, section needs to be clicked to open" - }, - "cutToHeight": { - "title": "Cut to Height", - "type": "boolean", - "default": false, - "description": "By default, sections will fill available space. Set this option to true to match section height with content height" - }, - "color": { - "title": "Color", - "type": "string", - "description": "Hex code, or HTML color for section fill" - }, - "customStyles": { - "title": "Custom Styles", - "type": "string", - "description": "CSS overides for section container" - }, - "itemSize": { - "title": "Item Size", - "type": "string", - "enum": [ - "small", - "medium", - "large" - ], - "default": "medium", - "description": "Size of items within the section" - }, - "rows": { - "title": "Num Rows", - "type": "number", - "minimum": 1, - "maximum": 5, - "default": 1, - "description": "The amount of space that the section spans vertically" - }, - "cols": { - "title": "Num Cols", - "type": "number", - "minimum": 1, - "maximum": 5, - "default": 1, - "description": "The amount of space that the section spans horizontally" - }, - "sectionLayout": { - "title": "Layout Type", - "type": "string", - "enum": [ - "grid", - "auto" - ], - "default": "auto", - "description": "If set to grid, items have uniform width, and itemCount can be set" - }, - "itemCountX": { - "title": "Item Count X", - "type": "number", - "minimum": 1, - "maximum": 12, - "description": "Number of items per column" - }, - "itemCountY": { - "title": "Item Count Y", - "type": "number", - "minimum": 1, - "maximum": 12, - "description": "Number of items per row" - }, "hideForUsers": { "title": "Hide for Users", "type": "array", - "description": "Section will be visible to all users, except for those specified in this list", + "description": "Item will be visible to all users, except for those specified in this list", "items": { "type": "string", - "description": "Username for the user that will not be able to view this section" + "description": "Username for the user that will not be able to view this item" } }, "showForUsers": { "title": "Show for Users", "type": "array", - "description": "Section will be hidden from all users, except for those specified in this list", + "description": "Item will be hidden from all users, except for those specified in this list", "items": { "type": "string", - "description": "Username for the user that will have access to this section" + "description": "Username for the user that will have access to this item" } }, "hideForGuests": { "title": "Hide for Guests?", "type": "boolean", "default": false, - "description": "If set to true, section will be visible for logged in users, but not for guests" + "description": "If set to true, item will be visible for logged in users, but not for guests" }, "showForKeycloakUsers": { "title": "Show for select Keycloak groups or roles", "type": "object", - "description": "Configure the Keycloak groups or roles that will have access to this section", + "description": "Configure the Keycloak groups or roles that will have access to this item", "additionalProperties": false, "properties": { "groups": { "title": "Show for Groups", "type": "array", - "description": "Section will be hidden from all users except those with one or more of these groups", + "description": "Item will be hidden from all users except those with one or more of these groups", "items": { "type": "string", - "description": "Name of the group that will be able to view this section" + "description": "Name of the group that will be able to view this item" } }, "roles": { "title": "Show for Roles", "type": "array", - "description": "Section will be hidden from all users except those with one or more of these roles", + "description": "Item will be hidden from all users except those with one or more of these roles", "items": { "type": "string", - "description": "Name of the role that will be able to view this section" + "description": "Name of the role that will be able to view this item" } } } @@ -924,25 +837,25 @@ "hideForKeycloakUsers": { "title": "Hide for select Keycloak groups or roles", "type": "object", - "description": "Configure the Keycloak groups or roles that will not have access to this section", + "description": "Configure the Keycloak groups or roles that will not have access to this item", "additionalProperties": false, "properties": { "groups": { "title": "Hide for Groups", "type": "array", - "description": "Section will be hidden from users with any of these groups", + "description": "Item will be hidden from users with any of these groups", "items": { "type": "string", - "description": "name of the group that will not be able to view this section" + "description": "name of the group that will not be able to view this item" } }, "roles": { "title": "Hide for Roles", "type": "array", - "description": "Section will be hidden from users with any of roles", + "description": "Item will be hidden from users with any of roles", "items": { "type": "string", - "description": "name of the role that will not be able to view this section" + "description": "name of the role that will not be able to view this item" } } }