diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..96c36f5
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,4 @@
+{
+ "singleQuote": true,
+ "tabWidth": 4
+}
diff --git a/README.md b/README.md
index 7a6e6f1..314be84 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Dashboard
-![screenshot](screenshot.png "screenshot")
+![screenshot](screenshot.png 'screenshot')
Dashboard is just that - a dashboard. It's inspired by [SUI](https://github.com/jeroenpardon/sui) and has all the same features as SUI, such as simple customization through JSON-files and a handy search bar to search the internet more efficiently.
@@ -8,9 +8,9 @@ Dashboard is just that - a dashboard. It's inspired by [SUI](https://github.com/
So what makes this thing better than SUI?
-- "Display URL" functionality, in case the URL you want to show is different than the URL you want to be redirected to
-- Theming through JSON
-- Search providers customizable through JSON (SUI has them both in a JSON and hardcoded)
+- "Display URL" functionality, in case the URL you want to show is different than the URL you want to be redirected to
+- Theming through JSON
+- Search providers customizable through JSON (SUI has them both in a JSON and hardcoded)
## Installation
@@ -26,7 +26,8 @@ To get Dashboard to run, just clone the repository, download the dependencies us
git clone https://github.com/phntxx/dashboard.git
cd dashboard
yarn
-yarn start
+yarn build
+yarn serve:production
```
alternatively, if you want to work using static files (requires a rebuild for
diff --git a/data/apps.json b/data/apps.json
new file mode 100644
index 0000000..d0c3fdc
--- /dev/null
+++ b/data/apps.json
@@ -0,0 +1,58 @@
+{
+ "apps": [
+ {
+ "name": "my pi hole",
+ "displayURL": "example.com",
+ "URL": "https://example.com",
+ "icon": "vpn_lock"
+ },
+ {
+ "name": "Plex",
+ "displayURL": "example.com",
+ "URL": "https://example.com",
+ "icon": "tv"
+ },
+ {
+ "name": "NextCloud",
+ "displayURL": "example.com",
+ "URL": "https://example.com",
+ "icon": "filter_drama"
+ },
+ {
+ "name": "Ghost",
+ "displayURL": "example.com",
+ "URL": "https://example.com",
+ "icon": "rss_feed"
+ },
+ {
+ "name": "Minecraft",
+ "displayURL": "example.com",
+ "URL": "https://example.com",
+ "icon": "games"
+ },
+ {
+ "name": "pfSense",
+ "displayURL": "example.com",
+ "URL": "https://example.com",
+ "icon": "security"
+ },
+ {
+ "name": "ESXi",
+ "displayURL": "example.com",
+ "URL": "https://example.com",
+ "icon": "dns"
+ },
+ {
+ "name": "Tautulli",
+ "displayURL": "example.com",
+ "URL": "https://example.com",
+ "icon": "bar_chart"
+ },
+ {
+ "name": "Grafana",
+ "displayURL": "example.com",
+ "URL": "https://example.com",
+ "icon": "show_chart"
+ }
+ ]
+}
diff --git a/package.json b/package.json
index 02ad091..50121ff 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
+ "http-server": "^0.12.3",
"material-icons-react": "^1.0.4",
"react": "^16.13.1",
"react-dom": "^16.13.1",
@@ -14,8 +15,12 @@
"styled-components": "^5.1.0"
},
"scripts": {
+ "serveAppData": "http-server ./data -c-1",
+ "serveProductionApp": "http-server ./build --proxy http://localhost:8080 --port 3000",
"start": "react-scripts start",
"build": "react-scripts build",
+ "serve:dev": "npm-run-all --parallel serveAppData start",
+ "serve:production": "npm-run-all --parallel serveAppData serveProductionApp",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
@@ -33,5 +38,8 @@
"last 1 firefox version",
"last 1 safari version"
]
+ },
+ "devDependencies": {
+ "npm-run-all": "^4.1.5"
}
}
diff --git a/src/App.js b/src/App.js
index a16d350..2cbca25 100644
--- a/src/App.js
+++ b/src/App.js
@@ -16,22 +16,22 @@ const GlobalStyle = createGlobalStyle`
`;
const AppContainer = styled.div`
- max-width: 80%;
- margin: auto;
- padding: 10px;
+ max-width: 80%;
+ margin: auto;
+ padding: 10px;
`;
const App = () => (
- <>
-
-
-
-
-
-
-
-
- >
+ <>
+
+
+
+
+
+
+
+
+ >
);
export default App;
diff --git a/src/components/appList.js b/src/components/appList.js
index f8a96c1..1e66f24 100644
--- a/src/components/appList.js
+++ b/src/components/appList.js
@@ -43,25 +43,69 @@ const App = styled.div`
padding: 1rem;
`;
-const appList = () => (
-
- Applications
-
- {appData.apps.map((app, index) => (
- -
-
-
-
-
-
- {app.name}
- {app.displayURL}
-
-
-
- ))}
-
-
-);
+const ErrorMessage = styled.p`
+ color: red;
+`;
-export default appList;
+function handleResponse(response) {
+ if (response.ok) {
+ return response.json();
+ }
+ throw new Error('Failed to load app data.');
+}
+
+function useAppData() {
+ const [appData, setAppData] = useState({ apps: [], error: false });
+ const fetchAppData = useCallback(() => {
+ (process.env.NODE_ENV === 'production'
+ ? fetch('/apps.json').then(handleResponse)
+ : import('./data/apps.json')
+ )
+ .then((jsonResponse) => {
+ setAppData({ ...jsonResponse, error: false });
+ })
+ .catch((error) => {
+ setAppData({ apps: [], error: error.message });
+ });
+ }, []);
+ useEffect(() => {
+ fetchAppData();
+ }, [fetchAppData]);
+ return { appData, fetchAppData };
+}
+
+const AppList = () => {
+ const {
+ appData: { apps, error },
+ fetchAppData,
+ } = useAppData();
+ return (
+
+
+ Applications
+
+
+ {error && {error}}
+ {apps.map((app, idx) => {
+ const { name } = app;
+ return (
+
+
+
+
+
+ {app.name}
+ {app.displayURL}
+
+
+ );
+ })}
+
+
+ );
+};
+
+export default AppList;
\ No newline at end of file
diff --git a/src/components/bookmarkList.js b/src/components/bookmarkList.js
index e08ce6f..7a1f9c2 100644
--- a/src/components/bookmarkList.js
+++ b/src/components/bookmarkList.js
@@ -34,20 +34,20 @@ const bookmarkList = () => (
Bookmarks
- {bookmarkData.groups.map((group, index) => (
- -
+ {bookmarkData.groups.map(({ name, items }) => (
+
-
- {group.name}
- {group.items.map(link => (
-
- {link.name}
+ {name}
+ {group.items.map(({ url, name: linkName }) => (
+
+ {linkName}
))}
- ))}
+ ))}
);
-export default bookmarkList;
+export default bookmarkList;
\ No newline at end of file
diff --git a/src/components/button.js b/src/components/button.js
new file mode 100644
index 0000000..7a01bd5
--- /dev/null
+++ b/src/components/button.js
@@ -0,0 +1,13 @@
+import styled from 'styled-components';
+import { selectedTheme } from '../selectedTheme';
+
+export const Button = styled.button`
+ font-family: Roboto, sans-serif;
+ text-transform: uppercase;
+ font-weight: 400;
+ border: 1px solid ${selectedTheme.mainColor};
+ color: ${selectedTheme.mainColor};
+ background: none;
+ margin-left: 1rem;
+ min-height: 3em;
+`;
diff --git a/src/components/data/apps.json b/src/components/data/apps.json
index 24d20cc..1f0184d 100644
--- a/src/components/data/apps.json
+++ b/src/components/data/apps.json
@@ -55,4 +55,4 @@
"icon": "show_chart"
}
]
-}
\ No newline at end of file
+}
diff --git a/src/components/data/bookmarks.json b/src/components/data/bookmarks.json
index abf8d55..ac8e00c 100644
--- a/src/components/data/bookmarks.json
+++ b/src/components/data/bookmarks.json
@@ -95,4 +95,4 @@
]
}
]
-}
\ No newline at end of file
+}
diff --git a/src/components/data/search.json b/src/components/data/search.json
index 243b18e..61a82eb 100644
--- a/src/components/data/search.json
+++ b/src/components/data/search.json
@@ -1,64 +1,64 @@
{
- "providers":[
- {
- "name":"Allmusic",
- "url":"https://www.allmusic.com/search/all/",
- "prefix":"/a"
- },
- {
- "name":"Discogs",
- "url":"https://www.discogs.com/search/?q=",
- "prefix":"/di"
- },
- {
- "name":"Duck Duck Go",
- "url":"https://duckduckgo.com/?q=",
- "prefix":"/d"
- },
- {
- "name":"iMDB",
- "url":"https://www.imdb.com/find?q=",
- "prefix":"/i"
- },
- {
- "name":"TheMovieDB",
- "url":"https://www.themoviedb.org/search?query=",
- "prefix":"/m"
- },
- {
- "name":"Reddit",
- "url":"https://www.reddit.com/search?q=",
- "prefix":"/r"
- },
- {
- "name":"Qwant",
- "url":"https://www.qwant.com/?q=",
- "prefix":"/q"
- },
- {
- "name":"Soundcloud",
- "url":"https://soundcloud.com/search?q=",
- "prefix":"/so"
- },
- {
- "name":"Spotify",
- "url":"https://open.spotify.com/search/results/",
- "prefix":"/s"
- },
- {
- "name":"TheTVDB",
- "url":"https://www.thetvdb.com/search?q=",
- "prefix":"/tv"
- },
- {
- "name":"Trakt",
- "url":"https://trakt.tv/search?query=",
- "prefix":"/t"
- },
- {
- "name": "YouTube",
- "url": "https://youtube.com/results?search_query=",
- "prefix":"/yt"
- }
+ "providers": [
+ {
+ "name": "Allmusic",
+ "url": "https://www.allmusic.com/search/all/",
+ "prefix": "/a"
+ },
+ {
+ "name": "Discogs",
+ "url": "https://www.discogs.com/search/?q=",
+ "prefix": "/di"
+ },
+ {
+ "name": "Duck Duck Go",
+ "url": "https://duckduckgo.com/?q=",
+ "prefix": "/d"
+ },
+ {
+ "name": "iMDB",
+ "url": "https://www.imdb.com/find?q=",
+ "prefix": "/i"
+ },
+ {
+ "name": "TheMovieDB",
+ "url": "https://www.themoviedb.org/search?query=",
+ "prefix": "/m"
+ },
+ {
+ "name": "Reddit",
+ "url": "https://www.reddit.com/search?q=",
+ "prefix": "/r"
+ },
+ {
+ "name": "Qwant",
+ "url": "https://www.qwant.com/?q=",
+ "prefix": "/q"
+ },
+ {
+ "name": "Soundcloud",
+ "url": "https://soundcloud.com/search?q=",
+ "prefix": "/so"
+ },
+ {
+ "name": "Spotify",
+ "url": "https://open.spotify.com/search/results/",
+ "prefix": "/s"
+ },
+ {
+ "name": "TheTVDB",
+ "url": "https://www.thetvdb.com/search?q=",
+ "prefix": "/tv"
+ },
+ {
+ "name": "Trakt",
+ "url": "https://trakt.tv/search?query=",
+ "prefix": "/t"
+ },
+ {
+ "name": "YouTube",
+ "url": "https://youtube.com/results?search_query=",
+ "prefix": "/yt"
+ }
]
- }
\ No newline at end of file
+}
diff --git a/src/components/data/themes.json b/src/components/data/themes.json
index c6462a5..10a5543 100644
--- a/src/components/data/themes.json
+++ b/src/components/data/themes.json
@@ -22,4 +22,4 @@
"backgroundColor": "#ffffff"
}
]
-}
\ No newline at end of file
+}
diff --git a/src/components/greeter.js b/src/components/greeter.js
index a791a1f..65d9377 100644
--- a/src/components/greeter.js
+++ b/src/components/greeter.js
@@ -25,73 +25,76 @@ const DateText = styled.h3`
`;
const getGreeting = () => {
- // Maybe add some expandability for different greetings?
- return "Hello World!";
+ // Maybe add some expandability for different greetings?
+ return 'Hello World!';
};
-const getExtension = day => {
- let extension = "";
+const getExtension = (day) => {
+ let extension = '';
- if ((day > 4 && day <= 20) || (day > 20 && day % 10 >= 4)) {
- extension = "th";
- } else if (day % 10 === 1) {
- extension = "st";
- } else if (day % 10 === 2) {
- extension = "nd";
- } else if (day % 10 === 3) {
- extension = "rd";
- }
+ if ((day > 4 && day <= 20) || (day > 20 && day % 10 >= 4)) {
+ extension = 'th';
+ } else if (day % 10 === 1) {
+ extension = 'st';
+ } else if (day % 10 === 2) {
+ extension = 'nd';
+ } else if (day % 10 === 3) {
+ extension = 'rd';
+ }
- return extension;
+ return extension;
};
+const monthNames = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December',
+];
+
+const weekDayNames = [
+ 'Sunday',
+ 'Monday',
+ 'Tuesday',
+ 'Wednesday',
+ 'Thursday',
+ 'Friday',
+ 'Saturday',
+];
+
const getDateString = () => {
- let currentDate = new Date();
- const monthNames = [
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December"
- ];
- const weekDayNames = [
- "Sunday",
- "Monday",
- "Tuesday",
- "Wednesday",
- "Thursday",
- "Friday",
- "Saturday"
- ];
- return (
- weekDayNames[currentDate.getUTCDay()] +
- ", " +
- monthNames[currentDate.getUTCMonth()] +
- " " +
- currentDate.getDate() +
- getExtension(currentDate.getDate()) +
- " " +
- currentDate.getFullYear()
- );
+ let currentDate = new Date();
+
+ return (
+ weekDayNames[currentDate.getUTCDay()] +
+ ', ' +
+ monthNames[currentDate.getUTCMonth()] +
+ ' ' +
+ currentDate.getDate() +
+ getExtension(currentDate.getDate()) +
+ ' ' +
+ currentDate.getFullYear()
+ );
};
-const greeter = () => {
- let date = getDateString();
- let greeting = getGreeting();
+const Greeter = () => {
+ let date = getDateString();
+ let greeting = getGreeting();
- return (
-
- {date}
- {greeting}
-
- );
+ return (
+
+ {date}
+ {greeting}
+
+ );
};
-export default greeter;
+export default Greeter;
\ No newline at end of file
diff --git a/src/components/settingsModal.js b/src/components/settingsModal.js
index 5922501..410fb35 100644
--- a/src/components/settingsModal.js
+++ b/src/components/settingsModal.js
@@ -4,10 +4,11 @@ import styled from "styled-components";
import Select from "react-select";
-import searchData from "./data/search.json";
-import themeData from "./data/themes.json";
+import searchData from './data/search.json';
+import themeData from './data/themes.json';
import selectedTheme, { setTheme } from "./themeManager";
+import { Button } from './button';
const ModalButton = styled.button`
float: right;
@@ -43,16 +44,6 @@ const FormContainer = styled.div`
flex-wrap: nowrap;
`;
-const ApplyButton = styled.button`
- font-family: Roboto, sans-serif;
- text-transform: uppercase;
- font-weight: 400;
- border: 1px solid ${selectedTheme.mainColor};
- color: ${selectedTheme.mainColor};
- background: none;
- margin-left: 1rem;
-`;
-
const Headline = styled.h3`
font-family: Roboto, sans-serif;
font-weight: 900;
@@ -150,9 +141,9 @@ const SettingsModal = () => {
}}
styles={SelectorStyle}
/>
- setTheme(JSON.stringify(newTheme))}>
+
+
diff --git a/src/index.js b/src/index.js
index 4146d1d..2b64cb7 100644
--- a/src/index.js
+++ b/src/index.js
@@ -4,10 +4,10 @@ import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
-
-
- ,
- document.getElementById('root')
+
+
+ ,
+ document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
diff --git a/src/selectedTheme.js b/src/selectedTheme.js
new file mode 100644
index 0000000..3655f75
--- /dev/null
+++ b/src/selectedTheme.js
@@ -0,0 +1,5 @@
+import themeData from './components/data/themes.json';
+
+export const selectedTheme = localStorage.getItem('theme')
+ ? JSON.parse(localStorage.getItem('theme'))
+ : themeData.themes[0];
diff --git a/src/serviceWorker.js b/src/serviceWorker.js
index b04b771..3aa8a6a 100644
--- a/src/serviceWorker.js
+++ b/src/serviceWorker.js
@@ -11,131 +11,132 @@
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
- window.location.hostname === 'localhost' ||
- // [::1] is the IPv6 localhost address.
- window.location.hostname === '[::1]' ||
- // 127.0.0.0/8 are considered localhost for IPv4.
- window.location.hostname.match(
- /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
- )
+ window.location.hostname === 'localhost' ||
+ // [::1] is the IPv6 localhost address.
+ window.location.hostname === '[::1]' ||
+ // 127.0.0.0/8 are considered localhost for IPv4.
+ window.location.hostname.match(
+ /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
+ )
);
export function register(config) {
- if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
- // The URL constructor is available in all browsers that support SW.
- const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
- if (publicUrl.origin !== window.location.origin) {
- // Our service worker won't work if PUBLIC_URL is on a different origin
- // from what our page is served on. This might happen if a CDN is used to
- // serve assets; see https://github.com/facebook/create-react-app/issues/2374
- return;
- }
+ if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
+ // The URL constructor is available in all browsers that support SW.
+ const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
+ if (publicUrl.origin !== window.location.origin) {
+ // Our service worker won't work if PUBLIC_URL is on a different origin
+ // from what our page is served on. This might happen if a CDN is used to
+ // serve assets; see https://github.com/facebook/create-react-app/issues/2374
+ return;
+ }
- window.addEventListener('load', () => {
- const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
+ window.addEventListener('load', () => {
+ const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
- if (isLocalhost) {
- // This is running on localhost. Let's check if a service worker still exists or not.
- checkValidServiceWorker(swUrl, config);
+ if (isLocalhost) {
+ // This is running on localhost. Let's check if a service worker still exists or not.
+ checkValidServiceWorker(swUrl, config);
- // Add some additional logging to localhost, pointing developers to the
- // service worker/PWA documentation.
- navigator.serviceWorker.ready.then(() => {
- console.log(
- 'This web app is being served cache-first by a service ' +
- 'worker. To learn more, visit https://bit.ly/CRA-PWA'
- );
+ // Add some additional logging to localhost, pointing developers to the
+ // service worker/PWA documentation.
+ navigator.serviceWorker.ready.then(() => {
+ console.log(
+ 'This web app is being served cache-first by a service ' +
+ 'worker. To learn more, visit https://bit.ly/CRA-PWA'
+ );
+ });
+ } else {
+ // Is not localhost. Just register service worker
+ registerValidSW(swUrl, config);
+ }
});
- } else {
- // Is not localhost. Just register service worker
- registerValidSW(swUrl, config);
- }
- });
- }
+ }
}
function registerValidSW(swUrl, config) {
- navigator.serviceWorker
- .register(swUrl)
- .then(registration => {
- registration.onupdatefound = () => {
- const installingWorker = registration.installing;
- if (installingWorker == null) {
- return;
- }
- installingWorker.onstatechange = () => {
- if (installingWorker.state === 'installed') {
- if (navigator.serviceWorker.controller) {
- // At this point, the updated precached content has been fetched,
- // but the previous service worker will still serve the older
- // content until all client tabs are closed.
- console.log(
- 'New content is available and will be used when all ' +
- 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
- );
+ navigator.serviceWorker
+ .register(swUrl)
+ .then((registration) => {
+ registration.onupdatefound = () => {
+ const installingWorker = registration.installing;
+ if (installingWorker == null) {
+ return;
+ }
+ installingWorker.onstatechange = () => {
+ if (installingWorker.state === 'installed') {
+ if (navigator.serviceWorker.controller) {
+ // At this point, the updated precached content has been fetched,
+ // but the previous service worker will still serve the older
+ // content until all client tabs are closed.
+ console.log(
+ 'New content is available and will be used when all ' +
+ 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
+ );
- // Execute callback
- if (config && config.onUpdate) {
- config.onUpdate(registration);
- }
- } else {
- // At this point, everything has been precached.
- // It's the perfect time to display a
- // "Content is cached for offline use." message.
- console.log('Content is cached for offline use.');
+ // Execute callback
+ if (config && config.onUpdate) {
+ config.onUpdate(registration);
+ }
+ } else {
+ // At this point, everything has been precached.
+ // It's the perfect time to display a
+ // "Content is cached for offline use." message.
+ console.log('Content is cached for offline use.');
- // Execute callback
- if (config && config.onSuccess) {
- config.onSuccess(registration);
- }
- }
- }
- };
- };
- })
- .catch(error => {
- console.error('Error during service worker registration:', error);
- });
+ // Execute callback
+ if (config && config.onSuccess) {
+ config.onSuccess(registration);
+ }
+ }
+ }
+ };
+ };
+ })
+ .catch((error) => {
+ console.error('Error during service worker registration:', error);
+ });
}
function checkValidServiceWorker(swUrl, config) {
- // Check if the service worker can be found. If it can't reload the page.
- fetch(swUrl, {
- headers: { 'Service-Worker': 'script' },
- })
- .then(response => {
- // Ensure service worker exists, and that we really are getting a JS file.
- const contentType = response.headers.get('content-type');
- if (
- response.status === 404 ||
- (contentType != null && contentType.indexOf('javascript') === -1)
- ) {
- // No service worker found. Probably a different app. Reload the page.
- navigator.serviceWorker.ready.then(registration => {
- registration.unregister().then(() => {
- window.location.reload();
- });
- });
- } else {
- // Service worker found. Proceed as normal.
- registerValidSW(swUrl, config);
- }
+ // Check if the service worker can be found. If it can't reload the page.
+ fetch(swUrl, {
+ headers: { 'Service-Worker': 'script' },
})
- .catch(() => {
- console.log(
- 'No internet connection found. App is running in offline mode.'
- );
- });
+ .then((response) => {
+ // Ensure service worker exists, and that we really are getting a JS file.
+ const contentType = response.headers.get('content-type');
+ if (
+ response.status === 404 ||
+ (contentType != null &&
+ contentType.indexOf('javascript') === -1)
+ ) {
+ // No service worker found. Probably a different app. Reload the page.
+ navigator.serviceWorker.ready.then((registration) => {
+ registration.unregister().then(() => {
+ window.location.reload();
+ });
+ });
+ } else {
+ // Service worker found. Proceed as normal.
+ registerValidSW(swUrl, config);
+ }
+ })
+ .catch(() => {
+ console.log(
+ 'No internet connection found. App is running in offline mode.'
+ );
+ });
}
export function unregister() {
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker.ready
- .then(registration => {
- registration.unregister();
- })
- .catch(error => {
- console.error(error.message);
- });
- }
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.ready
+ .then((registration) => {
+ registration.unregister();
+ })
+ .catch((error) => {
+ console.error(error.message);
+ });
+ }
}
diff --git a/yarn.lock b/yarn.lock
index e2c16ee..caf5887 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2433,6 +2433,11 @@ base@^0.11.1:
mixin-deep "^1.2.0"
pascalcase "^0.1.1"
+basic-auth@^1.0.3:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884"
+ integrity sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=
+
batch@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
@@ -3048,6 +3053,11 @@ color@^3.0.0:
color-convert "^1.9.1"
color-string "^1.5.2"
+colors@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
+ integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
+
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@@ -3231,6 +3241,11 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+corser@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87"
+ integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=
+
cosmiconfig@^5.0.0, cosmiconfig@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
@@ -3919,6 +3934,16 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
+ecstatic@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48"
+ integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==
+ dependencies:
+ he "^1.1.1"
+ mime "^1.6.0"
+ minimist "^1.1.0"
+ url-join "^2.0.5"
+
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -5079,7 +5104,7 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
-he@^1.2.0:
+he@^1.1.1, he@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
@@ -5250,6 +5275,31 @@ http-proxy@^1.17.0:
follow-redirects "^1.0.0"
requires-port "^1.0.0"
+http-proxy@^1.18.0:
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
+ integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
+ dependencies:
+ eventemitter3 "^4.0.0"
+ follow-redirects "^1.0.0"
+ requires-port "^1.0.0"
+
+http-server@^0.12.3:
+ version "0.12.3"
+ resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.12.3.tgz#ba0471d0ecc425886616cb35c4faf279140a0d37"
+ integrity sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==
+ dependencies:
+ basic-auth "^1.0.3"
+ colors "^1.4.0"
+ corser "^2.0.1"
+ ecstatic "^3.3.2"
+ http-proxy "^1.18.0"
+ minimist "^1.2.5"
+ opener "^1.5.1"
+ portfinder "^1.0.25"
+ secure-compare "3.0.1"
+ union "~0.5.0"
+
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@@ -6770,6 +6820,11 @@ memory-fs@^0.5.0:
errno "^0.1.3"
readable-stream "^2.0.1"
+memorystream@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
+ integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI=
+
merge-deep@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2"
@@ -6843,7 +6898,7 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
dependencies:
mime-db "1.43.0"
-mime@1.6.0:
+mime@1.6.0, mime@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
@@ -6895,7 +6950,7 @@ minimist@0.0.8:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
-minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5:
+minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
@@ -7186,6 +7241,21 @@ normalize-url@^3.0.0:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559"
integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
+npm-run-all@^4.1.5:
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba"
+ integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ chalk "^2.4.1"
+ cross-spawn "^6.0.5"
+ memorystream "^0.3.1"
+ minimatch "^3.0.4"
+ pidtree "^0.3.0"
+ read-pkg "^3.0.0"
+ shell-quote "^1.6.1"
+ string.prototype.padend "^3.0.0"
+
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
@@ -7360,6 +7430,11 @@ open@^7.0.2:
is-docker "^2.0.0"
is-wsl "^2.1.1"
+opener@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
+ integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
+
opn@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
@@ -7695,6 +7770,11 @@ picomatch@^2.0.4, picomatch@^2.0.7:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
+pidtree@^0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a"
+ integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==
+
pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -8630,6 +8710,11 @@ qs@6.7.0:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+qs@^6.4.0:
+ version "6.9.4"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
+ integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
+
qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
@@ -9386,6 +9471,11 @@ schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6
ajv "^6.12.0"
ajv-keywords "^3.4.1"
+secure-compare@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3"
+ integrity sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=
+
select-hose@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -9544,7 +9634,7 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-shell-quote@1.7.2:
+shell-quote@1.7.2, shell-quote@^1.6.1:
version "1.7.2"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2"
integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==
@@ -9918,6 +10008,14 @@ string.prototype.matchall@^4.0.2:
regexp.prototype.flags "^1.3.0"
side-channel "^1.0.2"
+string.prototype.padend@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz#dc08f57a8010dc5c153550318f67e13adbb72ac3"
+ integrity sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.0-next.1"
+
string.prototype.trimleft@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74"
@@ -10393,6 +10491,13 @@ union-value@^1.0.0:
is-extendable "^0.1.1"
set-value "^2.0.1"
+union@~0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/union/-/union-0.5.0.tgz#b2c11be84f60538537b846edb9ba266ba0090075"
+ integrity sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==
+ dependencies:
+ qs "^6.4.0"
+
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
@@ -10457,6 +10562,11 @@ urix@^0.1.0:
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+url-join@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728"
+ integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=
+
url-loader@2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.3.0.tgz#e0e2ef658f003efb8ca41b0f3ffbf76bab88658b"