Merge branch 'master' into revoke_claims and clean-up
This commit is contained in:
commit
c4626dda4a
9 changed files with 209 additions and 199 deletions
|
@ -9,15 +9,16 @@ Web UI version numbers should always match the corresponding version of LBRY App
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
* Now you can revoke your claims from the txns list itself.(#581)
|
* Now you can revoke your claims from the txns list itself.(#581)
|
||||||
|
* Added new window menu options for reloading and help.
|
||||||
|
* Rewards are now marked in transaction history (#660)
|
||||||
*
|
*
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
*
|
* Replaced all instances of `XMLHttpRequest` with native `Fetch` API.
|
||||||
*
|
*
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
*
|
* Fixed console errors on settings page related to improper React input properties.
|
||||||
*
|
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const {app, BrowserWindow, ipcMain} = require('electron');
|
const {app, BrowserWindow, ipcMain} = require('electron');
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
const isDebug = process.env.NODE_ENV === 'development'
|
const isDebug = process.env.NODE_ENV === 'development';
|
||||||
|
const setMenu = require('./menu/main-menu.js');
|
||||||
|
|
||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
try
|
try
|
||||||
|
@ -169,6 +170,12 @@ function createWindow () {
|
||||||
win.on('closed', () => {
|
win.on('closed', () => {
|
||||||
win = null
|
win = null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Menu bar
|
||||||
|
win.setAutoHideMenuBar(true);
|
||||||
|
win.setMenuBarVisibility(isDebug);
|
||||||
|
setMenu();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleOpenUriRequested(uri) {
|
function handleOpenUriRequested(uri) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
const {Menu} = require('electron');
|
const { app, shell, Menu } = require('electron');
|
||||||
const electron = require('electron');
|
|
||||||
const app = electron.app;
|
|
||||||
|
|
||||||
const baseTemplate = [
|
const baseTemplate = [
|
||||||
{
|
{
|
||||||
|
@ -30,16 +28,65 @@ const baseTemplate = [
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Help',
|
label: 'View',
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'Help',
|
role: 'reload'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Developer',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
role: 'forcereload'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'toggledevtools'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'togglefullscreen'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'help',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Learn More',
|
||||||
click(item, focusedWindow) {
|
click(item, focusedWindow) {
|
||||||
if (focusedWindow) {
|
if (focusedWindow) {
|
||||||
focusedWindow.webContents.send('open-menu', '/help');
|
focusedWindow.webContents.send('open-menu', '/help');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Frequently Asked Questions',
|
||||||
|
click(item, focusedWindow){
|
||||||
|
shell.openExternal('https://lbry.io/faq')
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Report Issue',
|
||||||
|
click(item, focusedWindow){
|
||||||
|
shell.openExternal('https://lbry.io/faq/contributing#report-a-bug');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Developer API Guide',
|
||||||
|
click(item, focusedWindow){
|
||||||
|
shell.openExternal('https://lbry.io/quickstart')
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -71,40 +118,8 @@ const macOSAppMenuTemplate = {
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const developerMenuTemplate = {
|
module.exports = () => {
|
||||||
label: 'Developer',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Reload',
|
|
||||||
accelerator: 'CmdOrCtrl+R',
|
|
||||||
click(item, focusedWindow) {
|
|
||||||
if (focusedWindow) {
|
|
||||||
focusedWindow.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Toggle Developer Tools',
|
|
||||||
accelerator: process.platform == 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
|
||||||
click(item, focusedWindow) {
|
|
||||||
if (focusedWindow) {
|
|
||||||
focusedWindow.webContents.toggleDevTools();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
showMenubar(showDeveloperMenu) {
|
|
||||||
let template = baseTemplate.slice();
|
let template = baseTemplate.slice();
|
||||||
if (process.platform === 'darwin') {
|
(process.platform === 'darwin') && template.unshift(macOSAppMenuTemplate);
|
||||||
template.unshift(macOSAppMenuTemplate);
|
|
||||||
}
|
|
||||||
if (showDeveloperMenu) {
|
|
||||||
template.push(developerMenuTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
|
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -133,30 +133,27 @@ export function doDownloadLanguages() {
|
||||||
fs.mkdirSync(app.i18n.directory);
|
fs.mkdirSync(app.i18n.directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
function checkStatus(response) {
|
||||||
xhr.onreadystatechange = () => {
|
if (response.status >= 200 && response.status < 300) {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
return response;
|
||||||
if (xhr.status === 200) {
|
|
||||||
try {
|
|
||||||
const files = JSON.parse(xhr.responseText);
|
|
||||||
const actions = [];
|
|
||||||
files.forEach(file => {
|
|
||||||
actions.push(doDownloadLanguage(file));
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatch(batchActions(...actions));
|
|
||||||
} catch (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
__("The list of available languages could not be retrieved.")
|
__("The list of available languages could not be retrieved.")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
xhr.open("get", "http://i18n.lbry.io");
|
function parseJSON(response) {
|
||||||
xhr.send();
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch("http://i18n.lbry.io")
|
||||||
|
.then(checkStatus)
|
||||||
|
.then(parseJSON)
|
||||||
|
.then(files => {
|
||||||
|
const actions = files.map(doDownloadLanguage);
|
||||||
|
dispatch(batchActions(...actions));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,10 @@ class TransactionListItem extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
capitalize(string) {
|
||||||
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { reward, transaction, isRevokeable } = this.props;
|
const { reward, transaction, isRevokeable } = this.props;
|
||||||
const {
|
const {
|
||||||
|
@ -108,8 +112,9 @@ class TransactionListItem extends React.PureComponent {
|
||||||
/>}
|
/>}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{type}{" "}
|
{this.capitalize(type)}{" "}
|
||||||
{isRevokeable && this.getLink(type)}
|
{isRevokeable && this.getLink(type)}
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{reward &&
|
{reward &&
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import TransactionListItem from "./internal/TransactionListItem";
|
import TransactionListItem from "./internal/TransactionListItem";
|
||||||
import FormField from "component/formField";
|
import FormField from "component/formField";
|
||||||
import lbryuri from "lbryuri";
|
|
||||||
import * as modals from "constants/modal_types";
|
import * as modals from "constants/modal_types";
|
||||||
|
|
||||||
class TransactionList extends React.PureComponent {
|
class TransactionList extends React.PureComponent {
|
||||||
|
|
112
ui/js/jsonrpc.js
112
ui/js/jsonrpc.js
|
@ -9,29 +9,62 @@ jsonrpc.call = function(
|
||||||
connectFailedCallback,
|
connectFailedCallback,
|
||||||
timeout
|
timeout
|
||||||
) {
|
) {
|
||||||
var xhr = new XMLHttpRequest();
|
function checkStatus(response) {
|
||||||
if (typeof connectFailedCallback !== "undefined") {
|
if (response.status >= 200 && response.status < 300) {
|
||||||
if (timeout) {
|
return response;
|
||||||
xhr.timeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
xhr.addEventListener("error", function(e) {
|
|
||||||
connectFailedCallback(e);
|
|
||||||
});
|
|
||||||
xhr.addEventListener("timeout", function() {
|
|
||||||
connectFailedCallback(
|
|
||||||
new Error(__("XMLHttpRequest connection timed out"))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
xhr.addEventListener("load", function() {
|
|
||||||
var response = JSON.parse(xhr.responseText);
|
|
||||||
|
|
||||||
let error = response.error || (response.result && response.result.error);
|
|
||||||
if (error) {
|
|
||||||
if (errorCallback) {
|
|
||||||
errorCallback(error);
|
|
||||||
} else {
|
} else {
|
||||||
|
var error = new Error(response.statusText);
|
||||||
|
error.response = response;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseJSON(response) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeRequest(url, options) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fetch(url, options).then(resolve).catch(reject);
|
||||||
|
|
||||||
|
if (timeout) {
|
||||||
|
const e = new Error(__("XMLHttpRequest connection timed out"));
|
||||||
|
setTimeout(() => {
|
||||||
|
return reject(e);
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const counter = parseInt(sessionStorage.getItem("JSONRPCCounter") || 0);
|
||||||
|
const url = connectionString;
|
||||||
|
const options = {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method: method,
|
||||||
|
params: params,
|
||||||
|
id: counter,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
sessionStorage.setItem("JSONRPCCounter", counter + 1);
|
||||||
|
|
||||||
|
return fetch(url, options)
|
||||||
|
.then(checkStatus)
|
||||||
|
.then(parseJSON)
|
||||||
|
.then(response => {
|
||||||
|
const error =
|
||||||
|
response.error || (response.result && response.result.error);
|
||||||
|
|
||||||
|
if (!error && typeof callback === "function") {
|
||||||
|
return callback(response.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error && typeof errorCallback === "function") {
|
||||||
|
return errorCallback(error);
|
||||||
|
}
|
||||||
|
|
||||||
var errorEvent = new CustomEvent("unhandledError", {
|
var errorEvent = new CustomEvent("unhandledError", {
|
||||||
detail: {
|
detail: {
|
||||||
connectionString: connectionString,
|
connectionString: connectionString,
|
||||||
|
@ -43,46 +76,23 @@ jsonrpc.call = function(
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
document.dispatchEvent(errorEvent);
|
document.dispatchEvent(errorEvent);
|
||||||
}
|
})
|
||||||
} else if (callback) {
|
.catch(e => {
|
||||||
callback(response.result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (connectFailedCallback) {
|
if (connectFailedCallback) {
|
||||||
xhr.addEventListener("error", function(event) {
|
return connectFailedCallback(e);
|
||||||
connectFailedCallback(event);
|
}
|
||||||
});
|
|
||||||
} else {
|
|
||||||
xhr.addEventListener("error", function(event) {
|
|
||||||
var errorEvent = new CustomEvent("unhandledError", {
|
var errorEvent = new CustomEvent("unhandledError", {
|
||||||
detail: {
|
detail: {
|
||||||
connectionString: connectionString,
|
connectionString: connectionString,
|
||||||
method: method,
|
method: method,
|
||||||
params: params,
|
params: params,
|
||||||
code: xhr.status,
|
code: e.response && e.response.status,
|
||||||
message: __("Connection to API server failed"),
|
message: __("Connection to API server failed"),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
document.dispatchEvent(errorEvent);
|
document.dispatchEvent(errorEvent);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const counter = parseInt(sessionStorage.getItem("JSONRPCCounter") || 0);
|
|
||||||
|
|
||||||
xhr.open("POST", connectionString, true);
|
|
||||||
xhr.send(
|
|
||||||
JSON.stringify({
|
|
||||||
jsonrpc: "2.0",
|
|
||||||
method: method,
|
|
||||||
params: params,
|
|
||||||
id: counter,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
sessionStorage.setItem("JSONRPCCounter", counter + 1);
|
|
||||||
|
|
||||||
return xhr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default jsonrpc;
|
export default jsonrpc;
|
||||||
|
|
102
ui/js/lbryio.js
102
ui/js/lbryio.js
|
@ -36,80 +36,56 @@ lbryio.getExchangeRates = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
lbryio.call = function(resource, action, params = {}, method = "get") {
|
lbryio.call = function(resource, action, params = {}, method = "get") {
|
||||||
return new Promise((resolve, reject) => {
|
if (!lbryio.enabled) {
|
||||||
if (!lbryio.enabled && (resource != "discover" || action != "list")) {
|
|
||||||
console.log(__("Internal API disabled"));
|
console.log(__("Internal API disabled"));
|
||||||
reject(new Error(__("LBRY internal API is disabled")));
|
return Promise.reject(new Error(__("LBRY internal API is disabled")));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
if (!(method == "get" || method == "post")) {
|
||||||
|
return Promise.reject(new Error(__("Invalid method")));
|
||||||
|
}
|
||||||
|
|
||||||
xhr.addEventListener("error", function(event) {
|
function checkStatus(response) {
|
||||||
reject(
|
if (response.status >= 200 && response.status < 300) {
|
||||||
new Error(__("Something went wrong making an internal API call."))
|
return response;
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
xhr.addEventListener("timeout", function() {
|
|
||||||
reject(new Error(__("XMLHttpRequest connection timed out")));
|
|
||||||
});
|
|
||||||
|
|
||||||
xhr.addEventListener("load", function() {
|
|
||||||
const response = JSON.parse(xhr.responseText);
|
|
||||||
|
|
||||||
if (!response.success) {
|
|
||||||
if (reject) {
|
|
||||||
const error = new Error(response.error);
|
|
||||||
error.xhr = xhr;
|
|
||||||
reject(error);
|
|
||||||
} else {
|
} else {
|
||||||
document.dispatchEvent(
|
var error = new Error(response.statusText);
|
||||||
new CustomEvent("unhandledError", {
|
error.response = response;
|
||||||
detail: {
|
throw error;
|
||||||
connectionString: connectionString,
|
|
||||||
method: action,
|
|
||||||
params: params,
|
|
||||||
message: response.error.message,
|
|
||||||
...(response.error.data ? { data: response.error.data } : {}),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
resolve(response.data);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
lbryio
|
function parseJSON(response) {
|
||||||
.getAuthToken()
|
return response.json();
|
||||||
.then(token => {
|
}
|
||||||
|
|
||||||
|
function makeRequest(url, options) {
|
||||||
|
return fetch(url, options).then(checkStatus).then(parseJSON).catch(e => {
|
||||||
|
throw new Error(__("Something went wrong making an internal API call."));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return lbryio.getAuthToken().then(token => {
|
||||||
const fullParams = { auth_token: token, ...params };
|
const fullParams = { auth_token: token, ...params };
|
||||||
|
const qs = querystring.stringify(fullParams);
|
||||||
|
let url = `${CONNECTION_STRING}${resource}/${action}?${qs}`;
|
||||||
|
|
||||||
if (method == "get") {
|
let options = {
|
||||||
xhr.open(
|
method: "GET",
|
||||||
"get",
|
};
|
||||||
CONNECTION_STRING +
|
|
||||||
resource +
|
if (method == "post") {
|
||||||
"/" +
|
options = {
|
||||||
action +
|
method: "POST",
|
||||||
"?" +
|
headers: {
|
||||||
querystring.stringify(fullParams),
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
true
|
},
|
||||||
);
|
body: qs,
|
||||||
xhr.send();
|
};
|
||||||
} else if (method == "post") {
|
url = `${CONNECTION_STRING}${resource}/${action}`;
|
||||||
xhr.open("post", CONNECTION_STRING + resource + "/" + action, true);
|
|
||||||
xhr.setRequestHeader(
|
|
||||||
"Content-type",
|
|
||||||
"application/x-www-form-urlencoded"
|
|
||||||
);
|
|
||||||
xhr.send(querystring.stringify(fullParams));
|
|
||||||
} else {
|
|
||||||
reject(new Error(__("Invalid method")));
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(reject);
|
return makeRequest(url, options).then(response => response.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -237,7 +237,7 @@ class SettingsPage extends React.PureComponent {
|
||||||
<FormRow
|
<FormRow
|
||||||
type="radio"
|
type="radio"
|
||||||
name="instant_purchase_max"
|
name="instant_purchase_max"
|
||||||
checked={!instantPurchaseEnabled}
|
defaultChecked={!instantPurchaseEnabled}
|
||||||
label={__("Ask for confirmation of all purchases")}
|
label={__("Ask for confirmation of all purchases")}
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
this.onInstantPurchaseEnabledChange(false);
|
this.onInstantPurchaseEnabledChange(false);
|
||||||
|
@ -247,7 +247,7 @@ class SettingsPage extends React.PureComponent {
|
||||||
<FormField
|
<FormField
|
||||||
type="radio"
|
type="radio"
|
||||||
name="instant_purchase_max"
|
name="instant_purchase_max"
|
||||||
checked={instantPurchaseEnabled}
|
defaultChecked={instantPurchaseEnabled}
|
||||||
label={
|
label={
|
||||||
"Single-click purchasing of content less than" +
|
"Single-click purchasing of content less than" +
|
||||||
(instantPurchaseEnabled ? "" : "...")
|
(instantPurchaseEnabled ? "" : "...")
|
||||||
|
|
Loading…
Add table
Reference in a new issue