Merge branch 'master' into revoke_claims and clean-up

This commit is contained in:
hackrush 2017-10-30 22:14:30 +05:30
commit c4626dda4a
9 changed files with 209 additions and 199 deletions

View file

@ -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
* *

View file

@ -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) {

View file

@ -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));
},
}; };

View file

@ -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) { } else {
try { throw new Error(
const files = JSON.parse(xhr.responseText); __("The list of available languages could not be retrieved.")
const actions = []; );
files.forEach(file => {
actions.push(doDownloadLanguage(file));
});
dispatch(batchActions(...actions));
} catch (err) {
throw err;
}
} else {
throw new Error(
__("The list of available languages could not be retrieved.")
);
}
} }
}; }
xhr.open("get", "http://i18n.lbry.io");
xhr.send(); function parseJSON(response) {
return response.json();
}
return fetch("http://i18n.lbry.io")
.then(checkStatus)
.then(parseJSON)
.then(files => {
const actions = files.map(doDownloadLanguage);
dispatch(batchActions(...actions));
});
}; };
} }

View file

@ -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 &&

View file

@ -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 {

View file

@ -9,80 +9,90 @@ 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; } else {
var error = new Error(response.statusText);
error.response = response;
throw error;
} }
}
xhr.addEventListener("error", function(e) { function parseJSON(response) {
connectFailedCallback(e); return response.json();
}); }
xhr.addEventListener("timeout", function() {
connectFailedCallback( function makeRequest(url, options) {
new Error(__("XMLHttpRequest connection timed out")) 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);
}
}); });
} }
xhr.addEventListener("load", function() {
var response = JSON.parse(xhr.responseText);
let error = response.error || (response.result && response.result.error); const counter = parseInt(sessionStorage.getItem("JSONRPCCounter") || 0);
if (error) { const url = connectionString;
if (errorCallback) { const options = {
errorCallback(error); method: "POST",
} else { body: JSON.stringify({
var errorEvent = new CustomEvent("unhandledError", { jsonrpc: "2.0",
detail: { method: method,
connectionString: connectionString, params: params,
method: method, id: counter,
params: params, }),
code: error.code, };
message: error.message || error,
data: error.data, sessionStorage.setItem("JSONRPCCounter", counter + 1);
},
}); return fetch(url, options)
document.dispatchEvent(errorEvent); .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);
} }
} else if (callback) {
callback(response.result);
}
});
if (connectFailedCallback) {
xhr.addEventListener("error", function(event) {
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: error.code,
message: error.message || error,
data: error.data,
},
});
document.dispatchEvent(errorEvent);
})
.catch(e => {
if (connectFailedCallback) {
return connectFailedCallback(e);
}
var errorEvent = new CustomEvent("unhandledError", {
detail: {
connectionString: connectionString,
method: method,
params: params,
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;

View file

@ -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")); return Promise.reject(new Error(__("LBRY internal API is disabled")));
reject(new Error(__("LBRY internal API is disabled"))); }
return;
if (!(method == "get" || method == "post")) {
return Promise.reject(new Error(__("Invalid method")));
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
} else {
var error = new Error(response.statusText);
error.response = response;
throw error;
}
}
function parseJSON(response) {
return response.json();
}
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 qs = querystring.stringify(fullParams);
let url = `${CONNECTION_STRING}${resource}/${action}?${qs}`;
let options = {
method: "GET",
};
if (method == "post") {
options = {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: qs,
};
url = `${CONNECTION_STRING}${resource}/${action}`;
} }
const xhr = new XMLHttpRequest(); return makeRequest(url, options).then(response => response.data);
xhr.addEventListener("error", function(event) {
reject(
new Error(__("Something went wrong making an internal API call."))
);
});
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 {
document.dispatchEvent(
new CustomEvent("unhandledError", {
detail: {
connectionString: connectionString,
method: action,
params: params,
message: response.error.message,
...(response.error.data ? { data: response.error.data } : {}),
},
})
);
}
} else {
resolve(response.data);
}
});
lbryio
.getAuthToken()
.then(token => {
const fullParams = { auth_token: token, ...params };
if (method == "get") {
xhr.open(
"get",
CONNECTION_STRING +
resource +
"/" +
action +
"?" +
querystring.stringify(fullParams),
true
);
xhr.send();
} else if (method == "post") {
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);
}); });
}; };

View file

@ -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 ? "" : "...")