🔀 Merge pull request #451 from Lissy93/REFACTOR/docker-builds-and-small-fixes

[REFACTOR] Architectural Update and Small Fixes, for V 2.0.0
This commit is contained in:
Alicia Sykes 2022-01-30 21:28:02 +00:00 committed by GitHub
commit e1a78db853
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 112 additions and 79 deletions

10
.github/CHANGELOG.md vendored
View File

@ -1,5 +1,15 @@
# Changelog
## ⚡️ 2.0.0 - Small Fixes and Docker Multi-Arch Build [PR #451](https://github.com/Lissy93/dashy/pull/451)
- Fixes full-height sections for mobile and Safari (Re: #432, #442)
- Fixes empty section visible in search (Re: #447)
- Fixes numbers omited from tag names (Re: #430)
- Option for custom status code in status check (Re: #456, #448)
- Adds @stuu3k's dashboard to showcase (Re: #446)
- Switches recover and death count in Covid widget (Re: #148)
- Improved contrast in light material theme
- Adds new script to lint, test, build and publish a multi-architecture Docker image to various registries
## 💄 1.9.9 - Minor UI + Docs Updates [PR #431](https://github.com/Lissy93/dashy/pull/431)
- Improved theme support for widgets
- Better widget layout in Workspace and Minimal views

View File

@ -59,5 +59,6 @@ body:
## Thanks 🙏
Sorry you are having issues with Dashy, and thank you for raising this ticket - in doing so you are helping to make the app better for everyone 💪
You should expect a reply within the next 48 hours :)
⭐️ If you are not a bot, please star the repo before submitting your ticket.
validations:
required: false
required: false

View File

@ -19,7 +19,7 @@ jobs:
add-awaiting-author:
runs-on: ubuntu-latest
if: ${{!github.event.issue.pull_request && github.event.comment.author_association != 'COLLABORATOR' && github.event.comment.author_association != 'OWNER' && github.event.issue.state === 'open' }}
if: ${{!github.event.issue.pull_request && github.event.comment.author_association != 'COLLABORATOR' && github.event.comment.author_association != 'OWNER' && github.event.issue.state == 'open' }}
steps:
- name: Add Awaiting Author labels when Updated
uses: actions-cool/issues-helper@v2

View File

@ -312,6 +312,7 @@ There are several different ways you can launch apps. You can specify the defaul
- `newtab` - The app will be launched in a new tab (or use Ctrl + Click)
- `modal` - Launch app in a resizable/ movable popup modal on the current page (or use Alt + Click)
- `workspace` - Changes to Workspace view and launches app
- `clipboard` - Copy the app's URL to your system clipboard
- `top` - Opens in the top-most browsing context, useful if you're accessing Dashy through an iframe
---
@ -462,7 +463,7 @@ Several areas that we need a bit of help with at the moment are:
- Complete a [short survey](https://survey.typeform.com/to/gl0L68ou) to have your say about future features
- Share your dashboard in the [Showcase](https://github.com/Lissy93/dashy/blob/master/docs/showcase.md#dashy-showcase-), to inspire others
- Spread the word by sharing Dashy or a screenshot of your dashboard to help new users discover it
- Submit a PR to add a new feature, fix a bug, update the docs, add a theme, or something else
- Submit a PR to add a new feature, fix a bug, update the docs, add a theme, widget or something else
- Star Dashy on GitHub/ DockerHub or leave an upvote / review on [these platforms](https://github.com/Lissy93/dashy/blob/master/docs/contributing.md#star-upvote-or-leave-a-review)
[![Sponsor Lissy93 on GitHub](./docs/assets/sponsor-button.svg)](https://github.com/sponsors/Lissy93)
@ -540,8 +541,9 @@ To set up the development environment:
1. Get Code: `git clone https://github.com/Lissy93/dashy.git` and `cd dashy`
2. Install dependencies: `yarn`
3. Start dev server: `yarn dev`
4. Open the browser: `http://localhost:8080`
Hot reload is enabled, so changes will be automatically detected, compiled and, refreshed.
When you're ready, you can build the production app with `yarn build`, and then run it with `yarn start`
If you're new to web development, I've put together a short [list of resources](https://github.com/Lissy93/dashy/blob/master/docs/developing.md#resources-for-beginners) to help beginners get started
@ -556,22 +558,6 @@ If you're new to web development, I've put together a short [list of resources](
---
## Release Schedule 🗞️
> For full release, automation and CI documentation, see: [**Releases & Workflows**](./docs/release-workflow.md)
Dashy is under active development, with features, improvements, and changes pushed almost daily.
We're using [Semantic Versioning](https://semver.org/) to indicate major, minor, and patch versions. You can find the current version number in the readme and check the version of your app under the config menu. The version number is pulled from the [package.json](https://github.com/Lissy93/dashy/blob/master/package.json#L3) file.
Typically there is a new major release every 2 - 4 weeks, usually on Sunday, and you can view these under the [Releases Page](https://github.com/Lissy93/dashy/releases) and [on DockerHub](https://hub.docker.com/r/lissy93/dashy/tags). In addition, new minor versions are pushed several times a week and are [tagged here](https://github.com/Lissy93/dashy/tags).
For a full breakdown of each change, you can view the [Changelog](https://github.com/Lissy93/dashy/blob/master/.github/CHANGELOG.md). In addition, each new feature or significant change needs to be submitted through [a pull request](https://github.com/Lissy93/dashy/pulls?q=is%3Apr), which makes it easy to review and track these changes, and roll back if needed.
**[⬆️ Back to Top](#dashy)**
---
## Documentation 📘
> For full docs, see: **[Documentation Contents](./docs/readme.md)**
#### Running Dashy
@ -581,6 +567,17 @@ For a full breakdown of each change, you can view the [Changelog](https://github
- 💻 [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
#### 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 backing up config with Dashy's cloud sync feature
- 🧸 [Icons](/docs/icons.md) - Outline of all available icon types for sections and items, with examples
- 🌐 [Multi-Language Support](/docs/multi-language-support.md) - Switching languages, and adding a new locales
- 🚦 [Status Indicators](/docs/status-indicators.md) - Using Dashy to monitor uptime and status of your apps
- 🔍 [Searching & Shortcuts](/docs/searching.md) - Searching, launching methods + keyboard shortcuts
- 🎨 [Theming](/docs/theming.md) - Complete guide to applying, writing and modifying themes + styles
- 📊 [Widgets](/docs/widgets.md) - List of all dynamic content widgets, with usage guides and examples
#### Development and Contributing
- 🧱 [Developing](/docs/developing.md) - Running Dashy development server locally, and general workflow
- 🛎️ [Development Guides](/docs/development-guides.md) - Common development tasks, to help new contributors
@ -589,16 +586,6 @@ For a full breakdown of each change, you can view the [Changelog](https://github
- 🏆 [Credits](/docs/credits.md) - Shout out to the amazing people who have contributed so far
- 🗞️ [Release Workflow](/docs/release-workflow.md) - Info about releases, CI and automated tasks
#### 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) - How to change language, add a language, or update text
- 🚦 [Status Indicators](/docs/status-indicators.md) - Using Dashy to monitor uptime and status of your apps
- 🔍 [Searching & Shortcuts](/docs/searching.md) - Finding and launching your apps, and using keyboard shortcuts
- 🎨 [Theming](/docs/theming.md) - Complete guide to applying, writing and modifying themes and styles
#### Misc
- 🔐 [Privacy & Security](/docs/privacy.md) - List of requests, potential issues, and security resources
- 📄 [License](/LICENSE) - Copy of the MIT License
@ -612,14 +599,11 @@ For a full breakdown of each change, you can view the [Changelog](https://github
## Roadmap 🛣️
> For past and future app updates, see: [**Changelog**](/.github/CHANGELOG.md)
For upcoming features that will be released in the near future, see the [**Current Roadmap**](https://github.com/Lissy93/dashy/discussions/405)
The following features and tasks are planned for the near future.
- Widget support- cards showing live stats and interactive content from your self-hosted services
- ✅ UI editor and visual configurator
- Replacement of Node backend with Go
**[⬆️ Back to Top](#dashy)**
For past updates, see the [**Changelog**](/.github/CHANGELOG.md)
**[⬆️ Back to Top](#dashy)**
---

View File

@ -193,6 +193,7 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)**
**`statusCheckUrl`** | `string` | _Optional_ | If you've enabled `statusCheck`, and want to use a different URL to what is defined under the item, then specify it here
**`statusCheckHeaders`** | `object` | _Optional_ | If you're endpoint requires any specific headers for the status checking, then define them here
**`statusCheckAllowInsecure`** | `boolean` | _Optional_ | By default, any request to insecure content will be blocked. Setting this option to `true` will disable the `rejectUnauthorized` option, enabling you to ping non-HTTPS services for the current item. Defaults to `false`
**`statusCheckAcceptCodes`** | `string` | _Optional_ | If your service's response code is anything other than 2xx, then you can opt to specify an alternative success code. E.g. if you expect your server to return 403, but still want the status indicator to be green, set this value to `403`
**`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

View File

@ -60,18 +60,29 @@ For example, `statusCheckHeaders: { 'X-Custom-Header': 'foobar' }`
## Disabling Security
By default, (if you're using HTTPS) any requests to insecure or non-HTTPS content will be blocked. This will cause the status check to fail. If you trust the endpoint (e.g. you're self-hosting it), then you can disable this security measure for an individual item. This is done by setting `statusCheckAllowInsecure: true`
## Allowing Alternative Status Codes
If you expect your service to return a status code that is not in the 2XX range, and still want the indicator to be green, then you can specify an expected status code under `statusCheckAcceptCodes` for a given item. For example, `statusCheckAcceptCodes: '403,418'`
## Troubleshooting Failing Status Checks
If the status is always returning an error, despite the service being online, then it is most likely an issue with access control, and should be fixed with the correct headers. Hover over the failing status to see the error code and response, in order to know where to start with addressing it.
If your service requires requests to include any authorization in the headers, then use the `statusCheckHeaders` property, as described above.
If you're using status checks, and despite a given service being online, the check is displaying an error, there are a couple of things you can look at:
If your service requires requests to include any authorization in the headers, then use the `statusCheckHeaders` property, as described [above](#setting-custom-headers).
If you are still having issues, it may be because your target application is blocking requests from Dashy's IP. This is a [CORS error](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), and can be fixed by setting the headers on your target app, to include:
```
Access-Control-Allow-Origin: https://[dashy-location]/
Access-Control-Allow-Origin: https://location-of-dashy/
Vary: Origin
```
If the URL you are checking is not using HTTPS, then you may need to disable the rejection of insecure requests. This can be done by setting `statusCheckAllowInsecure` to true for a given item.
If the URL you are checking has an unsigned certificate, or is not using HTTPS, then you may need to disable the rejection of insecure requests. This can be done by setting `statusCheckAllowInsecure` to true for a given item.
If your service is online, but responds with a status code that is not in the 2xx range, then you can use `statusCheckAcceptCodes` to set an accepted status code.
If you get an error, like `Service Unavailable: Server resulted in a fatal error`, even when it's definitely online, this is most likely caused by missing the protocol. Don't forget to include `https://` (or whatever protocol) before the URL, and ensure that if needed, you've specified the port.
Running Dashy in HOST network mode, instead of BRIDGE will allow status check access to other services in HOST mode. For more info, see [#445](https://github.com/Lissy93/dashy/discussions/445).
If you have firewall rules configured, then ensure that they don't prevent Dashy from making requests to the other services you are trying to access.
Currently, the status check needs a page to be rendered, so if this URL in your browser does not return anything, then status checks will not work. This may be modified in the future, but in the meantime, a fix would be to make your own status service, which just checks if your app responds with whatever code you'd like, and then return a 200 plus renders an arbitrary message. Then just point `statusCheckUrl` to your custom page.
For further troubleshooting, use an application like [Postman](https://postman.com) to diagnose the issue. Set the parameter to `GET`, and then make a call to: `https://[url-of-dashy]/status-check/?&url=[service-url]`. Where the service URL must have first been encoded (e.g. with `encodeURIComponent()` or [urlencoder.io](https://www.urlencoder.io/))

View File

@ -209,8 +209,14 @@ Vary: Origin
```
If the URL you are checking has an unsigned certificate, or is not using HTTPS, then you may need to disable the rejection of insecure requests. This can be done by setting `statusCheckAllowInsecure` to true for a given item.
If your service is online, but responds with a status code that is not in the 2xx range, then you can use `statusCheckAcceptCodes` to set an accepted status code.
If you get an error, like `Service Unavailable: Server resulted in a fatal error`, even when it's definitely online, this is most likely caused by missing the protocol. Don't forget to include `https://` (or whatever protocol) before the URL, and ensure that if needed, you've specified the port.
Running Dashy in HOST network mode, instead of BRIDGE will allow status check access to other services in HOST mode. For more info, see [#445](https://github.com/Lissy93/dashy/discussions/445).
If you have firewall rules configured, then ensure that they don't prevent Dashy from making requests to the other services you are trying to access.
Currently, the status check needs a page to be rendered, so if this URL in your browser does not return anything, then status checks will not work. This may be modified in the future, but in the meantime, a fix would be to make your own status service, which just checks if your app responds with whatever code you'd like, and then return a 200 plus renders an arbitrary message. Then just point `statusCheckUrl` to your custom page.
For further troubleshooting, use an application like [Postman](https://postman.com) to diagnose the issue. Set the parameter to `GET`, and then make a call to: `https://[url-of-dashy]/status-check/?&url=[service-url]`. Where the service URL must have first been encoded (e.g. with `encodeURIComponent()` or [urlencoder.io](https://www.urlencoder.io/))

View File

@ -1,6 +1,6 @@
{
"name": "Dashy",
"version": "1.9.9",
"version": "2.0.0",
"license": "MIT",
"main": "server",
"author": "Alicia Sykes <alicia@omg.lol> (https://aliciasykes.com)",
@ -96,4 +96,4 @@
"> 1%",
"last 2 versions"
]
}
}

View File

@ -7,7 +7,8 @@ const axios = require('axios').default;
const https = require('https');
/* Determines if successful from the HTTP response code */
const getResponseType = (code) => {
const getResponseType = (code, validCodes) => {
if (validCodes && String(validCodes).includes(String(code))) return true;
if (Number.isNaN(code)) return false;
const numericCode = parseInt(code, 10);
return (numericCode >= 200 && numericCode <= 302);
@ -27,7 +28,8 @@ const makeErrorMessage2 = (data) => '❌ Service Error - '
+ `${data.status} - ${data.statusText}`;
/* Kicks of a HTTP request, then formats and renders results */
const makeRequest = (url, headers, insecure, render) => {
const makeRequest = (url, headers, insecure, acceptCodes, render) => {
const validCodes = acceptCodes && acceptCodes !== 'null' ? acceptCodes : null;
const startTime = new Date();
const requestMaker = axios.create({
httpsAgent: new https.Agent({
@ -38,22 +40,35 @@ const makeRequest = (url, headers, insecure, render) => {
.then((response) => {
const statusCode = response.status;
const { statusText } = response;
const successStatus = getResponseType(statusCode);
const successStatus = getResponseType(statusCode, validCodes);
const serverName = response.request.socket.servername;
const timeTaken = (new Date() - startTime);
const results = {
statusCode, statusText, serverName, successStatus, timeTaken,
};
const messageText = makeMessageText(results);
results.message = messageText;
results.message = makeMessageText(results);
return results;
})
.catch((error) => {
render(JSON.stringify({
successStatus: false,
message: error.response ? makeErrorMessage2(error.response) : makeErrorMessage(error),
}));
const response = error ? (error.response || {}) : {};
const returnCode = response.status || response.code;
if (validCodes && String(validCodes).includes(returnCode)) { // Success overridden by user
const results = {
successStatus: getResponseType(returnCode, validCodes),
statusCode: returnCode,
statusText: response.statusText,
timeTaken: (new Date() - startTime),
};
results.message = makeMessageText(results);
return results;
} else { // Request failed
return {
successStatus: false,
message: error.response ? makeErrorMessage2(error.response) : makeErrorMessage(error),
};
}
}).then((results) => {
// Request completed (either successfully, or failed) - render results
render(JSON.stringify(results));
});
};
@ -68,19 +83,26 @@ const decodeHeaders = (maybeHeaders) => {
return parsedHeaders;
};
/* Returned if the URL param is not present or correct */
const immediateError = (render) => {
render(JSON.stringify({
successStatus: false,
message: '❌ Missing or Malformed URL',
}));
};
/* Main function, will check if a URL present, and call function */
module.exports = (paramStr, render) => {
if (!paramStr || !paramStr.includes('=')) {
render(JSON.stringify({
success: false,
message: '❌ Malformed URL',
}));
immediateError(render);
} else {
// Prepare the parameters, which are got from the URL
const params = new URLSearchParams(paramStr);
const url = decodeURIComponent(params.get('url'));
const acceptCodes = decodeURIComponent(params.get('acceptCodes'));
const headers = decodeHeaders(params.get('headers'));
const enableInsecure = !!params.get('enableInsecure');
makeRequest(url, headers, enableInsecure, render);
if (!url || url === 'undefined') immediateError(render);
makeRequest(url, headers, enableInsecure, acceptCodes, render);
}
};

View File

@ -226,7 +226,7 @@ export default {
if (newItem.hotkey) newItem.hotkey = parseInt(newItem.hotkey, 10);
const strToTags = (str) => {
const tagArr = str.split(',');
return tagArr.map((tag) => tag.trim().toLowerCase().replace(/[^a-z]+/, ''));
return tagArr.map((tag) => tag.trim().toLowerCase().replace(/[^a-z0-9]+/, ''));
};
const strToBool = (str) => {
if (str === undefined) return undefined;

View File

@ -95,6 +95,7 @@ export default {
statusCheckUrl: String, // Custom URL for status check endpoint
statusCheckInterval: Number, // Num seconds beteween repeating checks
statusCheckAllowInsecure: Boolean, // Status check ignore SSL certs
statusCheckAcceptCodes: String, // Allow status checks to pass with a code other than 200
parentSectionTitle: String, // Title of parent section (for add new)
isAddNew: Boolean, // Only set if 'fake' item used as Add New button
},
@ -236,7 +237,7 @@ export default {
/* Pulls together all user options, returns URL + Get params for ping endpoint */
makeApiUrl() {
const {
url, statusCheckUrl, statusCheckHeaders, statusCheckAllowInsecure,
url, statusCheckUrl, statusCheckHeaders, statusCheckAllowInsecure, statusCheckAcceptCodes,
} = this;
const encode = (str) => encodeURIComponent(str);
this.statusResponse = undefined;
@ -249,8 +250,10 @@ export default {
? `&headers=${encode(JSON.stringify(statusCheckHeaders))}` : '';
// Deterimine if user disabled security
const enableInsecure = statusCheckAllowInsecure ? '&enableInsecure=true' : '';
const acceptCodes = statusCheckAcceptCodes ? `&acceptCodes=${statusCheckAcceptCodes}` : '';
// Construct the full API endpoint's URL with GET params
return `${baseUrl}${serviceEndpoints.statusCheck}/${urlToCheck}${headers}${enableInsecure}`;
return `${baseUrl}${serviceEndpoints.statusCheck}/${urlToCheck}`
+ `${headers}${enableInsecure}${acceptCodes}`;
},
/* Checks if a given service is currently online */
checkWebsiteStatus() {

View File

@ -41,6 +41,7 @@
:enableStatusCheck="item.statusCheck !== undefined ? item.statusCheck : enableStatusCheck"
:statusCheckInterval="statusCheckInterval"
:statusCheckAllowInsecure="item.statusCheckAllowInsecure"
:statusCheckAcceptCodes="item.statusCheckAcceptCodes"
@itemClicked="$emit('itemClicked')"
@triggerModal="triggerModal"
:isAddNew="false"

View File

@ -17,6 +17,8 @@
:itemSize="itemSize"
:hotkey="item.hotkey"
:enableStatusCheck="shouldEnableStatusCheck(item.statusCheck)"
:statusCheckAllowInsecure="item.statusCheckAllowInsecure"
:statusCheckAcceptCodes="item.statusCheckAcceptCodes"
:statusCheckInterval="getStatusCheckInterval()"
@itemClicked="$emit('itemClicked')"
@triggerModal="triggerModal"

View File

@ -33,9 +33,7 @@ export default {
methods: {
/* Make GET request to NetData */
fetchData() {
this.makeRequest(this.endpoint).then(
(response) => { this.processData(response); },
);
this.makeRequest(this.endpoint).then(this.processData);
},
/* Assign data variables to the returned data */
processData(inputData) {

View File

@ -3,7 +3,6 @@
</template>
<script>
import axios from 'axios';
import WidgetMixin from '@/mixins/WidgetMixin';
import ChartingMixin from '@/mixins/ChartingMixin';
@ -34,16 +33,7 @@ export default {
methods: {
/* Make GET request to NetData */
fetchData() {
axios.get(this.endpoint)
.then((response) => {
this.processData(response.data);
})
.catch((dataFetchError) => {
this.error('Unable to fetch data', dataFetchError);
})
.finally(() => {
this.finishLoading();
});
this.makeRequest(this.endpoint).then(this.processData);
},
/* Assign data variables to the returned data */
processData(data) {

View File

@ -36,9 +36,7 @@ export default {
methods: {
/* Make GET request to NetData */
fetchData() {
this.makeRequest(this.endpoint).then(
(response) => { this.processData(response); },
);
this.makeRequest(this.endpoint).then(this.processData);
},
/* Assign data variables to the returned data */
processData(inputData) {

View File

@ -196,7 +196,7 @@
:ref="widgetRef"
/>
<GlNetworkTraffic
v-else-if="widgetType === 'gl-network-activity'"
v-else-if="widgetType === 'gl-network-traffic'"
:options="widgetOptions"
@loading="setLoaderState"
@error="handleError"

View File

@ -758,6 +758,12 @@
"default": false,
"description": "Allows for running status checks on insecure content/ non-HTTPS apps. Prevents checks failing for non-SSL sites"
},
"statusCheckAcceptCodes": {
"title": "Accepted HTTP Status Codes",
"type": "string",
"default": "",
"description": "If your service's response code is anything other than 2xx, then you can opt to specify an alternative success code"
},
"color": {
"title": "Custom Color",
"type": "string",
@ -796,4 +802,4 @@
}
}
}
}
}