Bug 1608925 - Stub out Personalization reducer component and devtools. r=gvn

Differential Revision: https://phabricator.services.mozilla.com/D59784

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Scott 2020-01-14 00:40:02 +00:00
Родитель 620e65a48a
Коммит 8c16693e1b
9 изменённых файлов: 463 добавлений и 24 удалений

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

@ -57,6 +57,10 @@ for (const type of [
"DISCOVERY_STREAM_LAYOUT_UPDATE",
"DISCOVERY_STREAM_LINK_BLOCKED",
"DISCOVERY_STREAM_LOADED_CONTENT",
"DISCOVERY_STREAM_PERSONALIZATION_INIT",
"DISCOVERY_STREAM_PERSONALIZATION_LAST_UPDATED",
"DISCOVERY_STREAM_PERSONALIZATION_VERSION",
"DISCOVERY_STREAM_PERSONALIZATION_VERSION_TOGGLE",
"DISCOVERY_STREAM_RETRY_FEED",
"DISCOVERY_STREAM_SPOCS_CAPS",
"DISCOVERY_STREAM_SPOCS_ENDPOINT",

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

@ -12,6 +12,7 @@ const { Dedupe } = ChromeUtils.import(
const TOP_SITES_DEFAULT_ROWS = 1;
const TOP_SITES_MAX_SITES_PER_ROW = 8;
const PREF_PERSONALIZATION_VERSION = "discoverystream.personalization.version";
const dedupe = new Dedupe(site => site && site.url);
@ -72,6 +73,11 @@ const INITIAL_STATE = {
placements: [],
},
},
Personalization: {
version: 1,
lastUpdated: null,
initialized: false,
},
Search: {
// When search hand-off is enabled, we render a big button that is styled to
// look like a search textbox. If the button is clicked, we style
@ -518,6 +524,36 @@ function Pocket(prevState = INITIAL_STATE.Pocket, action) {
}
}
function Personalization(prevState = INITIAL_STATE.Personalization, action) {
switch (action.type) {
case at.DISCOVERY_STREAM_PERSONALIZATION_VERSION:
return {
...prevState,
version: action.data.version,
};
case at.DISCOVERY_STREAM_PERSONALIZATION_LAST_UPDATED:
return {
...prevState,
lastUpdated: action.data.lastUpdated,
};
case at.DISCOVERY_STREAM_PERSONALIZATION_INIT:
return {
...prevState,
initialized: true,
};
case at.PREF_CHANGED:
if (action.data.name === PREF_PERSONALIZATION_VERSION) {
return {
...prevState,
version: action.data.value,
};
}
return prevState;
default:
return prevState;
}
}
function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
// Return if action data is empty, or spocs or feeds data is not loaded
const isNotReady = () =>
@ -762,6 +798,7 @@ this.reducers = {
Dialog,
Sections,
Pocket,
Personalization,
DiscoveryStream,
Search,
};

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

@ -80,6 +80,58 @@ export class TogglePrefCheckbox extends React.PureComponent {
}
}
export class Personalization extends React.PureComponent {
constructor(props) {
super(props);
this.togglePersonalizationVersion = this.togglePersonalizationVersion.bind(
this
);
}
togglePersonalizationVersion() {
this.props.dispatch(
ac.OnlyToMain({
type: at.DISCOVERY_STREAM_PERSONALIZATION_VERSION_TOGGLE,
})
);
}
render() {
const {
lastUpdated,
version,
initialized,
} = this.props.state.Personalization;
return (
<React.Fragment>
<button className="button" onClick={this.togglePersonalizationVersion}>
{version === 1
? "Enable V2 Personalization"
: "Enable V1 Personalization"}
</button>
<table>
<tbody>
<Row>
<td className="min">Personalization version</td>
<td>{version}</td>
</Row>
<Row>
<td className="min">Personalization Last Updated</td>
<td>{relativeTime(lastUpdated) || "(no data)"}</td>
</Row>
{version === 2 ? (
<Row>
<td className="min">Personalization V2 Initialized</td>
<td>{initialized ? "true" : "false"}</td>
</Row>
) : null}
</tbody>
</table>
</React.Fragment>
);
}
}
export class DiscoveryStreamAdmin extends React.PureComponent {
constructor(props) {
super(props);
@ -115,7 +167,7 @@ export class DiscoveryStreamAdmin extends React.PureComponent {
}
refreshCache() {
const { config } = this.props.state;
const { config } = this.props.state.DiscoveryStream;
this.props.dispatch(
ac.OnlyToMain({
type: at.DISCOVERY_STREAM_CONFIG_CHANGE,
@ -149,7 +201,7 @@ export class DiscoveryStreamAdmin extends React.PureComponent {
}
changeEndpointVariant(event) {
const endpoint = this.props.state.config.layout_endpoint;
const endpoint = this.props.state.DiscoveryStream.config.layout_endpoint;
if (endpoint) {
this.setConfigValue(
"layout_endpoint",
@ -180,13 +232,13 @@ export class DiscoveryStreamAdmin extends React.PureComponent {
}
isCurrentVariant(id) {
const endpoint = this.props.state.config.layout_endpoint;
const endpoint = this.props.state.DiscoveryStream.config.layout_endpoint;
const isMatch = endpoint && !!endpoint.match(`layout_variant=${id}`);
return isMatch;
}
renderFeedData(url) {
const { feeds } = this.props.state;
const { feeds } = this.props.state.DiscoveryStream;
const feed = feeds.data[url].data;
return (
<React.Fragment>
@ -201,7 +253,7 @@ export class DiscoveryStreamAdmin extends React.PureComponent {
}
renderFeedsData() {
const { feeds } = this.props.state;
const { feeds } = this.props.state.DiscoveryStream;
return (
<React.Fragment>
{Object.keys(feeds.data).map(url => this.renderFeedData(url))}
@ -210,7 +262,7 @@ export class DiscoveryStreamAdmin extends React.PureComponent {
}
renderSpocs() {
const { spocs } = this.props.state;
const { spocs } = this.props.state.DiscoveryStream;
let spocsData = [];
if (spocs.data && spocs.data.spocs && spocs.data.spocs.length) {
spocsData = spocs.data.spocs;
@ -275,7 +327,7 @@ export class DiscoveryStreamAdmin extends React.PureComponent {
}
renderFeed(feed) {
const { feeds } = this.props.state;
const { feeds } = this.props.state.DiscoveryStream;
if (!feed.url) {
return null;
}
@ -301,7 +353,7 @@ export class DiscoveryStreamAdmin extends React.PureComponent {
const prefToggles = "enabled hardcoded_layout show_spocs personalized collapsible".split(
" "
);
const { config, lastUpdated, layout } = this.props.state;
const { config, lastUpdated, layout } = this.props.state.DiscoveryStream;
return (
<div>
<button className="button" onClick={this.restorePrefDefaults}>
@ -385,10 +437,17 @@ export class DiscoveryStreamAdmin extends React.PureComponent {
))}
</div>
))}
<h3>Feeds Data</h3>
{this.renderFeedsData()}
<h3>Personalization</h3>
<Personalization
dispatch={this.props.dispatch}
state={{
Personalization: this.props.state.Personalization,
}}
/>
<h3>Spocs</h3>
{this.renderSpocs()}
<h3>Feeds Data</h3>
{this.renderFeedsData()}
</div>
);
}
@ -1378,7 +1437,10 @@ export class ASRouterAdminInner extends React.PureComponent {
<React.Fragment>
<h2>Discovery Stream</h2>
<DiscoveryStreamAdmin
state={this.props.DiscoveryStream}
state={{
DiscoveryStream: this.props.DiscoveryStream,
Personalization: this.props.Personalization,
}}
otherPrefs={this.props.Prefs.values}
dispatch={this.props.dispatch}
/>
@ -1547,5 +1609,6 @@ const _ASRouterAdmin = props => (
export const ASRouterAdmin = connect(state => ({
Sections: state.Sections,
DiscoveryStream: state.DiscoveryStream,
Personalization: state.Personalization,
Prefs: state.Prefs,
}))(_ASRouterAdmin);

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

@ -194,7 +194,7 @@ const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS :
// }
const actionTypes = {};
for (const type of ["ADDONS_INFO_REQUEST", "ADDONS_INFO_RESPONSE", "ARCHIVE_FROM_POCKET", "AS_ROUTER_INITIALIZED", "AS_ROUTER_PREF_CHANGED", "AS_ROUTER_TARGETING_UPDATE", "AS_ROUTER_TELEMETRY_USER_EVENT", "BLOCK_URL", "BOOKMARK_URL", "CLEAR_PREF", "COPY_DOWNLOAD_LINK", "DELETE_BOOKMARK_BY_ID", "DELETE_FROM_POCKET", "DELETE_HISTORY_URL", "DIALOG_CANCEL", "DIALOG_OPEN", "DISCOVERY_STREAM_CONFIG_CHANGE", "DISCOVERY_STREAM_CONFIG_RESET_DEFAULTS", "DISCOVERY_STREAM_CONFIG_SETUP", "DISCOVERY_STREAM_CONFIG_SET_VALUE", "DISCOVERY_STREAM_DEV_EXPIRE_CACHE", "DISCOVERY_STREAM_DEV_IDLE_DAILY", "DISCOVERY_STREAM_DEV_SYNC_RS", "DISCOVERY_STREAM_DEV_SYSTEM_TICK", "DISCOVERY_STREAM_FEEDS_UPDATE", "DISCOVERY_STREAM_FEED_UPDATE", "DISCOVERY_STREAM_IMPRESSION_STATS", "DISCOVERY_STREAM_LAYOUT_RESET", "DISCOVERY_STREAM_LAYOUT_UPDATE", "DISCOVERY_STREAM_LINK_BLOCKED", "DISCOVERY_STREAM_LOADED_CONTENT", "DISCOVERY_STREAM_RETRY_FEED", "DISCOVERY_STREAM_SPOCS_CAPS", "DISCOVERY_STREAM_SPOCS_ENDPOINT", "DISCOVERY_STREAM_SPOCS_FILL", "DISCOVERY_STREAM_SPOCS_PLACEMENTS", "DISCOVERY_STREAM_SPOCS_UPDATE", "DISCOVERY_STREAM_SPOC_BLOCKED", "DISCOVERY_STREAM_SPOC_IMPRESSION", "DOWNLOAD_CHANGED", "FAKE_FOCUS_SEARCH", "FILL_SEARCH_TERM", "HANDOFF_SEARCH_TO_AWESOMEBAR", "HIDE_PRIVACY_INFO", "HIDE_SEARCH", "INIT", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_DOWNLOAD_FILE", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "OPEN_WEBEXT_SETTINGS", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINKS_CHANGED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PLACES_SAVED_TO_POCKET", "POCKET_CTA", "POCKET_LINK_DELETED_OR_ARCHIVED", "POCKET_LOGGED_IN", "POCKET_WAITING_FOR_SPOC", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "PREVIEW_REQUEST", "PREVIEW_REQUEST_CANCEL", "PREVIEW_RESPONSE", "REMOVE_DOWNLOAD_FILE", "RICH_ICON_MISSING", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_MOVE", "SECTION_OPTIONS_CHANGED", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SETTINGS_CLOSE", "SETTINGS_OPEN", "SET_PREF", "SHOW_DOWNLOAD_FILE", "SHOW_FIREFOX_ACCOUNTS", "SHOW_PRIVACY_INFO", "SHOW_SEARCH", "SKIPPED_SIGNIN", "SNIPPETS_BLOCKLIST_CLEARED", "SNIPPETS_BLOCKLIST_UPDATED", "SNIPPETS_DATA", "SNIPPETS_PREVIEW_MODE", "SNIPPETS_RESET", "SNIPPET_BLOCKED", "SUBMIT_EMAIL", "SUBMIT_SIGNIN", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_EDIT", "TOP_SITES_INSERT", "TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_PIN", "TOP_SITES_PREFS_UPDATED", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "TOTAL_BOOKMARKS_REQUEST", "TOTAL_BOOKMARKS_RESPONSE", "TRAILHEAD_ENROLL_EVENT", "UNINIT", "UPDATE_PINNED_SEARCH_SHORTCUTS", "UPDATE_SEARCH_SHORTCUTS", "UPDATE_SECTION_PREFS", "WEBEXT_CLICK", "WEBEXT_DISMISS"]) {
for (const type of ["ADDONS_INFO_REQUEST", "ADDONS_INFO_RESPONSE", "ARCHIVE_FROM_POCKET", "AS_ROUTER_INITIALIZED", "AS_ROUTER_PREF_CHANGED", "AS_ROUTER_TARGETING_UPDATE", "AS_ROUTER_TELEMETRY_USER_EVENT", "BLOCK_URL", "BOOKMARK_URL", "CLEAR_PREF", "COPY_DOWNLOAD_LINK", "DELETE_BOOKMARK_BY_ID", "DELETE_FROM_POCKET", "DELETE_HISTORY_URL", "DIALOG_CANCEL", "DIALOG_OPEN", "DISCOVERY_STREAM_CONFIG_CHANGE", "DISCOVERY_STREAM_CONFIG_RESET_DEFAULTS", "DISCOVERY_STREAM_CONFIG_SETUP", "DISCOVERY_STREAM_CONFIG_SET_VALUE", "DISCOVERY_STREAM_DEV_EXPIRE_CACHE", "DISCOVERY_STREAM_DEV_IDLE_DAILY", "DISCOVERY_STREAM_DEV_SYNC_RS", "DISCOVERY_STREAM_DEV_SYSTEM_TICK", "DISCOVERY_STREAM_FEEDS_UPDATE", "DISCOVERY_STREAM_FEED_UPDATE", "DISCOVERY_STREAM_IMPRESSION_STATS", "DISCOVERY_STREAM_LAYOUT_RESET", "DISCOVERY_STREAM_LAYOUT_UPDATE", "DISCOVERY_STREAM_LINK_BLOCKED", "DISCOVERY_STREAM_LOADED_CONTENT", "DISCOVERY_STREAM_PERSONALIZATION_INIT", "DISCOVERY_STREAM_PERSONALIZATION_LAST_UPDATED", "DISCOVERY_STREAM_PERSONALIZATION_VERSION", "DISCOVERY_STREAM_PERSONALIZATION_VERSION_TOGGLE", "DISCOVERY_STREAM_RETRY_FEED", "DISCOVERY_STREAM_SPOCS_CAPS", "DISCOVERY_STREAM_SPOCS_ENDPOINT", "DISCOVERY_STREAM_SPOCS_FILL", "DISCOVERY_STREAM_SPOCS_PLACEMENTS", "DISCOVERY_STREAM_SPOCS_UPDATE", "DISCOVERY_STREAM_SPOC_BLOCKED", "DISCOVERY_STREAM_SPOC_IMPRESSION", "DOWNLOAD_CHANGED", "FAKE_FOCUS_SEARCH", "FILL_SEARCH_TERM", "HANDOFF_SEARCH_TO_AWESOMEBAR", "HIDE_PRIVACY_INFO", "HIDE_SEARCH", "INIT", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_DOWNLOAD_FILE", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "OPEN_WEBEXT_SETTINGS", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINKS_CHANGED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PLACES_SAVED_TO_POCKET", "POCKET_CTA", "POCKET_LINK_DELETED_OR_ARCHIVED", "POCKET_LOGGED_IN", "POCKET_WAITING_FOR_SPOC", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "PREVIEW_REQUEST", "PREVIEW_REQUEST_CANCEL", "PREVIEW_RESPONSE", "REMOVE_DOWNLOAD_FILE", "RICH_ICON_MISSING", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_MOVE", "SECTION_OPTIONS_CHANGED", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SETTINGS_CLOSE", "SETTINGS_OPEN", "SET_PREF", "SHOW_DOWNLOAD_FILE", "SHOW_FIREFOX_ACCOUNTS", "SHOW_PRIVACY_INFO", "SHOW_SEARCH", "SKIPPED_SIGNIN", "SNIPPETS_BLOCKLIST_CLEARED", "SNIPPETS_BLOCKLIST_UPDATED", "SNIPPETS_DATA", "SNIPPETS_PREVIEW_MODE", "SNIPPETS_RESET", "SNIPPET_BLOCKED", "SUBMIT_EMAIL", "SUBMIT_SIGNIN", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_EDIT", "TOP_SITES_INSERT", "TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_PIN", "TOP_SITES_PREFS_UPDATED", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "TOTAL_BOOKMARKS_REQUEST", "TOTAL_BOOKMARKS_RESPONSE", "TRAILHEAD_ENROLL_EVENT", "UNINIT", "UPDATE_PINNED_SEARCH_SHORTCUTS", "UPDATE_SEARCH_SHORTCUTS", "UPDATE_SECTION_PREFS", "WEBEXT_CLICK", "WEBEXT_DISMISS"]) {
actionTypes[type] = type;
} // These are acceptable actions for AS Router messages to have. They can show up
// as call-to-action buttons in snippets, onboarding tour, etc.
@ -755,6 +755,7 @@ const Base = Object(react_redux__WEBPACK_IMPORTED_MODULE_4__["connect"])(state =
__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ToggleStoryButton", function() { return ToggleStoryButton; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TogglePrefCheckbox", function() { return TogglePrefCheckbox; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Personalization", function() { return Personalization; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DiscoveryStreamAdmin", function() { return DiscoveryStreamAdmin; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ASRouterAdminInner", function() { return ASRouterAdminInner; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CollapseToggle", function() { return CollapseToggle; });
@ -845,6 +846,37 @@ class TogglePrefCheckbox extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
}), " ", this.props.pref, " ");
}
}
class Personalization extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
constructor(props) {
super(props);
this.togglePersonalizationVersion = this.togglePersonalizationVersion.bind(this);
}
togglePersonalizationVersion() {
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DISCOVERY_STREAM_PERSONALIZATION_VERSION_TOGGLE
}));
}
render() {
const {
lastUpdated,
version,
initialized
} = this.props.state.Personalization;
return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
className: "button",
onClick: this.togglePersonalizationVersion
}, version === 1 ? "Enable V2 Personalization" : "Enable V1 Personalization"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Row, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
className: "min"
}, "Personalization version"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, version)), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Row, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
className: "min"
}, "Personalization Last Updated"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, relativeTime(lastUpdated) || "(no data)")), version === 2 ? react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Row, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
className: "min"
}, "Personalization V2 Initialized"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, initialized ? "true" : "false")) : null)));
}
}
class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
constructor(props) {
@ -882,7 +914,7 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
refreshCache() {
const {
config
} = this.props.state;
} = this.props.state.DiscoveryStream;
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DISCOVERY_STREAM_CONFIG_CHANGE,
data: config
@ -912,7 +944,7 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
}
changeEndpointVariant(event) {
const endpoint = this.props.state.config.layout_endpoint;
const endpoint = this.props.state.DiscoveryStream.config.layout_endpoint;
if (endpoint) {
this.setConfigValue("layout_endpoint", endpoint.replace(/layout_variant=.+/, `layout_variant=${event.target.value}`));
@ -928,7 +960,7 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
}
isCurrentVariant(id) {
const endpoint = this.props.state.config.layout_endpoint;
const endpoint = this.props.state.DiscoveryStream.config.layout_endpoint;
const isMatch = endpoint && !!endpoint.match(`layout_variant=${id}`);
return isMatch;
}
@ -936,7 +968,7 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
renderFeedData(url) {
const {
feeds
} = this.props.state;
} = this.props.state.DiscoveryStream;
const feed = feeds.data[url].data;
return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h4", null, "Feed url: ", url), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, feed.recommendations.map(story => this.renderStoryData(story)))));
}
@ -944,14 +976,14 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
renderFeedsData() {
const {
feeds
} = this.props.state;
} = this.props.state.DiscoveryStream;
return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, Object.keys(feeds.data).map(url => this.renderFeedData(url)));
}
renderSpocs() {
const {
spocs
} = this.props.state;
} = this.props.state.DiscoveryStream;
let spocsData = [];
if (spocs.data && spocs.data.spocs && spocs.data.spocs.length) {
@ -999,7 +1031,7 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
renderFeed(feed) {
const {
feeds
} = this.props.state;
} = this.props.state.DiscoveryStream;
if (!feed.url) {
return null;
@ -1018,7 +1050,7 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
config,
lastUpdated,
layout
} = this.props.state;
} = this.props.state.DiscoveryStream;
return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
className: "button",
onClick: this.restorePrefDefaults
@ -1069,7 +1101,12 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
}, row.components.map((component, componentIndex) => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
key: `component-${componentIndex}`,
className: "ds-component"
}, this.renderComponent(row.width, component))))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", null, "Feeds Data"), this.renderFeedsData(), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", null, "Spocs"), this.renderSpocs());
}, this.renderComponent(row.width, component))))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", null, "Personalization"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Personalization, {
dispatch: this.props.dispatch,
state: {
Personalization: this.props.state.Personalization
}
}), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", null, "Spocs"), this.renderSpocs(), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", null, "Feeds Data"), this.renderFeedsData());
}
}
@ -1768,7 +1805,10 @@ class ASRouterAdminInner extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
case "ds":
return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, "Discovery Stream"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(DiscoveryStreamAdmin, {
state: this.props.DiscoveryStream,
state: {
DiscoveryStream: this.props.DiscoveryStream,
Personalization: this.props.Personalization
},
otherPrefs: this.props.Prefs.values,
dispatch: this.props.dispatch
}));
@ -1889,6 +1929,7 @@ const _ASRouterAdmin = props => react__WEBPACK_IMPORTED_MODULE_4___default.a.cre
const ASRouterAdmin = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])(state => ({
Sections: state.Sections,
DiscoveryStream: state.DiscoveryStream,
Personalization: state.Personalization,
Prefs: state.Prefs
}))(_ASRouterAdmin);
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
@ -14141,6 +14182,7 @@ class Dedupe {
const TOP_SITES_DEFAULT_ROWS = 1;
const TOP_SITES_MAX_SITES_PER_ROW = 8;
const PREF_PERSONALIZATION_VERSION = "discoverystream.personalization.version";
const dedupe = new Dedupe(site => site && site.url);
const INITIAL_STATE = {
App: {
@ -14206,6 +14248,11 @@ const INITIAL_STATE = {
placements: []
}
},
Personalization: {
version: 1,
lastUpdated: null,
initialized: false
},
Search: {
// When search hand-off is enabled, we render a big button that is styled to
// look like a search textbox. If the button is clicked, we style
@ -14745,6 +14792,37 @@ function Pocket(prevState = INITIAL_STATE.Pocket, action) {
}
}
function Personalization(prevState = INITIAL_STATE.Personalization, action) {
switch (action.type) {
case Actions["actionTypes"].DISCOVERY_STREAM_PERSONALIZATION_VERSION:
return { ...prevState,
version: action.data.version
};
case Actions["actionTypes"].DISCOVERY_STREAM_PERSONALIZATION_LAST_UPDATED:
return { ...prevState,
lastUpdated: action.data.lastUpdated
};
case Actions["actionTypes"].DISCOVERY_STREAM_PERSONALIZATION_INIT:
return { ...prevState,
initialized: true
};
case Actions["actionTypes"].PREF_CHANGED:
if (action.data.name === PREF_PERSONALIZATION_VERSION) {
return { ...prevState,
version: action.data.value
};
}
return prevState;
default:
return prevState;
}
}
function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
// Return if action data is empty, or spocs or feeds data is not loaded
const isNotReady = () => !action.data || !prevState.spocs.loaded || !prevState.feeds.loaded;
@ -14982,6 +15060,7 @@ var reducers = {
Dialog,
Sections,
Pocket,
Personalization,
DiscoveryStream,
Search
};

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

@ -234,6 +234,13 @@ const PREFS_CONFIG = new Map([
}),
},
],
[
"discoverystream.personalization.version",
{
title: "",
value: 1,
},
],
[
"showSponsored",
{

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

@ -70,6 +70,7 @@ const PREF_SHOW_SPONSORED = "showSponsored";
const PREF_SPOC_IMPRESSIONS = "discoverystream.spoc.impressions";
const PREF_FLIGHT_BLOCKS = "discoverystream.flight.blocks";
const PREF_REC_IMPRESSIONS = "discoverystream.rec.impressions";
const PREF_PERSONALIZATION_VERSION = "discoverystream.personalization.version";
let getHardcodedLayout;
@ -1169,10 +1170,29 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
}
}
/**
* Sets affinityProvider state to the correct version.
*/
setAffinityProviderVersion() {
const version = this.store.getState().Prefs.values[
PREF_PERSONALIZATION_VERSION
];
this.store.dispatch(
ac.BroadcastToContent({
type: at.DISCOVERY_STREAM_PERSONALIZATION_VERSION,
data: {
version,
},
})
);
}
async enable() {
// Note that cache age needs to be reported prior to refreshAll.
await this.reportCacheAge();
const start = perfService.absNow();
this.setAffinityProviderVersion();
await this.refreshAll({ updateOpenTabs: true, isStartup: true });
Services.obs.addObserver(this, "idle-daily");
this.loaded = true;
@ -1314,6 +1334,7 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
case PREF_HARDCODED_BASIC_LAYOUT:
case PREF_SPOCS_ENDPOINT:
case PREF_LANG_LAYOUT_CONFIG:
case PREF_PERSONALIZATION_VERSION:
// Clear the cached config and broadcast the newly computed value
this._prefCache.config = null;
this.store.dispatch(
@ -1375,6 +1396,16 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
case at.DISCOVERY_STREAM_DEV_EXPIRE_CACHE:
await this.resetCache();
break;
case at.DISCOVERY_STREAM_PERSONALIZATION_VERSION_TOGGLE:
let version = this.store.getState().Prefs.values[
PREF_PERSONALIZATION_VERSION
];
// Toggle the version between 1 and 2.
this.store.dispatch(
ac.SetPref(PREF_PERSONALIZATION_VERSION, version === 1 ? 2 : 1)
);
break;
case at.DISCOVERY_STREAM_CONFIG_SET_VALUE:
// Use the original string pref to then set a value instead of
// this.config which has some modifications

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

@ -7,6 +7,7 @@ const {
Dialog,
Sections,
Pocket,
Personalization,
DiscoveryStream,
Search,
ASRouter,
@ -893,6 +894,48 @@ describe("Reducers", () => {
assert.equal(state.pocketCta.useCta, data.use_cta);
});
});
describe("Personalization", () => {
it("should return INITIAL_STATE by default", () => {
assert.equal(
Personalization(undefined, { type: "some_action" }),
INITIAL_STATE.Personalization
);
});
it("should set version to 2 with DISCOVERY_STREAM_PERSONALIZATION_VERSION", () => {
const state = Personalization(undefined, {
type: at.DISCOVERY_STREAM_PERSONALIZATION_VERSION,
data: {
version: 2,
},
});
assert.equal(state.version, 2);
});
it("should set version to 2 with PREF_CHANGED", () => {
const state = Personalization(undefined, {
type: at.PREF_CHANGED,
data: {
name: "discoverystream.personalization.version",
value: 2,
},
});
assert.equal(state.version, 2);
});
it("should set lastUpdated with DISCOVERY_STREAM_PERSONALIZATION_LAST_UPDATED", () => {
const state = Personalization(undefined, {
type: at.DISCOVERY_STREAM_PERSONALIZATION_LAST_UPDATED,
data: {
lastUpdated: 123,
},
});
assert.equal(state.lastUpdated, 123);
});
it("should set initialized to true with DISCOVERY_STREAM_PERSONALIZATION_INIT", () => {
const state = Personalization(undefined, {
type: at.DISCOVERY_STREAM_PERSONALIZATION_INIT,
});
assert.equal(state.initialized, true);
});
});
describe("DiscoveryStream", () => {
it("should return INITIAL_STATE by default", () => {
assert.equal(

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

@ -3,6 +3,7 @@ import {
ASRouterAdminInner,
CollapseToggle,
DiscoveryStreamAdmin,
Personalization,
ToggleStoryButton,
} from "content-src/components/ASRouterAdmin/ASRouterAdmin";
import { GlobalOverrider } from "test/unit/utils";
@ -332,7 +333,9 @@ describe("ASRouterAdmin", () => {
<DiscoveryStreamAdmin
dispatch={dispatch}
otherPrefs={{}}
state={state}
state={{
DiscoveryStream: state,
}}
/>
);
});
@ -356,7 +359,12 @@ describe("ASRouterAdmin", () => {
],
},
};
wrapper = shallow(<DiscoveryStreamAdmin otherPrefs={{}} state={state} />);
wrapper = shallow(
<DiscoveryStreamAdmin
otherPrefs={{}}
state={{ DiscoveryStream: state }}
/>
);
wrapper.instance().onStoryToggle({ id: 12345 });
const messageSummary = wrapper.find(".message-summary").at(0);
const pre = messageSummary.find("pre").at(0);
@ -449,6 +457,110 @@ describe("ASRouterAdmin", () => {
);
});
});
describe("#Personalization", () => {
let dispatch;
beforeEach(() => {
dispatch = sandbox.stub();
wrapper = shallow(
<Personalization
dispatch={dispatch}
state={{
Personalization: {
version: 1,
lastUpdated: 1000,
initialized: true,
},
}}
/>
);
});
it("should render with buttons, version, and lastUpdated", () => {
assert.equal(
wrapper
.find("button")
.at(0)
.text(),
"Enable V2 Personalization"
);
assert.equal(
wrapper
.find("td")
.at(1)
.text(),
"1"
);
assert.equal(
wrapper
.find("td")
.at(3)
.text(),
"12/31/1969, 7:00:01 PM"
);
});
it("should render with proper version 2 state", () => {
wrapper = shallow(
<Personalization
dispatch={dispatch}
state={{
Personalization: {
version: 2,
lastUpdated: 1000,
initialized: true,
},
}}
/>
);
assert.equal(
wrapper
.find("button")
.at(0)
.text(),
"Enable V1 Personalization"
);
assert.equal(
wrapper
.find("td")
.at(1)
.text(),
"2"
);
});
it("should render with no data with no last updated", () => {
wrapper = shallow(
<Personalization
dispatch={dispatch}
state={{
Personalization: {
version: 2,
lastUpdated: 0,
initialized: true,
},
}}
/>
);
assert.equal(
wrapper
.find("td")
.at(3)
.text(),
"(no data)"
);
});
it("should fire DISCOVERY_STREAM_PERSONALIZATION_VERSION_TOGGLE with version", () => {
wrapper
.find("button")
.at(0)
.simulate("click");
assert.calledWith(
dispatch,
ac.OnlyToMain({
type: at.DISCOVERY_STREAM_PERSONALIZATION_VERSION_TOGGLE,
})
);
});
});
describe("#ToggleStoryButton", () => {
it("should fire onClick in toggle button", async () => {
let result = "";

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

@ -2032,6 +2032,27 @@ describe("DiscoveryStreamFeed", () => {
});
});
describe("#onAction: DISCOVERY_STREAM_PERSONALIZATION_VERSION_TOGGLE", () => {
it("should fire SET_PREF with version", async () => {
sandbox.spy(feed.store, "dispatch");
feed.store.getState = () => ({
Prefs: {
values: {
"discoverystream.personalization.version": 1,
},
},
});
await feed.onAction({
type: at.DISCOVERY_STREAM_PERSONALIZATION_VERSION_TOGGLE,
});
assert.calledWith(
feed.store.dispatch,
ac.SetPref("discoverystream.personalization.version", 2)
);
});
});
describe("#onAction: DISCOVERY_STREAM_DEV_IDLE_DAILY", () => {
it("should trigger idle-daily observer", async () => {
sandbox.stub(global.Services.obs, "notifyObservers").returns();
@ -2349,6 +2370,48 @@ describe("DiscoveryStreamFeed", () => {
});
});
describe("#setAffinityProviderVersion", () => {
beforeEach(() => {
sandbox.spy(feed.store, "dispatch");
});
it("should properly set affinity provider with version 1", async () => {
feed.store.getState = () => ({
Prefs: {
values: {
"discoverystream.personalization.version": 1,
},
},
});
feed.setAffinityProviderVersion();
assert.calledWith(
feed.store.dispatch,
ac.BroadcastToContent({
type: at.DISCOVERY_STREAM_PERSONALIZATION_VERSION,
data: { version: 1 },
})
);
assert.equal(feed.affinityProviderV2, null);
});
it("should properly set affinity provider with version 2", async () => {
feed.store.getState = () => ({
Prefs: {
values: {
"discoverystream.personalization.modelKeys": "1,2,3,4",
"discoverystream.personalization.version": 2,
},
},
});
feed.setAffinityProviderVersion();
assert.calledWith(
feed.store.dispatch,
ac.BroadcastToContent({
type: at.DISCOVERY_STREAM_PERSONALIZATION_VERSION,
data: { version: 2 },
})
);
});
});
describe("#reportCacheAge", () => {
let cache;
const cacheAge = 30;