Skip to content

Commit 053c55c

Browse files
authored
🔀 Merge pull request gchq#173 from Lissy93/FIX/section-visibility
[BUG-FIX] Conditional visibility of sections for users Closes gchq#172
2 parents fa56446 + 007a13d commit 053c55c

7 files changed

Lines changed: 148 additions & 45 deletions

File tree

docs/alternate-views.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Alternate Views & Opening Methods
2+
3+
## Views
4+
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`).
5+
6+
### Default
7+
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.
8+
9+
<p align="center">
10+
<b>Example of Default View</b><br>
11+
<img width="800" src="https://i.ibb.co/L8YbNNc/dashy-demo2.gif" alt="Demo" />
12+
</p>
13+
14+
### Workspace
15+
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.
16+
17+
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.
18+
19+
<p align="center">
20+
<b>Example of Workspace View</b><br>
21+
<img alt="Workspace view demo" src="https://raw.githubusercontent.com/Lissy93/dashy/master/docs/assets/workspace-demo.gif" width="800" />
22+
</p>
23+
24+
### Minimal View
25+
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.
26+
27+
<p align="center">
28+
<b>Example of Minimal View</b><br>
29+
<img alt="Workspace view demo" src="https://raw.githubusercontent.com/Lissy93/dashy/master/docs/assets/minimal-view-demo.gif" width="800" />
30+
</p>
31+
32+
## Opening Methods
33+
34+
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:
35+
36+
- `sametab` - The app will be launched in the current tab
37+
- `newtab` - The app will be launched in a new tab
38+
- `modal` - Launch app in a resizable/ movable popup modal on the current page
39+
- `workspace` - Changes to Workspace view, and launches app
40+
41+
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`.
42+
43+
<p align="center">
44+
<img width="500" src="https://i.ibb.co/vmZdSRt/dashy-context-menu-2.png" />
45+
</p>
46+
47+
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).

docs/privacy.md

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ For privacy and security tips, check out another project of mine: **[Personal Se
1111
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.
1212

1313
### Font Awesome
14-
If either sections or items are using font-awesome icons, then these will be fetched directly from font-awesome on page load.
14+
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.
1515

1616
### Favicon Fetching
1717
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
4141

4242
---
4343

44+
## Local Storage
45+
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.
46+
You can view your browsers session storage by opening up the dev tools (F12) --> Application --> Storage.
47+
48+
The following section outlines all data that is stored in the browsers, as cookies or local storage.
49+
50+
#### Cookies
51+
- `AUTH_TOKEN` - A unique token, generated from a hash of users credentials, to verify they are authenticated. Only used when auth is enabled
52+
53+
#### Local Storage
54+
- `LANGUAGE` - The locale to show app text in
55+
- `HIDE_WELCOME_BANNER` - Set to true once user dismissed welcome message, so that it's not shown again
56+
- `LAYOUT_ORIENTATION` - Preferred section layout, either horizontal, vertical or auto
57+
- `COLLAPSE_STATE` - Remembers which sections are collapsed
58+
- `ICON_SIZE` - Size of items, either small, medium or large
59+
- `THEME: 'theme` - Users applied theme
60+
- `CUSTOM_COLORS` - Any color modifications made to a given theme
61+
- `BACKUP_ID` - If a backup has been made, the ID is stored here
62+
- `BACKUP_HASH` - A unique hash of the previous backups meta data
63+
- `HIDE_SETTINGS` - Lets user hide or show the settings menu
64+
- `USERNAME` - If user logged in, store username in order to welcome them
65+
- `CONF_SECTIONS` - Array of sections, only used when user applies changes locally
66+
- `PAGE_INFO` - Config page info, only used when user applies changes locally
67+
- `APP_CONFIG` - App config, only used when user applies changes locally
68+
69+
---
70+
4471
## Dependencies
4572
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).
4673

47-
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).
74+
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.
75+
76+
Note that packages listed under `deDependencies` section are only used for building the project, and are not included in the production environment.
4877

4978
---
5079

