Skip to content

Commit

Permalink
Implement app versioning, changelog & update popup (PIVX-Labs#139)
Browse files Browse the repository at this point in the history
* Implement app versioning, changelog & update popup

* Update changelog

* Remove weird merge duplicate
  • Loading branch information
JSKitty authored and Liquid369 committed Jul 27, 2023
1 parent 082bb28 commit 8f6ab38
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 7 deletions.
8 changes: 8 additions & 0 deletions assets/style/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ button {
text-align: center;
}

.changelog {
text-align: left;
}

.changelog p {
margin-bottom: 0px;
font-family: monospace !important;
}

.large-box {
background: rgba(43, 9, 80, 0.55);
Expand Down
18 changes: 18 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# New Features
- PIVX Promos: Create or Redeem on-chain gift codes.
- Dashboard Activity: Detailed transaction history.
- New Database: With modern features and scalability.
- Per-update changelog: You're reading it right now!

# Improvements
- New Settings screen design, sleek and intuitive.
- New Explorer: explorer.duddino.com.

# Bug Fixes
- Fixed VanityGen from failing.
- Fixed CoinGecko API spam, reducing ratelimits.
- Fixed potential XSS vulnerabilities.
- Fixed Masternodes being loaded from the wrong DB.
- Fixed Activity failing to load on Shield Txs.
- Fixed black screens on Payment Request URLs.
- Fixed Payment Request info staying post-payment.
2 changes: 1 addition & 1 deletion index.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@ <h2 id="mnLastSeen" class="stake-balances" style="overflow-wrap: anywhere; top:
<div class="footer">
<div>
<span> © MIT 2023 </span> - <span style="cursor: pointer;" onclick="MPW.playMusic()" data-i18n="footerBuiltWithPivxLabs">Built with 💜 by PIVX Labs</span><br />
<a href="https://github.com/PIVX-Labs/MyPIVXWallet" target="_blank" rel="noopener noreferrer"><i class="fa-brands fa-github"></i></i> GitHub</a> - <a href="https://discord.gg/zTScGaGtgv" target="_blank" rel="noopener noreferrer"><i class="fa-brands fa-discord"></i></i> Discord</a> - <a href="https://medium.com/@pivx-labs" target="_blank" rel="noopener noreferrer"><i class="fa-brands fa-medium"></i></i> Medium</a>
<a href="https://github.com/PIVX-Labs/MyPIVXWallet" target="_blank" rel="noopener noreferrer"><i class="fa-brands fa-github"></i></i></a> - <a href="https://discord.gg/zTScGaGtgv" target="_blank" rel="noopener noreferrer"><i class="fa-brands fa-discord"></i></i></a> - <a href="https://medium.com/@pivx-labs" target="_blank" rel="noopener noreferrer"><i class="fa-brands fa-medium"></i></i></a> - <span id="version" class="ptr" onclick="MPW.renderChangelog();"></span>
</div>
</div>
</footer>
Expand Down
70 changes: 70 additions & 0 deletions scripts/changelog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { doms } from './global';
import { confirmPopup, sanitizeHTML } from './misc';

// ESLint error-skipping for webpack-injected globals
/* global VERSION */
/* global CHANGELOG */

/**
* Check for recent local app updates
*/
export function checkForUpgrades() {
// Check if the last used version doesn't match the current version.
// Note: it's intended to skip if `lastVersion` is null, as this stops the popups for NEW users.
const lastVersion = localStorage.getItem('version');
if (lastVersion && lastVersion !== VERSION) {
// Old user's first time on this update; display the changelog
renderChangelog();
}

// Update the footer with our version
doms.domVersion.innerText = 'v' + VERSION;

// Update the last-used app version
localStorage.setItem('version', VERSION);
}

/**
* Render the Changelog from app versioning data, displaying it to the user
*/
export function renderChangelog() {
let strHTML = '';

// Loop every line of the markdown
for (const rawLine of CHANGELOG.split(/\r?\n/)) {
// Skip empty lines with linebreaks
if (!rawLine.trim()) {
strHTML += '<br><br>';
continue;
}

// Parse the element type and the line content
const type = rawLine[0];
const line = rawLine.substring(1).trim();

switch (type) {
case '#':
// `#` is a header, for titles like "New Features" or "Bug Fixes"
strHTML += `<h3>${sanitizeHTML(line)}</h3>`;
break;
case '-':
// `-` is a list element, for each 'New Feature' or 'Bug Fix' to be listed with
strHTML += `<p>- ${sanitizeHTML(line)}</p>`;
break;
default:
// If no element was recognised, it's just a plaintext line
strHTML += `<p>${sanitizeHTML(type + line)}</p>`;
break;
}
}

// Enclose the Changelog in a body with a Changelog class
const strFinalHTML = `<div class="changelog">${strHTML}</div>`;

confirmPopup({
title: "What's New in " + VERSION + '?',
html: strFinalHTML,
resolvePromise: false,
hideConfirm: true,
});
}
5 changes: 5 additions & 0 deletions scripts/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { Address6 } from 'ip-address';
import { getEventEmitter } from './event_bus.js';
import { scanQRCode } from './scanner.js';
import { Database } from './database.js';
import { checkForUpgrades } from './changelog.js';

/** A flag showing if base MPW is fully loaded or not */
export let fIsLoaded = false;
Expand Down Expand Up @@ -234,6 +235,7 @@ export async function start() {
domDisplaySettings: document.getElementById('settingsDisplay'),
domWalletSettingsBtn: document.getElementById('settingsWalletBtn'),
domDisplaySettingsBtn: document.getElementById('settingsDisplayBtn'),
domVersion: document.getElementById('version'),
};
await i18nStart();
await loadImages();
Expand Down Expand Up @@ -354,6 +356,9 @@ export async function start() {

// After reaching here; we know MPW's base is fully loaded!
fIsLoaded = true;

// Check for recent upgrades, display the changelog
checkForUpgrades();
}

function subscribeToNetworkEvents() {
Expand Down
1 change: 1 addition & 0 deletions scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export { renderWalletBreakdown } from './charting';
export { hexToBytes, bytesToHex, dSHA256 } from './utils.js';

import Masternode from './masternode.js';
export { renderChangelog } from './changelog';
export { Masternode };

export { getNetwork } from './network.js';
Expand Down
33 changes: 27 additions & 6 deletions scripts/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,27 @@ export function createAlert(type, message, alertVariables = [], timeout = 0) {
doms.domAlertPos.appendChild(domAlert);
}

// Shows the confirm modal with the provided html.
// If resolvePromise has a value, the popup won't have
// Confirm/Cancel buttons and will wait for the promise to resolve
// Returns the awaited value of resolvePromise
// or true/false if the user confirmed or not the modal
export async function confirmPopup({ title, html, resolvePromise }) {
/**
* Shows a Confirm popup with custom HTML.
*
* If `resolvePromise` has a value, the popup won't have
* Confirm/Cancel buttons and will wait for the promise to resolve.
*
* Returns the awaited value of `resolvePromise` or `true/false` if the
* user used a Cancel/Confirm button.
* @param {object} options
* @param {string?} options.title - The optional title of the popup
* @param {string} options.html - The HTML of the popup contents
* @param {Promise<any>} options.resolvePromise - A promise to resolve before closing the modal
* @param {boolean?} options.hideConfirm - Whether to hide the Confirm button or not
* @returns {Promise<boolean|any>}
*/
export async function confirmPopup({
title,
html,
resolvePromise,
hideConfirm,
}) {
// If there's a title provided: display the header and text
doms.domConfirmModalHeader.style.display = title ? 'block' : 'none';
doms.domConfirmModalTitle.innerHTML = title || '';
Expand All @@ -96,6 +111,12 @@ export async function confirmPopup({ title, html, resolvePromise }) {
);
$('#confirmModal').modal(resolvePromise ? 'show' : { keyboard: false });

// Show or hide the confirm button, and replace 'Cancel' with 'Close'
doms.domConfirmModalConfirmButton.style.display = hideConfirm ? 'none' : '';
doms.domConfirmModalCancelButton.innerText = hideConfirm
? 'Close'
: 'Cancel';

// Set content display
doms.domConfirmModalContent.innerHTML = html;

Expand Down
12 changes: 12 additions & 0 deletions webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const { readFileSync } = require('fs');

// Inject the Changelog and Version to the app
const changelog = readFileSync('./changelog.md', { encoding: 'utf8' });
const version = JSON.parse(
readFileSync('./package.json', { encoding: 'utf8' })
).version;

module.exports = {
entry: './scripts/index.js',
Expand Down Expand Up @@ -55,6 +62,11 @@ module.exports = {
jQuery: 'jquery',
'window.jQuery': 'jquery',
}),
// Make the Changelog available globally
new webpack.DefinePlugin({
CHANGELOG: JSON.stringify(changelog),
VERSION: JSON.stringify(version),
}),
// Ignore non english bip39 wordlists
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/wordlists\/(?!english)/,
Expand Down

0 comments on commit 8f6ab38

Please sign in to comment.