Merge branch 'lighthouse_v2'

This commit is contained in:
Jeremy Kauffman 2017-10-10 09:24:48 -04:00
commit dd667e8bad
15 changed files with 139 additions and 181 deletions

View file

@ -22,6 +22,7 @@ Web UI version numbers should always match the corresponding version of LBRY App
* Changed the File page to make it clearer how to to open the folder for a file
* The upgrade message is now friendlier and includes a link to the release notes.
* Improved Discover page load time by batching all URIs into one API call
* Local settings refactored and no longer intermixed with LBRY API library.
### Fixed
* Improve layout (and implementation) of the icon panel in file tiles and cards

View file

@ -1,6 +1,5 @@
import * as types from "constants/action_types";
import lbryuri from "lbryuri";
import lighthouse from "lighthouse";
import { doResolveUri } from "actions/content";
import { doNavigate } from "actions/navigation";
import { selectCurrentPage } from "selectors/navigation";
@ -25,28 +24,41 @@ export function doSearch(query) {
if (page != "search") {
dispatch(doNavigate("search", { query: query }));
} else {
lighthouse.search(query).then(results => {
const actions = [];
fetch("https://lighthouse.lbry.io/search?s=" + query)
.then(response => {
return response.status === 200
? Promise.resolve(response.json())
: Promise.reject(new Error(response.statusText));
})
.then(data => {
console.log(data);
let uris = [];
let actions = [];
results.forEach(result => {
const uri = lbryuri.build({
channelName: result.channel_name,
contentName: result.name,
claimId: result.channel_id || result.claim_id,
data.forEach(result => {
const uri = lbryuri.build({
name: result.name,
claimId: result.claimId,
});
actions.push(doResolveUri(uri));
uris.push(uri);
});
actions.push(doResolveUri(uri));
});
actions.push({
type: types.SEARCH_COMPLETED,
data: {
query,
results,
},
actions.push({
type: types.SEARCH_COMPLETED,
data: {
query,
uris,
},
});
dispatch(batchActions(...actions));
})
.catch(err => {
console.log(err);
dispatch({
type: types.SEARCH_CANCELLED,
});
});
dispatch(batchActions(...actions));
});
}
};
}

View file

@ -0,0 +1,19 @@
import React from "react";
import { connect } from "react-redux";
import { doFetchClaimCountByChannel } from "actions/content";
import { makeSelectClaimForUri } from "selectors/claims";
import { doNavigate } from "actions/navigation";
import { makeSelectTotalItemsForChannel } from "selectors/content";
import ChannelTile from "./view";
const select = (state, props) => ({
claim: makeSelectClaimForUri(props.uri)(state),
totalItems: makeSelectTotalItemsForChannel(props.uri)(state),
});
const perform = dispatch => ({
fetchClaimCount: uri => dispatch(doFetchClaimCountByChannel(uri)),
navigate: (path, params) => dispatch(doNavigate(path, params)),
});
export default connect(select, perform)(ChannelTile);

View file

@ -0,0 +1,50 @@
import React from "react";
import { TruncatedText, BusyMessage } from "component/common.js";
class ChannelTile extends React.PureComponent {
componentDidMount() {
const { uri, fetchClaimCount } = this.props;
fetchClaimCount(uri);
}
componentWillReceiveProps(nextProps) {
const { uri, fetchClaimCount } = this.props;
if (nextProps.uri != uri) {
fetchClaimCount(uri);
}
}
render() {
const { navigate, totalItems, uri } = this.props;
let onClick = () => navigate("/show", { uri });
return (
<section className="file-tile card">
<div onClick={onClick} className="card__link">
<div className="file-tile__content">
<div className="card__title-primary">
<h3>
<TruncatedText lines={1}>{uri}</TruncatedText>
</h3>
</div>
<div className="card__content card__subtext">
{isNaN(totalItems) &&
<BusyMessage message={__("Resolving channel")} />}
{totalItems > 0 &&
<span>
This is a channel with over {totalItems} items inside of it.
</span>}
{totalItems === 0 &&
<span className="empty">This is an empty channel.</span>}
</div>
</div>
</div>
</section>
);
}
}
export default ChannelTile;

View file

@ -1,22 +1,15 @@
import React from "react";
import { connect } from "react-redux";
import { doSearch } from "actions/search";
import {
selectIsSearching,
selectCurrentSearchResults,
selectSearchQuery,
} from "selectors/search";
import { doNavigate } from "actions/navigation";
import { selectIsSearching, makeSelectSearchUris } from "selectors/search";
import FileListSearch from "./view";
const select = state => ({
const select = (state, props) => ({
isSearching: selectIsSearching(state),
query: selectSearchQuery(state),
results: selectCurrentSearchResults(state),
uris: makeSelectSearchUris(props.query)(state),
});
const perform = dispatch => ({
navigate: path => dispatch(doNavigate(path)),
search: search => dispatch(doSearch(search)),
});

View file

@ -1,52 +1,23 @@
import React from "react";
import lbry from "lbry";
import lbryio from "lbryio";
import lbryuri from "lbryuri";
import lighthouse from "lighthouse";
import FileTile from "component/fileTile";
import ChannelTile from "component/channelTile";
import Link from "component/link";
import { ToolTip } from "component/tooltip.js";
import { BusyMessage } from "component/common.js";
import lbryuri from "lbryuri";
const SearchNoResults = props => {
const { navigate, query } = props;
const { query } = props;
return (
<section>
<span className="empty">
{(__("No one has checked anything in for %s yet."), query)} {" "}
<Link label={__("Be the first")} onClick={() => navigate("/publish")} />
<Link label={__("Be the first")} navigate="/publish" />
</span>
</section>
);
};
const FileListSearchResults = props => {
const { results } = props;
const rows = [],
seenNames = {}; //fix this when the search API returns claim IDs
for (let {
name,
claim,
claim_id,
channel_name,
channel_id,
txid,
nout,
} of results) {
const uri = lbryuri.build({
channelName: channel_name,
contentName: name,
claimId: channel_id || claim_id,
});
rows.push(<FileTile key={uri} uri={uri} />);
}
return <div>{rows}</div>;
};
class FileListSearch extends React.PureComponent {
componentWillMount() {
this.doSearch(this.props);
@ -63,21 +34,26 @@ class FileListSearch extends React.PureComponent {
}
render() {
const { isSearching, results } = this.props;
const { isSearching, uris, query } = this.props;
return (
<div>
{isSearching &&
!results &&
!uris &&
<BusyMessage message={__("Looking up the Dewey Decimals")} />}
{isSearching &&
results &&
uris &&
<BusyMessage message={__("Refreshing the Dewey Decimals")} />}
{results && !!results.length
? <FileListSearchResults {...this.props} />
: !isSearching && <SearchNoResults {...this.props} />}
{uris && uris.length
? uris.map(
uri =>
lbryuri.parse(uri).name[0] === "@"
? <ChannelTile key={uri} uri={uri} />
: <FileTile key={uri} uri={uri} />
)
: !isSearching && <SearchNoResults query={query} />}
</div>
);
}

View file

@ -2,8 +2,6 @@ import React from "react";
import * as icons from "constants/icons";
import lbryuri from "lbryuri.js";
import CardMedia from "component/cardMedia";
import FileActions from "component/fileActions";
import Link from "component/link";
import { TruncatedText } from "component/common.js";
import FilePrice from "component/filePrice";
import NsfwOverlay from "component/nsfwOverlay";

View file

@ -1,82 +0,0 @@
import lbry from "./lbry.js";
import jsonrpc from "./jsonrpc.js";
const queryTimeout = 3000;
const maxQueryTries = 2;
const defaultServers = [
"http://lighthouse7.lbry.io:50005",
"http://lighthouse8.lbry.io:50005",
"http://lighthouse9.lbry.io:50005",
];
const path = "/";
let server = null;
let connectTryNum = 0;
function getServers() {
return defaultServers;
}
function call(method, params, callback, errorCallback) {
if (connectTryNum >= maxQueryTries) {
errorCallback(
new Error(
__(
`Could not connect to Lighthouse server. Last server attempted: %s`,
server
)
)
);
return;
}
/**
* Set the Lighthouse server if it hasn't been set yet, if the current server is not in current
* set of servers (most likely because of a settings change), or we're re-trying after a failed
* query.
*/
if (!server || !getServers().includes(server) || connectTryNum > 0) {
// If there's a current server, filter it out so we get a new one
const newServerChoices = server
? getServers().filter(s => s != server)
: getServers();
server =
newServerChoices[
Math.round(Math.random() * (newServerChoices.length - 1))
];
}
jsonrpc.call(
server + path,
method,
params,
response => {
connectTryNum = 0;
callback(response);
},
error => {
connectTryNum = 0;
errorCallback(error);
},
() => {
connectTryNum++;
call(method, params, callback, errorCallback);
},
queryTimeout
);
}
const lighthouse = new Proxy(
{},
{
get: function(target, name) {
return function(...params) {
return new Promise((resolve, reject) => {
call(name, params, resolve, reject);
});
};
},
}
);
export default lighthouse;

View file

@ -1,6 +1,5 @@
import React from "react";
import ReactDOM from "react-dom";
import lbry from "./lbry.js";
import App from "component/app/index.js";
import SnackBar from "component/snackBar";
import { Provider } from "react-redux";

View file

@ -16,7 +16,7 @@ class ModalUpgrade extends React.PureComponent {
onConfirmed={downloadUpgrade}
onAborted={skipUpgrade}
>
<h3 className="text-center">{__("LBRY Just Got BTTR")}</h3>
<h3 className="text-center">{__("LBRY Leveled Up")}</h3>
<br />
<p>
{__("An updated version of LBRY is now available.")}

View file

@ -1,10 +1,6 @@
import React from "react";
import { connect } from "react-redux";
import {
selectIsSearching,
selectSearchQuery,
selectCurrentSearchResults,
} from "selectors/search";
import { selectIsSearching, selectSearchQuery } from "selectors/search";
import { doNavigate } from "actions/navigation";
import SearchPage from "./view";

View file

@ -3,7 +3,6 @@ import lbryuri from "lbryuri";
import FileTile from "component/fileTile";
import FileListSearch from "component/fileListSearch";
import { ToolTip } from "component/tooltip.js";
import { BusyMessage } from "component/common.js";
class SearchPage extends React.PureComponent {
render() {

View file

@ -1,7 +1,10 @@
import * as types from "constants/action_types";
const reducers = {};
const defaultState = {};
const defaultState = {
urisByQuery: {},
searching: false,
};
reducers[types.SEARCH_STARTED] = function(state, action) {
const { query } = action.data;
@ -12,17 +15,11 @@ reducers[types.SEARCH_STARTED] = function(state, action) {
};
reducers[types.SEARCH_COMPLETED] = function(state, action) {
const { query, results } = action.data;
const oldResults = Object.assign({}, state.results);
const newByQuery = Object.assign({}, oldResults.byQuery);
newByQuery[query] = results;
const newResults = Object.assign({}, oldResults, {
byQuery: newByQuery,
});
const { query, uris } = action.data;
return Object.assign({}, state, {
searching: false,
results: newResults,
urisByQuery: Object.assign({}, state.urisByQuery, { [query]: uris }),
});
};

View file

@ -34,6 +34,13 @@ export const selectChannelPages = createSelector(
state => state.channelPages || {}
);
export const makeSelectTotalItemsForChannel = uri => {
return createSelector(
selectChannelPages,
byUri => (byUri && byUri[uri]) * 10
);
};
export const makeSelectTotalPagesForChannel = uri => {
return createSelector(selectChannelPages, byUri => byUri && byUri[uri]);
};

View file

@ -18,21 +18,14 @@ export const selectIsSearching = createSelector(
state => !!state.searching
);
export const selectSearchResults = createSelector(
export const selectSearchUrisByQuery = createSelector(
_selectState,
state => state.results || {}
state => state.urisByQuery
);
export const selectSearchResultsByQuery = createSelector(
selectSearchResults,
results => results.byQuery || {}
);
export const selectCurrentSearchResults = createSelector(
selectSearchQuery,
selectSearchResultsByQuery,
(query, byQuery) => byQuery[query]
);
export const makeSelectSearchUris = query => {
return createSelector(selectSearchUrisByQuery, byQuery => byQuery[query]);
};
export const selectWunderBarAddress = createSelector(
selectCurrentPage,