Bug 1517596 - Add basic DiscoveryStream devtools

This commit is contained in:
Kate Hudson 2019-01-04 12:08:44 -05:00 коммит произвёл GitHub
Родитель 4ec4f4bb06
Коммит 9220cb8e28
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 113 добавлений и 8 удалений

Просмотреть файл

@ -41,6 +41,8 @@ for (const type of [
"DIALOG_OPEN",
"DISCOVERY_STREAM_CONFIG_CHANGE",
"DISCOVERY_STREAM_CONFIG_SETUP",
"DISCOVERY_STREAM_CONFIG_SET_VALUE",
"DISCOVERY_STREAM_LAYOUT_RESET",
"DISCOVERY_STREAM_LAYOUT_UPDATE",
"DOWNLOAD_CHANGED",
"FILL_SEARCH_TERM",

Просмотреть файл

@ -52,6 +52,10 @@ const INITIAL_STATE = {
// This is a JSON-parsed copy of the discoverystream.config pref value.
config: {enabled: false, layout_endpoint: ""},
layout: [],
lastUpdated: null,
feeds: {
// "https://foo.com/feed1": {lastUpdated: 123, data: []}
},
},
Search: {
// Pretend the search box is focused after handing off to AwesomeBar.
@ -448,7 +452,9 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
case at.DISCOVERY_STREAM_CONFIG_SETUP:
return {...prevState, config: action.data || {}};
case at.DISCOVERY_STREAM_LAYOUT_UPDATE:
return {...prevState, layout: action.data || []};
return {...prevState, lastUpdated: action.data.lastUpdated || null, layout: action.data.layout || []};
case at.DISCOVERY_STREAM_LAYOUT_RESET:
return {...prevState, lastUpdated: INITIAL_STATE.DiscoveryStream.lastUpdated, layout: INITIAL_STATE.DiscoveryStream.layout};
default:
return prevState;
}

Просмотреть файл

@ -1,9 +1,57 @@
import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
import {ASRouterUtils} from "../../asrouter/asrouter-content";
import {connect} from "react-redux";
import {ModalOverlay} from "../../asrouter/components/ModalOverlay/ModalOverlay";
import React from "react";
import {SimpleHashRouter} from "./SimpleHashRouter";
const Row = props => (<tr className="message-item" {...props}>{props.children}</tr>);
function relativeTime(timestamp) {
if (!timestamp) {
return "";
}
const seconds = Math.floor((Date.now() - timestamp) / 1000);
const minutes = Math.floor((Date.now() - timestamp) / 60000);
if (seconds < 2) {
return "just now";
} else if (seconds < 60) {
return `${seconds} seconds ago`;
} else if (minutes === 1) {
return "1 minute ago";
} else if (minutes < 600) {
return `${minutes} minutes ago`;
}
return new Date(timestamp).toLocaleString();
}
class DiscoveryStreamAdmin extends React.PureComponent {
constructor(props) {
super(props);
this.onEnableToggle = this.onEnableToggle.bind(this);
}
setConfigValue(name, value) {
this.props.dispatch(ac.OnlyToMain({type: at.DISCOVERY_STREAM_CONFIG_SET_VALUE, data: {name, value}}));
}
onEnableToggle(event) {
this.setConfigValue("enabled", event.target.checked);
}
render() {
const {config, lastUpdated} = this.props.state;
return (<div>
<div className="dsEnabled"><input type="checkbox" checked={config.enabled} onChange={this.onEnableToggle} /> enabled</div>
<table style={config.enabled ? null : {opacity: 0.5}}><tbody>
<Row><td className="min">Data last fetched</td><td>{relativeTime(lastUpdated) || "(no data)"}</td></Row>
<Row><td className="min">Endpoint</td><td>{config.layout_endpoint || "(empty)"}</td></Row>
</tbody></table>
</div>);
}
}
export class ASRouterAdminInner extends React.PureComponent {
constructor(props) {
super(props);
@ -393,6 +441,17 @@ export class ASRouterAdminInner extends React.PureComponent {
</tbody></table>);
}
renderDiscoveryStream() {
const {config} = this.props.DiscoveryStream;
return (<div>
<table><tbody>
<tr className="message-item"><td className="min">Enabled</td><td>{config.enabled ? "yes" : "no"}</td></tr>
<tr className="message-item"><td className="min">Endpoint</td><td>{config.endpoint || "(empty)"}</td></tr>
</tbody></table>
</div>);
}
renderAttributionParamers() {
return (
<div>
@ -433,9 +492,14 @@ export class ASRouterAdminInner extends React.PureComponent {
<h2>Pocket</h2>
{this.renderPocketStories()}
</React.Fragment>);
case "ds":
return (<React.Fragment>
<h2>Discovery Stream</h2>
<DiscoveryStreamAdmin state={this.props.DiscoveryStream} dispatch={this.props.dispatch} />
</React.Fragment>);
default:
return (<React.Fragment>
<h2>Message Providers <button title="Restore all provider settings that ship with Firefox" className="button" onClick={this.resetPref}>Restorear default prefs</button></h2>
<h2>Message Providers <button title="Restore all provider settings that ship with Firefox" className="button" onClick={this.resetPref}>Restore default prefs</button></h2>
{this.state.providers ? this.renderProviders() : null}
<h2>Messages</h2>
{this.renderMessageFilter()}
@ -452,6 +516,7 @@ export class ASRouterAdminInner extends React.PureComponent {
<li><a href="#devtools">General</a></li>
<li><a href="#devtools-targeting">Targeting</a></li>
<li><a href="#devtools-pocket">Pocket</a></li>
<li><a href="#devtools-ds">Discovery Stream</a></li>
</ul>
</aside>
<main className="main-panel">
@ -472,4 +537,4 @@ export class ASRouterAdminInner extends React.PureComponent {
}
export const _ASRouterAdmin = props => (<SimpleHashRouter><ASRouterAdminInner {...props} /></SimpleHashRouter>);
export const ASRouterAdmin = connect(state => ({Sections: state.Sections}))(_ASRouterAdmin);
export const ASRouterAdmin = connect(state => ({Sections: state.Sections, DiscoveryStream: state.DiscoveryStream}))(_ASRouterAdmin);

Просмотреть файл

@ -139,4 +139,12 @@
text-decoration: underline;
}
}
.dsEnabled {
padding: 10px;
font-size: 16px;
margin-bottom: 20px;
border: 1px solid $border-color;
}
}

Просмотреть файл

@ -11,6 +11,8 @@ import React from "react";
import {Search} from "content-src/components/Search/Search";
import {Sections} from "content-src/components/Sections/Sections";
let didLogDevtoolsHelpText = false;
const PrefsButton = injectIntl(props => (
<div className="prefs-button">
<button className="icon icon-settings" onClick={props.onClick} title={props.intl.formatMessage({id: "settings_pane_button_label"})} />
@ -86,8 +88,10 @@ export class _Base extends React.PureComponent {
if (window.location.hash.startsWith("#asrouter") ||
window.location.hash.startsWith("#devtools")) {
return (<ASRouterAdmin />);
} else if (!didLogDevtoolsHelpText) {
console.log("Activity Stream devtools enabled. To access visit %cabout:newtab#devtools", "font-weight: bold"); // eslint-disable-line no-console
didLogDevtoolsHelpText = true;
}
console.log("Activity Stream devtools enabled. To access visit %cabout:newtab#devtools", "font-weight: bold"); // eslint-disable-line no-console
}
if (!props.isPrerendered && !initialized) {

Просмотреть файл

@ -82,7 +82,6 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
async loadCachedData() {
const cachedData = await this.cache.get() || {};
let {layout: layoutResponse} = cachedData;
if (!layoutResponse || !(Date.now() - layoutResponse._timestamp < LAYOUT_UPDATE_TIME)) {
layoutResponse = await this.fetchLayout();
@ -95,7 +94,13 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
}
if (layoutResponse && layoutResponse.layout) {
this.store.dispatch(ac.BroadcastToContent({type: at.DISCOVERY_STREAM_LAYOUT_UPDATE, data: layoutResponse.layout}));
this.store.dispatch(ac.BroadcastToContent({
type: at.DISCOVERY_STREAM_LAYOUT_UPDATE,
data: {
layout: layoutResponse.layout,
lastUpdated: layoutResponse._timestamp,
},
}));
}
}
@ -107,7 +112,7 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
async disable() {
await this.clearCache();
// Reset reducer
this.store.dispatch(ac.BroadcastToContent({type: at.DISCOVERY_STREAM_LAYOUT_UPDATE, data: []}));
this.store.dispatch(ac.BroadcastToContent({type: at.DISCOVERY_STREAM_LAYOUT_RESET}));
this.loaded = false;
}
@ -140,6 +145,9 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
await this.enable();
}
break;
case at.DISCOVERY_STREAM_CONFIG_SET_VALUE:
Services.prefs.setStringPref(CONFIG_PREF_NAME, JSON.stringify({...this.config, [action.data.name]: action.data.value}));
break;
case at.DISCOVERY_STREAM_CONFIG_CHANGE:
// When the config pref changes, load or unload data as needed.
await this.onPrefChange();

Просмотреть файл

@ -660,8 +660,9 @@ describe("Reducers", () => {
assert.equal(DiscoveryStream(undefined, {type: "some_action"}), INITIAL_STATE.DiscoveryStream);
});
it("should set layout data with DISCOVERY_STREAM_LAYOUT_UPDATE", () => {
const state = DiscoveryStream(undefined, {type: at.DISCOVERY_STREAM_LAYOUT_UPDATE, data: ["test"]});
const state = DiscoveryStream(undefined, {type: at.DISCOVERY_STREAM_LAYOUT_UPDATE, data: {layout: ["test"], lastUpdated: 123}});
assert.equal(state.layout[0], "test");
assert.equal(state.lastUpdated, 123);
});
it("should set config data with DISCOVERY_STREAM_CONFIG_CHANGE", () => {
const state = DiscoveryStream(undefined, {type: at.DISCOVERY_STREAM_CONFIG_CHANGE, data: {enabled: true}});

Просмотреть файл

@ -117,6 +117,17 @@ describe("DiscoveryStreamFeed", () => {
});
});
describe("#onAction: DISCOVERY_STREAM_CONFIG_SET_VALUE", () => {
it("should add the new value to the pref without changing the existing values", async () => {
sandbox.stub(global.Services.prefs, "setStringPref");
configPrefStub.returns(JSON.stringify({enabled: true}));
await feed.onAction({type: at.DISCOVERY_STREAM_CONFIG_SET_VALUE, data: {name: "layout_endpoint", value: "foo.com"}});
assert.calledWith(global.Services.prefs.setStringPref, CONFIG_PREF_NAME, JSON.stringify({enabled: true, layout_endpoint: "foo.com"}));
});
});
describe("#onAction: DISCOVERY_STREAM_CONFIG_CHANGE", () => {
it("should call this.loadCachedData if config.enabled changes to true ", async () => {
sandbox.stub(feed.cache, "set").returns(Promise.resolve());