mirror of
https://github.com/Lissy93/dashy.git
synced 2024-12-25 09:56:15 +03:00
🔀 Merge pull request #173 from Lissy93/FIX/section-visibility
[BUG-FIX] Conditional visibility of sections for users Closes #172
This commit is contained in:
commit
053c55c8e3
@ -0,0 +1,47 @@
|
||||
# Alternate Views & Opening Methods
|
||||
|
||||
## Views
|
||||
As well as the default start view, Dashy has several other start pages, for different tasks. You can switch views with the view-switcher button in the top-right, or set a default starting view using the `appConfig.startingView` attribute (can be `default`, `minimal` or `workspace`).
|
||||
|
||||
### Default
|
||||
This is the main page that you will land on when you first launch the application. Here all of your sections and items will be visible, you can modify settings and search + launch your applications.
|
||||
|
||||
<p align="center">
|
||||
<b>Example of Default View</b><br>
|
||||
<img width="800" src="https://i.ibb.co/L8YbNNc/dashy-demo2.gif" alt="Demo" />
|
||||
</p>
|
||||
|
||||
### Workspace
|
||||
The workspace view displays your links in a sidebar on the left-hand side, and apps are launched within Dashy. This enables you to use all of your self-hosted apps from one place, and makes multi-tasking easy.
|
||||
|
||||
In the workspace view, you can keep previously opened websites/ apps open in the background, by setting `appConfig.enableMultiTasking: true`. This comes at the cost of performance, but does mean that your session with each app is preserved, enabling you to quickly switch between your apps.
|
||||
|
||||
<p align="center">
|
||||
<b>Example of Workspace View</b><br>
|
||||
<img alt="Workspace view demo" src="https://raw.githubusercontent.com/Lissy93/dashy/master/docs/assets/workspace-demo.gif" width="800" />
|
||||
</p>
|
||||
|
||||
### Minimal View
|
||||
The minimal view aims to be super fast and simple, and can be used as a browser startpage. Items are grouped into a tab view, and the last opened tab will be remembered. Similar to the main view, you can search and launch items just by typing, and right-clicking will show more options.
|
||||
|
||||
<p align="center">
|
||||
<b>Example of Minimal View</b><br>
|
||||
<img alt="Workspace view demo" src="https://raw.githubusercontent.com/Lissy93/dashy/master/docs/assets/minimal-view-demo.gif" width="800" />
|
||||
</p>
|
||||
|
||||
## Opening Methods
|
||||
|
||||
Dashy supports several different ways to launch your apps. The default opening method for each app can be specified using the `target` attribute, with a value of one of the following:
|
||||
|
||||
- `sametab` - The app will be launched in the current tab
|
||||
- `newtab` - The app will be launched in a new tab
|
||||
- `modal` - Launch app in a resizable/ movable popup modal on the current page
|
||||
- `workspace` - Changes to Workspace view, and launches app
|
||||
|
||||
Even if the target is not set (or is set to `sametab`), you can still launch any given app in an alternative method: Alt + Click will open the modal, and Ctrl + Click will open in a new tab. You can also right-click on any item to see all options (as seen in the screenshot below). This custom context menu can be disabled by setting `appConfig.disableContextMenu: true`.
|
||||
|
||||
<p align="center">
|
||||
<img width="500" src="https://i.ibb.co/vmZdSRt/dashy-context-menu-2.png" />
|
||||
</p>
|
||||
|
||||
If you get a 'Refused to Connect' error in the modal or workspace views, then the target app has it's X-Frame-Options HTTP set to block requests from embedded content. You can easily fix this by setting this header to ALLOW, for instructions on how to do so, see the [Troubleshooting Docs](/docs/troubleshooting.md#refused-to-connect-in-modal-or-workspace-view).
|
@ -11,7 +11,7 @@ For privacy and security tips, check out another project of mine: **[Personal Se
|
||||
By default, Dashy will not make any external requests, unless you configure it to. Some features (which are all off by default) do require internat access, and this section outlines those features, the services used, and links to their privacy policies.
|
||||
|
||||
### Font Awesome
|
||||
If either sections or items are using font-awesome icons, then these will be fetched directly from font-awesome on page load.
|
||||
If either any of your sections or items are using font-awesome icons, then these will be fetched directly from font-awesome on page load. See the [Font Awesome Privacy Policy](https://fontawesome.com/privacy) for more info.
|
||||
|
||||
### Favicon Fetching
|
||||
If an item's icon is set to `favicon`, then it will be auto-fetched from the corresponding URL. Since not all websites have their icon located at `/favicon.ico`, and if they do, it's often very low resolution (like `16 x 16 px`). Therefore, the default behavior is for Dashy to check if the URL is public, and if so will use an API to fetch the favicon. For self-hosted services, the favion will be fetched from the default path, and no external requests will be made.
|
||||
@ -41,10 +41,39 @@ If you need to monitor bugs yourself, then you can [self-host your own Sentry Se
|
||||
|
||||
---
|
||||
|
||||
## Local Storage
|
||||
In order for user preferences to be persisted between sessions, certain data needs to be stored in the browsers local storage. No personal info is kept here, none of this data can be accessed by other domains, and no data is ever sent to any server without your prior consent.
|
||||
You can view your browsers session storage by opening up the dev tools (F12) --> Application --> Storage.
|
||||
|
||||
The following section outlines all data that is stored in the browsers, as cookies or local storage.
|
||||
|
||||
#### Cookies
|
||||
- `AUTH_TOKEN` - A unique token, generated from a hash of users credentials, to verify they are authenticated. Only used when auth is enabled
|
||||
|
||||
#### Local Storage
|
||||
- `LANGUAGE` - The locale to show app text in
|
||||
- `HIDE_WELCOME_BANNER` - Set to true once user dismissed welcome message, so that it's not shown again
|
||||
- `LAYOUT_ORIENTATION` - Preferred section layout, either horizontal, vertical or auto
|
||||
- `COLLAPSE_STATE` - Remembers which sections are collapsed
|
||||
- `ICON_SIZE` - Size of items, either small, medium or large
|
||||
- `THEME: 'theme` - Users applied theme
|
||||
- `CUSTOM_COLORS` - Any color modifications made to a given theme
|
||||
- `BACKUP_ID` - If a backup has been made, the ID is stored here
|
||||
- `BACKUP_HASH` - A unique hash of the previous backups meta data
|
||||
- `HIDE_SETTINGS` - Lets user hide or show the settings menu
|
||||
- `USERNAME` - If user logged in, store username in order to welcome them
|
||||
- `CONF_SECTIONS` - Array of sections, only used when user applies changes locally
|
||||
- `PAGE_INFO` - Config page info, only used when user applies changes locally
|
||||
- `APP_CONFIG` - App config, only used when user applies changes locally
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
As with most web projects, Dashy relies on several [dependencies](https://github.com/Lissy93/dashy/blob/master/docs/credits.md#dependencies-). For links to each, and a breakdown of their licenses, please see [Legal](https://github.com/Lissy93/dashy/blob/master/.github/LEGAL.md).
|
||||
|
||||
Dependencies can introduce security vulnerabilities, but since all these packages are open source any issues are usually very quickly spotted. Dashy is using Snyk for dependency security monitoring, and you can see [the latest report here](https://snyk.io/test/github/lissy93/dashy).
|
||||
Dependencies can introduce security vulnerabilities, but since all these packages are open source any issues are usually very quickly spotted. Dashy is using Snyk for dependency security monitoring, and you can see [the latest report here](https://snyk.io/test/github/lissy93/dashy). If any issue is detected by Snyk, a note about it will appear at the top of the Reamde, and will usually be fixed within 48 hours.
|
||||
|
||||
Note that packages listed under `deDependencies` section are only used for building the project, and are not included in the production environment.
|
||||
|
||||
---
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
![Dashy Docs](https://i.ibb.co/4mdNf7M/heading-docs.png)
|
||||
|
||||
### Running Dashy
|
||||
- [Deployment](/docs/deployment.md) - Getting Dashy up and running
|
||||
- [Quick Start](/docs/quick-start.md) - TDLR guide on getting Dashy up and running
|
||||
- [Deployment](/docs/deployment.md) - Full guide on deploying Dashy either locally or online
|
||||
- [Configuring](/docs/configuring.md) - Complete list of all available options in the config file
|
||||
- [App Management](/docs/management.md) - Managing your app, updating, security, web server configuration, etc
|
||||
- [Troubleshooting](/docs/troubleshooting.md) - Common errors and problems, and how to fix them
|
||||
@ -15,9 +16,10 @@
|
||||
|
||||
### Feature Docs
|
||||
- [Authentication](/docs/authentication.md) - Guide to setting up authentication to protect your dashboard
|
||||
- [Alternate Views](/docs/alternate-views.md) - Outline of available pages / views and item opening methods
|
||||
- [Backup & Restore](/docs/backup-restore.md) - Guide to Dashy's cloud sync feature
|
||||
- [Icons](/docs/icons.md) - Outline of all available icon types for sections and items
|
||||
- [Language Switching](/docs/multi-language-support.md)
|
||||
- [Language Switching](/docs/multi-language-support.md) - Details on how to switch language, or add a new locale
|
||||
- [Status Indicators](/docs/status-indicators.md) - Using Dashy to monitor uptime and status of your apps
|
||||
- [Theming](/docs/theming.md) - Complete guide to applying, writing and modifying themes and styles
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
:rows="displayData.rows"
|
||||
:color="displayData.color"
|
||||
:customStyles="displayData.customStyles"
|
||||
v-if="isSectionVisibleToUser()"
|
||||
>
|
||||
<div v-if="!items || items.length < 1" class="no-items">
|
||||
No Items to Show Yet
|
||||
@ -52,10 +51,9 @@
|
||||
import Item from '@/components/LinkItems/Item.vue';
|
||||
import Collapsable from '@/components/LinkItems/Collapsable.vue';
|
||||
import IframeModal from '@/components/LinkItems/IframeModal.vue';
|
||||
import { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth';
|
||||
|
||||
export default {
|
||||
name: 'ItemGroup',
|
||||
name: 'Section',
|
||||
inject: ['config'],
|
||||
props: {
|
||||
groupId: String,
|
||||
@ -87,9 +85,6 @@ export default {
|
||||
? `grid-template-rows: repeat(${this.displayData.itemCountY}, 1fr);` : '';
|
||||
return styles;
|
||||
},
|
||||
currentUser() {
|
||||
return getCurrentUser();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/* Returns a unique lowercase string, based on name, for section ID */
|
||||
@ -116,35 +111,6 @@ export default {
|
||||
if (interval < 1) interval = 0;
|
||||
return interval;
|
||||
},
|
||||
/* Returns false if this section should not be rendered for the current user/ guest */
|
||||
isSectionVisibleToUser() {
|
||||
const determineVisibility = (visibilityList, currentUser) => {
|
||||
let isFound = false;
|
||||
visibilityList.forEach((userInList) => {
|
||||
if (userInList.toLowerCase() === currentUser) isFound = true;
|
||||
});
|
||||
return isFound;
|
||||
};
|
||||
const checkVisiblity = () => {
|
||||
if (!this.currentUser) return true;
|
||||
const hideFor = this.displayData.hideForUsers || [];
|
||||
const currentUser = this.currentUser.user.toLowerCase();
|
||||
return !determineVisibility(hideFor, currentUser);
|
||||
};
|
||||
const checkHiddenability = () => {
|
||||
if (!this.currentUser) return true;
|
||||
const currentUser = this.currentUser.user.toLowerCase();
|
||||
const showForUsers = this.displayData.showForUsers || [];
|
||||
if (showForUsers.length < 1) return true;
|
||||
return determineVisibility(showForUsers, currentUser);
|
||||
};
|
||||
const checkIfHideForGuest = () => {
|
||||
const hideForGuest = this.displayData.hideForGuests;
|
||||
const isGuest = isLoggedInAsGuest();
|
||||
return !(hideForGuest && isGuest);
|
||||
};
|
||||
return checkVisiblity() && checkHiddenability() && checkIfHideForGuest();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
54
src/utils/CheckSectionVisibility.js
Normal file
54
src/utils/CheckSectionVisibility.js
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* A helper function that filters all the sections 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 { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth';
|
||||
|
||||
/* Helper function, checks if a given username appears in a user array */
|
||||
const determineVisibility = (visibilityList, cUsername) => {
|
||||
let isFound = false;
|
||||
visibilityList.forEach((userInList) => {
|
||||
if (userInList.toLowerCase() === cUsername) isFound = true;
|
||||
});
|
||||
return isFound;
|
||||
};
|
||||
|
||||
/* 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 checkVisiblity = () => {
|
||||
if (!currentUser) return true;
|
||||
const hideFor = displayData.hideForUsers || [];
|
||||
const cUsername = currentUser.user.toLowerCase();
|
||||
return !determineVisibility(hideFor, 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);
|
||||
};
|
||||
// Checks if the current user is a guest, and if section allows for guests
|
||||
const checkIfHideForGuest = () => {
|
||||
const hideForGuest = displayData.hideForGuests;
|
||||
return !(hideForGuest && isGuest);
|
||||
};
|
||||
return checkVisiblity() && checkHiddenability() && checkIfHideForGuest();
|
||||
};
|
||||
|
||||
/* Putting it all together, the function to 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);
|
||||
});
|
||||
};
|
||||
|
||||
export default checkSectionVisibility;
|
@ -1,4 +1,5 @@
|
||||
import ConfigAccumulator from '@/utils/ConfigAccumalator';
|
||||
import filterUserSections from '@/utils/CheckSectionVisibility';
|
||||
import { languages } from '@/utils/languages';
|
||||
import {
|
||||
visibleComponents,
|
||||
@ -13,7 +14,11 @@ import {
|
||||
*/
|
||||
export const config = (() => {
|
||||
const Accumulator = new ConfigAccumulator();
|
||||
return Accumulator.config();
|
||||
return {
|
||||
appConfig: Accumulator.appConfig(),
|
||||
pageInfo: Accumulator.pageInfo(),
|
||||
sections: filterUserSections(Accumulator.sections()),
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,7 @@
|
||||
<!-- Main content, section for each group of items -->
|
||||
<div v-if="checkTheresData(sections)"
|
||||
:class="`item-group-container orientation-${layout} item-size-${itemSizeBound}`">
|
||||
<ItemGroup
|
||||
<Section
|
||||
v-for="(section, index) in getSections(sections)"
|
||||
:key="index"
|
||||
:title="section.name"
|
||||
@ -42,7 +42,7 @@
|
||||
<script>
|
||||
|
||||
import SettingsContainer from '@/components/Settings/SettingsContainer.vue';
|
||||
import ItemGroup from '@/components/LinkItems/ItemGroup.vue';
|
||||
import Section from '@/components/LinkItems/Section.vue';
|
||||
import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults';
|
||||
|
||||
export default {
|
||||
@ -54,7 +54,7 @@ export default {
|
||||
},
|
||||
components: {
|
||||
SettingsContainer,
|
||||
ItemGroup,
|
||||
Section,
|
||||
},
|
||||
data: () => ({
|
||||
searchValue: '',
|
||||
@ -130,11 +130,11 @@ export default {
|
||||
getDisplayData(section) {
|
||||
return !section.displayData ? {} : section.displayData;
|
||||
},
|
||||
/* Sets layout attribute, which is used by ItemGroup */
|
||||
/* Sets layout attribute, which is used by Section */
|
||||
setLayoutOrientation(layout) {
|
||||
this.layoutOrientation = layout;
|
||||
},
|
||||
/* Sets item size attribute, which is used by ItemGroup */
|
||||
/* Sets item size attribute, which is used by Section */
|
||||
setItemSize(itemSize) {
|
||||
this.iconSize = itemSize;
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user