From c83041882a0ff619038703a2e5d9d765e711b9ce Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sat, 21 Aug 2021 15:01:08 +0100 Subject: [PATCH 1/6] =?UTF-8?q?:truck:=20Rename=20ItemGroup=20=E2=86=92=20?= =?UTF-8?q?Section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LinkItems/{ItemGroup.vue => Section.vue} | 2 +- src/views/Home.vue | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) rename src/components/LinkItems/{ItemGroup.vue => Section.vue} (99%) diff --git a/src/components/LinkItems/ItemGroup.vue b/src/components/LinkItems/Section.vue similarity index 99% rename from src/components/LinkItems/ItemGroup.vue rename to src/components/LinkItems/Section.vue index 482c83b61..4b78eec8c 100644 --- a/src/components/LinkItems/ItemGroup.vue +++ b/src/components/LinkItems/Section.vue @@ -55,7 +55,7 @@ import IframeModal from '@/components/LinkItems/IframeModal.vue'; import { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth'; export default { - name: 'ItemGroup', + name: 'Section', inject: ['config'], props: { groupId: String, diff --git a/src/views/Home.vue b/src/views/Home.vue index 42adf811e..b13c818e7 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -18,7 +18,7 @@
- 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; }, From f7ad5206d6a1e5663543d4b844bccda503162f6a Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sat, 21 Aug 2021 16:41:40 +0100 Subject: [PATCH 2/6] :bug: Re: #172 - Moves section filtering to higher order --- src/components/LinkItems/Section.vue | 37 ++-------------- src/utils/CheckSectionVisibility.js | 64 ++++++++++++++++++++++++++++ src/utils/ConfigHelpers.js | 8 +++- 3 files changed, 75 insertions(+), 34 deletions(-) create mode 100644 src/utils/CheckSectionVisibility.js diff --git a/src/components/LinkItems/Section.vue b/src/components/LinkItems/Section.vue index 4b78eec8c..e77df8ab1 100644 --- a/src/components/LinkItems/Section.vue +++ b/src/components/LinkItems/Section.vue @@ -8,7 +8,6 @@ :rows="displayData.rows" :color="displayData.color" :customStyles="displayData.customStyles" - v-if="isSectionVisibleToUser()" >
No Items to Show Yet @@ -52,7 +51,7 @@ 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'; +// import { isSectionVisibleToUser } from '@/utils/ConfigHelpers'; export default { name: 'Section', @@ -87,9 +86,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 */ @@ -117,34 +113,9 @@ export default { 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(); - }, + // isSectionVisibleToUser() { + // return isSectionVisibleToUser(this.displayData); + // }, }, }; diff --git a/src/utils/CheckSectionVisibility.js b/src/utils/CheckSectionVisibility.js new file mode 100644 index 000000000..55b789545 --- /dev/null +++ b/src/utils/CheckSectionVisibility.js @@ -0,0 +1,64 @@ +/** + * 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 filterSectionVisibility = (sections) => { + const currentUser = getCurrentUser(); // Get current user object + const isGuest = isLoggedInAsGuest(); // Check if current user is a guest + // const sectionsToReturn = []; + // sections.forEach((currentSection) => { + // const displayData = currentSection.displayData || {}; + // if (isSectionVisibleToUser(displayData, currentUser, isGuest)) { + // sectionsToReturn.push(currentSection); + // } + // }); + + const filteredSections = sections.filter((currentSection) => { + const displayData = currentSection.displayData || {}; + return isSectionVisibleToUser(displayData, currentUser, isGuest); + }); + + return filteredSections; +}; + +export default filterSectionVisibility; diff --git a/src/utils/ConfigHelpers.js b/src/utils/ConfigHelpers.js index d282c297c..381a9c0f0 100644 --- a/src/utils/ConfigHelpers.js +++ b/src/utils/ConfigHelpers.js @@ -1,4 +1,5 @@ import ConfigAccumulator from '@/utils/ConfigAccumalator'; +import filterUserSections from '@/utils/CheckSectionVisibility'; import { languages } from '@/utils/languages'; import { visibleComponents, @@ -13,7 +14,12 @@ import { */ export const config = (() => { const Accumulator = new ConfigAccumulator(); - return Accumulator.config(); + // return Accumulator.config(); + return { + appConfig: Accumulator.appConfig(), + pageInfo: Accumulator.pageInfo(), + sections: filterUserSections(Accumulator.sections()), + }; })(); /** From 4c1475533e48b4bf73488a081ce3205643979fbb Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sat, 21 Aug 2021 16:49:06 +0100 Subject: [PATCH 3/6] :green_heart: Removes commented out code in Section --- src/components/LinkItems/Section.vue | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/LinkItems/Section.vue b/src/components/LinkItems/Section.vue index e77df8ab1..f9bc3afa2 100644 --- a/src/components/LinkItems/Section.vue +++ b/src/components/LinkItems/Section.vue @@ -51,7 +51,6 @@ import Item from '@/components/LinkItems/Item.vue'; import Collapsable from '@/components/LinkItems/Collapsable.vue'; import IframeModal from '@/components/LinkItems/IframeModal.vue'; -// import { isSectionVisibleToUser } from '@/utils/ConfigHelpers'; export default { name: 'Section', @@ -112,10 +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() { - // return isSectionVisibleToUser(this.displayData); - // }, }, }; From b9e9db3ec9b123871d2816b1b8e1d77b15f425ef Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sat, 21 Aug 2021 17:17:02 +0100 Subject: [PATCH 4/6] :memo: Adds alternate views page to docs --- docs/alternate-views.md | 47 +++++++++++++++++++++++++++++++++++++++++ docs/readme.md | 6 ++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/docs/alternate-views.md b/docs/alternate-views.md index e69de29bb..de72cd1a5 100644 --- a/docs/alternate-views.md +++ b/docs/alternate-views.md @@ -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. + +

