mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-27 19:53:36 +00:00
commit
30d5bfe59e
@ -16,7 +16,7 @@
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 2018,
|
||||
"ecmaVersion": 2020,
|
||||
"ecmaFeatures": {
|
||||
"globalReturn": true
|
||||
}
|
||||
|
6
.github/dependabot.yaml
vendored
Normal file
6
.github/dependabot.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
0
.github/stale.yml → .github/stale.yaml
vendored
0
.github/stale.yml → .github/stale.yaml
vendored
@ -9,16 +9,19 @@ on:
|
||||
pull_request:
|
||||
branches: [master, develop]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x, 16.x, 17.x]
|
||||
node-version: [14.x, 16.x, 18.x]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
@ -1,4 +1,5 @@
|
||||
# This workflow runs the automated test and uploads the coverage results to codecov.io
|
||||
# For more information see: https://github.com/codecov/codecov-action
|
||||
|
||||
name: "Run Codecov Tests"
|
||||
|
||||
@ -8,13 +9,16 @@ on:
|
||||
pull_request:
|
||||
branches: [master, develop]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
run-and-upload-coverage-report:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: Install dependencies and run coverage
|
||||
run: |
|
||||
Xvfb :99 -screen 0 1024x768x16 &
|
@ -1,4 +1,5 @@
|
||||
# This workflow enforces the update of a changelog file on every pull request
|
||||
# For more information see: https://github.com/dangoslen/changelog-enforcer
|
||||
|
||||
name: "Enforce Changelog"
|
||||
|
||||
@ -11,10 +12,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Enforce changelog️
|
||||
uses: dangoslen/changelog-enforcer@v2
|
||||
uses: dangoslen/changelog-enforcer@v3
|
||||
with:
|
||||
changeLogPath: "CHANGELOG.md"
|
||||
skipLabels: "Skip Changelog"
|
27
CHANGELOG.md
27
CHANGELOG.md
@ -5,6 +5,28 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror².
|
||||
|
||||
## [2.20.0] - 2022-07-02
|
||||
|
||||
Special thanks to the following contributors: @eouia, @khassel, @kolbyjack, @KristjanESPERANTO, @nathannaveen, @naveensrinivasan, @rejas, @rohitdharavath and @sdetweil.
|
||||
|
||||
### Added
|
||||
|
||||
- Added a new config option `httpHeaders` used by helmet (see https://helmetjs.github.io/). You can now set own httpHeaders which will override the defaults in `js/defauls.js` which is useful e.g. if you want to embed MagicMirror into annother website (solves #2847).
|
||||
- Show endDate for calendar events when dateHeader is enabled and showEnd is set to true (#2192).
|
||||
- Added the notification emitting from the weather module on infromation updated.
|
||||
- Use recommended file extention for YAML files (#2864).
|
||||
|
||||
### Updated
|
||||
|
||||
- Use latest node 18 when running tests on github actions.
|
||||
- Update `electron` to v19 and other dependencies.
|
||||
- Use internal fetch function of node instead external `node-fetch` library if used node version >= `v18`.
|
||||
- Include duplicate events in broadcasts.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix problems with non latin fonds caused by updating to fontsource (fixes #2835).
|
||||
|
||||
## [2.19.0] - 2022-04-01
|
||||
|
||||
Special thanks to the following contributors: @10bias, @CFenner, @JHWelch, @k1rd3rf, @khassel, @kolbyjack, @krekos, @KristjanESPERANTO, @Nerfzooka, @oraclesean, @oscarb, @philnagel, @rejas, @sdetweil, @shin10, @SiderealArt and @Tom-Hirschberger.
|
||||
@ -12,9 +34,9 @@ Special thanks to the following contributors: @10bias, @CFenner, @JHWelch, @k1rd
|
||||
### Added
|
||||
|
||||
- Added a config option under the weather module, `absoluteDates`, providing an option to format weather forecast date output with either absolute or relative dates.
|
||||
- Added test for new weather forecast `absoluteDates` porperty.
|
||||
- Added test for new weather forecast `absoluteDates` property.
|
||||
- The modules get a class hidden added/removed if they get hidden/shown which will also toggle pointer-events.
|
||||
- Added new config option `showTitleAsUrl` to newsfeed module. If set, the diplayed title is a link to the article which is useful when running in a browser and you want to read this article.
|
||||
- Added new config option `showTitleAsUrl` to newsfeed module. If set, the displayed title is a link to the article which is useful when running in a browser and you want to read this article.
|
||||
- Added internal cors proxy to get weather providers working without public proxies (fixes #2714). The new url `http(s)://address:port/cors?url=https://whatever-to-proxy` can be used in other modules too.
|
||||
- Added a WeatherProvider for Weatherflow.
|
||||
- Added new env var `ELECTRON_DISABLE_GPU` which disable gpu under electron if set (fixes #2831).
|
||||
@ -39,6 +61,7 @@ Special thanks to the following contributors: @10bias, @CFenner, @JHWelch, @k1rd
|
||||
- Don't adjust startDate for full day events if endDate is in the past.
|
||||
- Fix windspeed conversion error in openweathermap provider. (#2812)
|
||||
- Fix conflicting parms turning off showEnd for full day events. (#2629)
|
||||
- Fix regression, calendar.maximumEntries not used to filter calendar level entries (#2868)
|
||||
|
||||
## [2.18.0] - 2022-01-01
|
||||
|
||||
|
28
fonts/package-lock.json
generated
28
fonts/package-lock.json
generated
@ -7,31 +7,31 @@
|
||||
"name": "magicmirror-fonts",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "^4.5.5",
|
||||
"@fontsource/roboto-condensed": "^4.5.6"
|
||||
"@fontsource/roboto": "^4.5.7",
|
||||
"@fontsource/roboto-condensed": "^4.5.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@fontsource/roboto": {
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.5.tgz",
|
||||
"integrity": "sha512-Pe1p+gAO6K0aLxBXlLoJRHVx352tVc/v/7DOnvM3t+FYXb+KUga9aCD1NpnDfd0kKnWXqrZyAXguyyFWDDuphw=="
|
||||
"version": "4.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz",
|
||||
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw=="
|
||||
},
|
||||
"node_modules/@fontsource/roboto-condensed": {
|
||||
"version": "4.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.6.tgz",
|
||||
"integrity": "sha512-WDN0RlwXa3ADUDJxrB9HEIhrwYdJFLTNw4YemEYSeIPURU5DAHSx2VFXFv69PbM7kV8At5yMTp8bQkL5TBUP3w=="
|
||||
"version": "4.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.8.tgz",
|
||||
"integrity": "sha512-HCuf1rVSOsXnl/KgHNRLCr8XS/Dunzn10BjhliJiEZ5qPynXCWH4RRBFupIODHamhj2Uyp/iZkSQp574luKp6A=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": {
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.5.tgz",
|
||||
"integrity": "sha512-Pe1p+gAO6K0aLxBXlLoJRHVx352tVc/v/7DOnvM3t+FYXb+KUga9aCD1NpnDfd0kKnWXqrZyAXguyyFWDDuphw=="
|
||||
"version": "4.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz",
|
||||
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw=="
|
||||
},
|
||||
"@fontsource/roboto-condensed": {
|
||||
"version": "4.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.6.tgz",
|
||||
"integrity": "sha512-WDN0RlwXa3ADUDJxrB9HEIhrwYdJFLTNw4YemEYSeIPURU5DAHSx2VFXFv69PbM7kV8At5yMTp8bQkL5TBUP3w=="
|
||||
"version": "4.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-4.5.8.tgz",
|
||||
"integrity": "sha512-HCuf1rVSOsXnl/KgHNRLCr8XS/Dunzn10BjhliJiEZ5qPynXCWH4RRBFupIODHamhj2Uyp/iZkSQp574luKp6A=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
"url": "https://github.com/MichMich/MagicMirror/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "^4.5.5",
|
||||
"@fontsource/roboto-condensed": "^4.5.6"
|
||||
"@fontsource/roboto": "^4.5.7",
|
||||
"@fontsource/roboto-condensed": "^4.5.8"
|
||||
}
|
||||
}
|
||||
|
@ -2,57 +2,54 @@
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
src: local("Roboto Thin"), local("Roboto-Thin"), url("node_modules/@fontsource/roboto/files/roboto-latin-100-normal.woff2") format("woff2"), url("node_modules/@fontsource/roboto/files/roboto-latin-100-normal.woff") format("woff");
|
||||
src: local("Roboto Thin"), local("Roboto-Thin"), url("node_modules/@fontsource/roboto/files/roboto-all-100-normal.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Roboto Condensed";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local("Roboto Condensed Light"), local("RobotoCondensed-Light"), url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-300-normal.woff2") format("woff2"),
|
||||
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-300-normal.woff") format("woff");
|
||||
src: local("Roboto Condensed Light"), local("RobotoCondensed-Light"), url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-all-300-normal.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Roboto Condensed";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local("Roboto Condensed"), local("RobotoCondensed-Regular"), url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-400-normal.woff2") format("woff2"),
|
||||
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-400-normal.woff") format("woff");
|
||||
src: local("Roboto Condensed"), local("RobotoCondensed-Regular"), url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-all-400-normal.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Roboto Condensed";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local("Roboto Condensed Bold"), local("RobotoCondensed-Bold"), url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-700-normal.woff2") format("woff2"),
|
||||
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-700-normal.woff") format("woff");
|
||||
src: local("Roboto Condensed Bold"), local("RobotoCondensed-Bold"), url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-all-700-normal.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local("Roboto"), local("Roboto-Regular"), url("node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff2") format("woff2"), url("node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff") format("woff");
|
||||
src: local("Roboto"), local("Roboto-Regular"), url("node_modules/@fontsource/roboto/files/roboto-all-400-normal.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: local("Roboto Medium"), local("Roboto-Medium"), url("node_modules/@fontsource/roboto/files/roboto-latin-500-normal.woff2") format("woff2"), url("node_modules/@fontsource/roboto/files/roboto-latin-500-normal.woff") format("woff");
|
||||
src: local("Roboto Medium"), local("Roboto-Medium"), url("node_modules/@fontsource/roboto/files/roboto-all-500-normal.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local("Roboto Bold"), local("Roboto-Bold"), url("node_modules/@fontsource/roboto/files/roboto-latin-700-normal.woff2") format("woff2"), url("node_modules/@fontsource/roboto/files/roboto-latin-700-normal.woff") format("woff");
|
||||
src: local("Roboto Bold"), local("Roboto-Bold"), url("node_modules/@fontsource/roboto/files/roboto-all-700-normal.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Roboto;
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local("Roboto Light"), local("Roboto-Light"), url("node_modules/@fontsource/roboto/files/roboto-latin-300-normal.woff2") format("woff2"), url("node_modules/@fontsource/roboto/files/roboto-latin-300-normal.woff") format("woff");
|
||||
src: local("Roboto Light"), local("Roboto-Light"), url("node_modules/@fontsource/roboto/files/roboto-all-300-normal.woff") format("woff");
|
||||
}
|
||||
|
@ -25,6 +25,9 @@ const defaults = {
|
||||
units: "metric",
|
||||
zoom: 1,
|
||||
customCss: "css/custom.css",
|
||||
// httpHeaders used by helmet, see https://helmetjs.github.io/. You can add other/more object values by overriding this in config.js,
|
||||
// e.g. you need to add `frameguard: false` for embedding MagicMirror in another website, see https://github.com/MichMich/MagicMirror/issues/2847
|
||||
httpHeaders: { contentSecurityPolicy: false, crossOriginOpenerPolicy: false, crossOriginEmbedderPolicy: false, crossOriginResourcePolicy: false, originAgentCluster: false },
|
||||
|
||||
modules: [
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ const Log = require("logger");
|
||||
let config = process.env.config ? JSON.parse(process.env.config) : {};
|
||||
// Module to control application life.
|
||||
const app = electron.app;
|
||||
// If ELECTRON_DISABLE_GPU is set electron is startet with --disable-gpu flag.
|
||||
// If ELECTRON_DISABLE_GPU is set electron is started with --disable-gpu flag.
|
||||
// See https://www.electronjs.org/docs/latest/tutorial/offscreen-rendering for more info.
|
||||
if (process.env.ELECTRON_DISABLE_GPU !== undefined) {
|
||||
app.disableHardwareAcceleration();
|
||||
|
20
js/fetch.js
Normal file
20
js/fetch.js
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* fetch
|
||||
*
|
||||
* @param {string} url to be fetched
|
||||
* @param {object} options object e.g. for headers
|
||||
* @class
|
||||
*/
|
||||
async function fetch(url, options) {
|
||||
const nodeVersion = process.version.match(/^v(\d+)\.*/)[1];
|
||||
if (nodeVersion >= 18) {
|
||||
// node version >= 18
|
||||
return global.fetch(url, options);
|
||||
} else {
|
||||
// node version < 18
|
||||
const nodefetch = require("node-fetch");
|
||||
return nodefetch(url, options);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = fetch;
|
@ -10,7 +10,7 @@ const path = require("path");
|
||||
const ipfilter = require("express-ipfilter").IpFilter;
|
||||
const fs = require("fs");
|
||||
const helmet = require("helmet");
|
||||
const fetch = require("node-fetch");
|
||||
const fetch = require("fetch");
|
||||
|
||||
const Log = require("logger");
|
||||
const Utils = require("./utils.js");
|
||||
@ -69,7 +69,7 @@ function Server(config, callback) {
|
||||
res.status(403).send("This device is not allowed to access your mirror. <br> Please check your config.js or config.js.sample to change this.");
|
||||
});
|
||||
});
|
||||
app.use(helmet({ contentSecurityPolicy: false, crossOriginOpenerPolicy: false, crossOriginEmbedderPolicy: false, crossOriginResourcePolicy: false, originAgentCluster: false }));
|
||||
app.use(helmet(config.httpHeaders));
|
||||
|
||||
app.use("/js", express.static(__dirname));
|
||||
|
||||
|
@ -305,6 +305,12 @@ Module.register("calendar", {
|
||||
timeWrapper.className = "time light align-left " + this.timeClassForUrl(event.url);
|
||||
timeWrapper.style.paddingLeft = "2px";
|
||||
timeWrapper.innerHTML = moment(event.startDate, "x").format("LT");
|
||||
|
||||
// Add endDate to dataheaders if showEnd is enabled
|
||||
if (this.config.showEnd) {
|
||||
timeWrapper.innerHTML += " - " + moment(event.endDate, "x").format("LT");
|
||||
}
|
||||
|
||||
eventWrapper.appendChild(timeWrapper);
|
||||
titleWrapper.classList.add("align-right");
|
||||
}
|
||||
@ -490,23 +496,21 @@ Module.register("calendar", {
|
||||
for (const e in calendar) {
|
||||
const event = JSON.parse(JSON.stringify(calendar[e])); // clone object
|
||||
|
||||
if (event.endDate < now && limitNumberOfEntries) {
|
||||
continue;
|
||||
}
|
||||
if (this.config.hidePrivate) {
|
||||
if (event.class === "PRIVATE") {
|
||||
if (this.config.hidePrivate && event.class === "PRIVATE") {
|
||||
// do not add the current event, skip it
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (this.config.hideOngoing && limitNumberOfEntries) {
|
||||
if (event.startDate < now) {
|
||||
if (limitNumberOfEntries) {
|
||||
if (event.endDate < now) {
|
||||
continue;
|
||||
}
|
||||
if (this.config.hideOngoing && event.startDate < now) {
|
||||
continue;
|
||||
}
|
||||
if (this.listContainsEvent(events, event)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
event.url = calendarUrl;
|
||||
event.today = event.startDate >= today && event.startDate < today + 24 * 60 * 60 * 1000;
|
||||
|
||||
|
@ -8,7 +8,7 @@ const CalendarUtils = require("./calendarutils");
|
||||
const Log = require("logger");
|
||||
const NodeHelper = require("node_helper");
|
||||
const ical = require("node-ical");
|
||||
const fetch = require("node-fetch");
|
||||
const fetch = require("fetch");
|
||||
const digest = require("digest-fetch");
|
||||
const https = require("https");
|
||||
|
||||
|
@ -498,7 +498,8 @@ const CalendarUtils = {
|
||||
return a.startDate - b.startDate;
|
||||
});
|
||||
|
||||
return newEvents;
|
||||
let maxEvents = newEvents.slice(0, config.maximumEntries);
|
||||
return maxEvents;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -7,8 +7,9 @@
|
||||
const Log = require("logger");
|
||||
const FeedMe = require("feedme");
|
||||
const NodeHelper = require("node_helper");
|
||||
const fetch = require("node-fetch");
|
||||
const fetch = require("fetch");
|
||||
const iconv = require("iconv-lite");
|
||||
const stream = require("stream");
|
||||
|
||||
/**
|
||||
* Responsible for requesting an update on the set interval and broadcasting the data.
|
||||
@ -87,7 +88,13 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
|
||||
fetch(url, { headers: headers })
|
||||
.then(NodeHelper.checkFetchStatus)
|
||||
.then((response) => {
|
||||
response.body.pipe(iconv.decodeStream(encoding)).pipe(parser);
|
||||
let nodeStream;
|
||||
if (response.body instanceof stream.Readable) {
|
||||
nodeStream = response.body;
|
||||
} else {
|
||||
nodeStream = stream.Readable.fromWeb(response.body);
|
||||
}
|
||||
nodeStream.pipe(iconv.decodeStream(encoding)).pipe(parser);
|
||||
})
|
||||
.catch((error) => {
|
||||
fetchFailedCallback(this, error);
|
||||
|
@ -154,6 +154,15 @@ Module.register("weather", {
|
||||
if (this.weatherProvider.currentWeather()) {
|
||||
this.sendNotification("CURRENTWEATHER_TYPE", { type: this.weatherProvider.currentWeather().weatherType.replace("-", "_") });
|
||||
}
|
||||
|
||||
const notificationPayload = {
|
||||
currentWeather: this.weatherProvider?.currentWeatherObject?.simpleClone() ?? null,
|
||||
forecastArray: this.weatherProvider?.weatherForecastArray?.map((ar) => ar.simpleClone()) ?? [],
|
||||
hourlyArray: this.weatherProvider?.weatherHourlyArray?.map((ar) => ar.simpleClone()) ?? [],
|
||||
locationName: this.weatherProvider?.fetchedLocationName,
|
||||
providerName: this.weatherProvider.providerName
|
||||
};
|
||||
this.sendNotification("WEATHER_UPDATED", notificationPayload);
|
||||
},
|
||||
|
||||
scheduleUpdate: function (delay = null) {
|
||||
|
@ -146,6 +146,23 @@ class WeatherObject {
|
||||
this.sunrise = moment(times.sunrise, "X");
|
||||
this.sunset = moment(times.sunset, "X");
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone to simple object to prevent mutating and deprecation of legacy library.
|
||||
*
|
||||
* Before being handed to other modules, mutable values must be cloned safely.
|
||||
* Especially 'moment' object is not immutable, so original 'date', 'sunrise', 'sunset' could be corrupted or changed by other modules.
|
||||
*
|
||||
* @returns {object} plained object clone of original weatherObject
|
||||
*/
|
||||
simpleClone() {
|
||||
const toFlat = ["date", "sunrise", "sunset"];
|
||||
let clone = { ...this };
|
||||
for (const prop of toFlat) {
|
||||
clone[prop] = clone?.[prop]?.valueOf() ?? clone?.[prop];
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
|
5197
package-lock.json
generated
5197
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
41
package.json
41
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "magicmirror",
|
||||
"version": "2.19.0",
|
||||
"version": "2.20.0",
|
||||
"description": "The open source modular smart mirror platform.",
|
||||
"main": "js/electron.js",
|
||||
"scripts": {
|
||||
@ -48,48 +48,49 @@
|
||||
"homepage": "https://magicmirror.builders",
|
||||
"devDependencies": {
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^26.1.3",
|
||||
"eslint-plugin-jsdoc": "^38.1.3",
|
||||
"eslint-plugin-jest": "^26.5.3",
|
||||
"eslint-plugin-jsdoc": "^39.3.3",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"husky": "^7.0.4",
|
||||
"jest": "^27.5.1",
|
||||
"jsdom": "^19.0.0",
|
||||
"husky": "^8.0.1",
|
||||
"jest": "^28.1.1",
|
||||
"jsdom": "^20.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"nyc": "^15.1.0",
|
||||
"playwright": "^1.20.1",
|
||||
"prettier": "^2.6.1",
|
||||
"playwright": "^1.22.2",
|
||||
"prettier": "^2.7.1",
|
||||
"pretty-quick": "^3.1.3",
|
||||
"sinon": "^13.0.1",
|
||||
"stylelint": "^14.6.1",
|
||||
"sinon": "^14.0.0",
|
||||
"stylelint": "^14.9.1",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-standard": "^25.0.0",
|
||||
"stylelint-config-standard": "^26.0.0",
|
||||
"stylelint-prettier": "^2.0.0",
|
||||
"suncalc": "^1.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"electron": "^17.2.0"
|
||||
"electron": "^19.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"colors": "^1.4.0",
|
||||
"console-stamp": "^3.0.4",
|
||||
"console-stamp": "^3.0.6",
|
||||
"digest-fetch": "^1.2.1",
|
||||
"eslint": "^8.12.0",
|
||||
"express": "^4.17.3",
|
||||
"eslint": "^8.18.0",
|
||||
"express": "^4.18.1",
|
||||
"express-ipfilter": "^1.2.0",
|
||||
"feedme": "^2.0.2",
|
||||
"helmet": "^5.0.2",
|
||||
"helmet": "^5.1.0",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"luxon": "^1.21.3",
|
||||
"luxon": "^1.28.0",
|
||||
"module-alias": "^2.2.2",
|
||||
"moment": "^2.29.1",
|
||||
"moment": "^2.29.3",
|
||||
"node-fetch": "^2.6.7",
|
||||
"node-ical": "^0.15.1",
|
||||
"socket.io": "^4.4.1"
|
||||
"socket.io": "^4.5.1"
|
||||
},
|
||||
"_moduleAliases": {
|
||||
"node_helper": "js/node_helper.js",
|
||||
"logger": "js/logger.js"
|
||||
"logger": "js/logger.js",
|
||||
"fetch": "js/fetch.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
|
@ -1,4 +1,4 @@
|
||||
const fetch = require("node-fetch");
|
||||
const fetch = require("fetch");
|
||||
const helpers = require("./global-setup");
|
||||
|
||||
describe("App environment", function () {
|
||||
@ -6,8 +6,8 @@ describe("App environment", function () {
|
||||
helpers.startApplication("tests/configs/default.js");
|
||||
helpers.getDocument(done);
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
it("get request from http://localhost:8080 should return 200", function (done) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
const fetch = require("node-fetch");
|
||||
const fetch = require("fetch");
|
||||
const helpers = require("./global-setup");
|
||||
|
||||
describe("All font files from roboto.css should be downloadable", function () {
|
||||
@ -17,8 +17,8 @@ describe("All font files from roboto.css should be downloadable", function () {
|
||||
beforeAll(function () {
|
||||
helpers.startApplication("tests/configs/without_modules.js");
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
test.each(fontFiles)("should return 200 HTTP code for file '%s'", (fontFile, done) => {
|
||||
|
@ -2,9 +2,7 @@ const jsdom = require("jsdom");
|
||||
|
||||
exports.startApplication = function (configFilename, exec) {
|
||||
jest.resetModules();
|
||||
if (global.app) {
|
||||
global.app.stop();
|
||||
}
|
||||
this.stopApplication();
|
||||
// Set config sample for use in test
|
||||
if (configFilename === "") {
|
||||
process.env.MM_CONFIG_FILE = "config/config.js";
|
||||
@ -16,10 +14,11 @@ exports.startApplication = function (configFilename, exec) {
|
||||
global.app.start();
|
||||
};
|
||||
|
||||
exports.stopApplication = function () {
|
||||
exports.stopApplication = async function () {
|
||||
if (global.app) {
|
||||
global.app.stop();
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
};
|
||||
|
||||
exports.getDocument = function (callback) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
const fetch = require("node-fetch");
|
||||
const fetch = require("fetch");
|
||||
const helpers = require("./global-setup");
|
||||
|
||||
describe("ipWhitelist directive configuration", function () {
|
||||
@ -6,8 +6,8 @@ describe("ipWhitelist directive configuration", function () {
|
||||
beforeAll(function () {
|
||||
helpers.startApplication("tests/configs/noIpWhiteList.js");
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
it("should return 403", function (done) {
|
||||
@ -22,8 +22,8 @@ describe("ipWhitelist directive configuration", function () {
|
||||
beforeAll(function () {
|
||||
helpers.startApplication("tests/configs/empty_ipWhiteList.js");
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
it("should return 200", function (done) {
|
||||
|
@ -5,8 +5,8 @@ describe("Alert module", function () {
|
||||
helpers.startApplication("tests/configs/modules/alert/default.js");
|
||||
helpers.getDocument(done);
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
it("should show the welcome message", function () {
|
||||
|
@ -25,8 +25,8 @@ describe("Calendar module", function () {
|
||||
});
|
||||
};
|
||||
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
describe("Default configuration", function () {
|
||||
|
@ -1,8 +1,8 @@
|
||||
const helpers = require("../global-setup");
|
||||
|
||||
describe("Clock set to spanish language module", function () {
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
const testMatch = function (element, regex) {
|
||||
|
@ -2,8 +2,8 @@ const helpers = require("../global-setup");
|
||||
const moment = require("moment");
|
||||
|
||||
describe("Clock module", function () {
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
const testMatch = function (element, regex) {
|
||||
|
@ -16,8 +16,8 @@ function doTest(complimentsArray) {
|
||||
}
|
||||
|
||||
describe("Compliments module", function () {
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
describe("parts of days", function () {
|
||||
|
@ -1,8 +1,8 @@
|
||||
const helpers = require("../global-setup");
|
||||
|
||||
describe("Test helloworld module", function () {
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
describe("helloworld set config text", function () {
|
||||
|
@ -1,8 +1,8 @@
|
||||
const helpers = require("../global-setup");
|
||||
|
||||
describe("Newsfeed module", function () {
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
describe("Default configuration", function () {
|
||||
|
@ -40,8 +40,8 @@ describe("Weather module", function () {
|
||||
helpers.getDocument(callback);
|
||||
}
|
||||
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
describe("Current weather", function () {
|
||||
|
@ -5,8 +5,8 @@ describe("Display of modules", function () {
|
||||
helpers.startApplication("tests/configs/modules/display.js");
|
||||
helpers.getDocument(done);
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
it("should show the test header", function () {
|
||||
|
@ -5,8 +5,8 @@ describe("Position of modules", function () {
|
||||
helpers.startApplication("tests/configs/modules/positions.js");
|
||||
helpers.getDocument(done);
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
const positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"];
|
||||
|
@ -1,4 +1,4 @@
|
||||
const fetch = require("node-fetch");
|
||||
const fetch = require("fetch");
|
||||
const helpers = require("./global-setup");
|
||||
|
||||
describe("port directive configuration", function () {
|
||||
@ -6,8 +6,8 @@ describe("port directive configuration", function () {
|
||||
beforeAll(function () {
|
||||
helpers.startApplication("tests/configs/port_8090.js");
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
it("should return 200", function (done) {
|
||||
@ -22,8 +22,8 @@ describe("port directive configuration", function () {
|
||||
beforeAll(function () {
|
||||
helpers.startApplication("tests/configs/port_8090.js", (process.env.MM_PORT = 8100));
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
it("should return 200", function (done) {
|
||||
|
@ -1,12 +1,12 @@
|
||||
const fetch = require("node-fetch");
|
||||
const fetch = require("fetch");
|
||||
const helpers = require("./global-setup");
|
||||
|
||||
describe("Vendors", function () {
|
||||
beforeAll(function () {
|
||||
helpers.startApplication("tests/configs/default.js");
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
describe("Get list vendors", function () {
|
||||
|
@ -5,8 +5,8 @@ describe("Check configuration without modules", function () {
|
||||
helpers.startApplication("tests/configs/without_modules.js");
|
||||
helpers.getDocument(done);
|
||||
});
|
||||
afterAll(function () {
|
||||
helpers.stopApplication();
|
||||
afterAll(async function () {
|
||||
await helpers.stopApplication();
|
||||
});
|
||||
|
||||
it("Show the message MagicMirror² title", function () {
|
||||
|
14
vendor/package-lock.json
generated
vendored
14
vendor/package-lock.json
generated
vendored
@ -8,7 +8,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||
"moment": "^2.29.1",
|
||||
"moment": "^2.29.3",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"nunjucks": "^3.2.3",
|
||||
"suncalc": "^1.9.0",
|
||||
@ -43,9 +43,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
|
||||
"version": "2.29.3",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
|
||||
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
@ -118,9 +118,9 @@
|
||||
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
||||
"version": "2.29.3",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
|
||||
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw=="
|
||||
},
|
||||
"moment-timezone": {
|
||||
"version": "0.5.34",
|
||||
|
2
vendor/package.json
vendored
2
vendor/package.json
vendored
@ -11,7 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||
"moment": "^2.29.1",
|
||||
"moment": "^2.29.3",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"nunjucks": "^3.2.3",
|
||||
"suncalc": "^1.9.0",
|
||||
|
Loading…
x
Reference in New Issue
Block a user