docs/readme.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
![Dashy Docs](https://i.ibb.co/4mdNf7M/heading-docs.png)
22

33
### Running Dashy
4-
- [Deployment](/docs/deployment.md) - Getting Dashy up and running
4+
- [Quick Start](/docs/quick-start.md) - TDLR guide on getting Dashy up and running
5+
- [Deployment](/docs/deployment.md) - Full guide on deploying Dashy either locally or online
56
- [Configuring](/docs/configuring.md) - Complete list of all available options in the config file
67
- [App Management](/docs/management.md) - Managing your app, updating, security, web server configuration, etc
78
- [Troubleshooting](/docs/troubleshooting.md) - Common errors and problems, and how to fix them
@@ -15,9 +16,10 @@
1516

1617
### Feature Docs
1718
- [Authentication](/docs/authentication.md) - Guide to setting up authentication to protect your dashboard
19+
- [Alternate Views](/docs/alternate-views.md) - Outline of available pages / views and item opening methods
1820
- [Backup & Restore](/docs/backup-restore.md) - Guide to Dashy's cloud sync feature
1921
- [Icons](/docs/icons.md) - Outline of all available icon types for sections and items
20-
- [Language Switching](/docs/multi-language-support.md)
22+
- [Language Switching](/docs/multi-language-support.md) - Details on how to switch language, or add a new locale
2123
- [Status Indicators](/docs/status-indicators.md) - Using Dashy to monitor uptime and status of your apps
2224
- [Theming](/docs/theming.md) - Complete guide to applying, writing and modifying themes and styles
2325

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
:rows="displayData.rows"
99
:color="displayData.color"
1010
:customStyles="displayData.customStyles"
11-
v-if="isSectionVisibleToUser()"
1211
>
1312
<div v-if="!items || items.length < 1" class="no-items">
1413
No Items to Show Yet
@@ -52,10 +51,9 @@
5251
import Item from '@/components/LinkItems/Item.vue';
5352
import Collapsable from '@/components/LinkItems/Collapsable.vue';
5453
import IframeModal from '@/components/LinkItems/IframeModal.vue';
55-
import { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth';
5654
5755
export default {
58-
name: 'ItemGroup',
56+
name: 'Section',
5957
inject: ['config'],
6058
props: {
6159
groupId: String,
@@ -87,9 +85,6 @@ export default {
8785
? `grid-template-rows: repeat(${this.displayData.itemCountY}, 1fr);` : '';
8886
return styles;
8987
},
90-
currentUser() {
91-
return getCurrentUser();
92-
},
9388
},
9489
methods: {
9590
/* Returns a unique lowercase string, based on name, for section ID */
@@ -116,35 +111,6 @@ export default {
116111
if (interval < 1) interval = 0;
117112
return interval;
118113
},
119-
/* Returns false if this section should not be rendered for the current user/ guest */
120-
isSectionVisibleToUser() {
121-
const determineVisibility = (visibilityList, currentUser) => {
122-
let isFound = false;
123-
visibilityList.forEach((userInList) => {
124-
if (userInList.toLowerCase() === currentUser) isFound = true;
125-
});
126-
return isFound;
127-
};
128-
const checkVisiblity = () => {
129-
if (!this.currentUser) return true;
130-
const hideFor = this.displayData.hideForUsers || [];
131-
const currentUser = this.currentUser.user.toLowerCase();
132-
return !determineVisibility(hideFor, currentUser);
133-
};
134-
const checkHiddenability = () => {
135-
if (!this.currentUser) return true;
136-
const currentUser = this.currentUser.user.toLowerCase();
137-
const showForUsers = this.displayData.showForUsers || [];
138-
if (showForUsers.length < 1) return true;
139-
return determineVisibility(showForUsers, currentUser);
140-
};
141-
const checkIfHideForGuest = () => {
142-
const hideForGuest = this.displayData.hideForGuests;
143-
const isGuest = isLoggedInAsGuest();
144-
return !(hideForGuest && isGuest);
145-
};
146-
return checkVisiblity() && checkHiddenability() && checkIfHideForGuest();
147-
},
148114
},
149115
};
150116
</script>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* A helper function that filters all the sections based on current users permissions
3+
* Checks each sections displayData for hideForUsers, showForUsers and hideForGuests
4+
* Returns an array of sections that the current logged in user has permissions for
5+
*/
6+
7+
// Import helper functions from auth, to get current user, and check if guest
8+
import { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth';
9+
10+
/* Helper function, checks if a given username appears in a user array */
11+
const determineVisibility = (visibilityList, cUsername) => {
12+
let isFound = false;
13+
visibilityList.forEach((userInList) => {
14+
if (userInList.toLowerCase() === cUsername) isFound = true;
15+
});
16+
return isFound;
17+
};
18+
19+
/* Returns false if this section should not be rendered for the current user/ guest */
20+
const isSectionVisibleToUser = (displayData, currentUser, isGuest) => {
21+
// Checks if user explicitly has access to a certain section
22+
const checkVisiblity = () => {
23+
if (!currentUser) return true;
24+
const hideFor = displayData.hideForUsers || [];
25+
const cUsername = currentUser.user.toLowerCase();
26+
return !determineVisibility(hideFor, cUsername);
27+
};
28+
// Checks if user is explicitly prevented from viewing a certain section
29+
const checkHiddenability = () => {
30+
if (!currentUser) return true;
31+
const cUsername = currentUser.user.toLowerCase();
32+
const showForUsers = displayData.showForUsers || [];
33+
if (showForUsers.length < 1) return true;
34+
return determineVisibility(showForUsers, cUsername);
35+
};
36+
// Checks if the current user is a guest, and if section allows for guests
37+
const checkIfHideForGuest = () => {
38+
const hideForGuest = displayData.hideForGuests;
39+
return !(hideForGuest && isGuest);
40+
};
41+
return checkVisiblity() && checkHiddenability() && checkIfHideForGuest();
42+
};
43+
44+
/* Putting it all together, the function to export */
45+
const checkSectionVisibility = (sections) => {
46+
const currentUser = getCurrentUser(); // Get current user object
47+
const isGuest = isLoggedInAsGuest(); // Check if current user is a guest
48+
return sections.filter((currentSection) => {
49+
const displayData = currentSection.displayData || {};
50+
return isSectionVisibleToUser(displayData, currentUser, isGuest);
51+
});
52+
};
53+
54+
export default checkSectionVisibility;

src/utils/ConfigHelpers.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ConfigAccumulator from '@/utils/ConfigAccumalator';
2+
import filterUserSections from '@/utils/CheckSectionVisibility';
23
import { languages } from '@/utils/languages';
34
import {
45
visibleComponents,
@@ -13,7 +14,11 @@ import {
1314
*/
1415
export const config = (() => {
1516
const Accumulator = new ConfigAccumulator();
16-
return Accumulator.config();
17+
return {
18+
appConfig: Accumulator.appConfig(),
19+
pageInfo: Accumulator.pageInfo(),
20+
sections: filterUserSections(Accumulator.sections()),
21+
};
1722
})();
1823

1924
/**

src/views/Home.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<!-- Main content, section for each group of items -->
1919
<div v-if="checkTheresData(sections)"
2020
:class="`item-group-container orientation-${layout} item-size-${itemSizeBound}`">
21-
<ItemGroup
21+
<Section
2222
v-for="(section, index) in getSections(sections)"
2323
:key="index"
2424
:title="section.name"
@@ -42,7 +42,7 @@
4242
<script>
4343
4444
import SettingsContainer from '@/components/Settings/SettingsContainer.vue';
45-
import ItemGroup from '@/components/LinkItems/ItemGroup.vue';
45+
import Section from '@/components/LinkItems/Section.vue';
4646
import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults';
4747
4848
export default {
@@ -54,7 +54,7 @@ export default {
5454
},
5555
components: {
5656
SettingsContainer,
57-
ItemGroup,
57+
Section,
5858
},
5959
data: () => ({
6060
searchValue: '',
@@ -130,11 +130,11 @@ export default {
130130
getDisplayData(section) {
131131
return !section.displayData ? {} : section.displayData;
132132
},
133-
/* Sets layout attribute, which is used by ItemGroup */
133+
/* Sets layout attribute, which is used by Section */
134134
setLayoutOrientation(layout) {
135135
this.layoutOrientation = layout;
136136
},
137-
/* Sets item size attribute, which is used by ItemGroup */
137+
/* Sets item size attribute, which is used by Section */
138138
setItemSize(itemSize) {
139139
this.iconSize = itemSize;
140140
},

0 commit comments

Comments
 (0)