+ Example of Default View
+ Demo +

+ +### 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. + +

+ Example of Workspace View
+ Workspace view demo +

+ +### 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. + +

+ Example of Minimal View
+ Workspace view demo +

+ +## 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`. + +

+ +

+ +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). diff --git a/docs/readme.md b/docs/readme.md index 334cb7b55..945212041 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -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 From 426f6a79c33d5cbe6466679b0cb8ff86e02173bb Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sat, 21 Aug 2021 17:18:33 +0100 Subject: [PATCH 5/6] :memo: Adds list of data stored in Local Storage --- docs/privacy.md | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/privacy.md b/docs/privacy.md index ff43538b9..2e7898166 100644 --- a/docs/privacy.md +++ b/docs/privacy.md @@ -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. --- From 007a13d8685a204dbaef635da381323737745bf2 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sat, 21 Aug 2021 17:24:11 +0100 Subject: [PATCH 6/6] :green_heart: Fix code quality issues --- src/utils/CheckSectionVisibility.js | 16 +++------------- src/utils/ConfigHelpers.js | 1 - 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/utils/CheckSectionVisibility.js b/src/utils/CheckSectionVisibility.js index 55b789545..b5b65f4e0 100644 --- a/src/utils/CheckSectionVisibility.js +++ b/src/utils/CheckSectionVisibility.js @@ -42,23 +42,13 @@ const isSectionVisibleToUser = (displayData, currentUser, isGuest) => { }; /* Putting it all together, the function to export */ -const filterSectionVisibility = (sections) => { +const checkSectionVisibility = (sections) => { const currentUser = getCurrentUser(); // Get current user object const isGuest = isLoggedInAsGuest(); // Check if current user is a guest - // const sectionsToReturn = []; - // sections.forEach((currentSection) => { - // const displayData = currentSection.displayData || {}; - // if (isSectionVisibleToUser(displayData, currentUser, isGuest)) { - // sectionsToReturn.push(currentSection); - // } - // }); - - const filteredSections = sections.filter((currentSection) => { + return sections.filter((currentSection) => { const displayData = currentSection.displayData || {}; return isSectionVisibleToUser(displayData, currentUser, isGuest); }); - - return filteredSections; }; -export default filterSectionVisibility; +export default checkSectionVisibility; diff --git a/src/utils/ConfigHelpers.js b/src/utils/ConfigHelpers.js index 381a9c0f0..d8ce987f5 100644 --- a/src/utils/ConfigHelpers.js +++ b/src/utils/ConfigHelpers.js @@ -14,7 +14,6 @@ import { */ export const config = (() => { const Accumulator = new ConfigAccumulator(); - // return Accumulator.config(); return { appConfig: Accumulator.appConfig(), pageInfo: Accumulator.pageInfo(),