Commit 1eca54dd authored by Natalie Chouinard's avatar Natalie Chouinard Committed by Commit Bot

[Feed Internals] Add current content

This internals page is used to surface debugging information useful to
developers of the NTP Interest Feed. This CL surfaces the current
Feed content, including suggestion titles, URLs and other metadata.

https://screenshot.googleplex.com/gGGcX0BZkYM

Bug: 913126
Change-Id: I48dd63698229f43bb1671a0035e7c0b6cf34559a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1506539
Commit-Queue: Natalie Chouinard <chouinard@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarSky Malice <skym@chromium.org>
Reviewed-by: default avatarBrandon Wylie <wylieb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#638700}
parent 168598ea
......@@ -10,6 +10,7 @@ h2 {
}
table {
table-layout: fixed;
width: 100%;
}
......@@ -19,9 +20,14 @@ table > tbody > tr:nth-child(odd) {
table td {
width: 50%;
word-wrap: break-word;
}
button {
display: block;
min-height: 30px;
}
#current-content table td:first-child {
width: 15%;
}
......@@ -23,6 +23,7 @@ found in the LICENSE file.
</head>
<body>
<h2>Properties</h2>
<table>
<tr>
......@@ -30,6 +31,7 @@ found in the LICENSE file.
<td id="is-feed-enabled"></td>
</tr>
</table>
<h2>User Classifier</h2>
<table>
<tr>
......@@ -52,6 +54,7 @@ found in the LICENSE file.
<button id="clear-cached-data">
Clear Cache & Refresh Feed
</button>
<h2>Last Fetch</h2>
<table>
<tr>
......@@ -67,5 +70,33 @@ found in the LICENSE file.
<td id="refresh-suppress-time"></td>
</tr>
</table>
<h2>Current Content</h2>
<div id="current-content">
<template id="suggestion-template">
<details>
<summary class="title"></summary>
<table>
<tr>
<td>Publisher Name</td>
<td class="publisher"></td>
</tr>
<tr>
<td>URL</td>
<td><a class="url"></a></td>
</tr>
<tr>
<td>Favicon URL</td>
<td><a class="favicon"></a></td>
</tr>
<tr>
<td>Image URL</td>
<td><a class="image"></a></td>
</tr>
</table>
</details>
</template>
</div>
</body>
</html>
......@@ -50,6 +50,48 @@ function updatePageWithLastFetchProperties() {
});
}
/**
* Get and display last known content.
*/
function updatePageWithCurrentContent() {
pageHandler.getCurrentContent().then(response => {
const before = $('current-content');
const after = before.cloneNode(false);
/** @type {!Array<feedInternals.mojom.Suggestion>} */
const suggestions = response.suggestions;
for (const suggestion of suggestions) {
// Create new content item from template.
const item = document.importNode($('suggestion-template').content, true);
// Populate template with text metadata.
item.querySelector('.title').textContent = suggestion.title;
item.querySelector('.publisher').textContent = suggestion.publisherName;
// Populate template with link metadata.
setLinkNode(item.querySelector('a.url'), suggestion.url);
setLinkNode(item.querySelector('a.image'), suggestion.imageUrl);
setLinkNode(item.querySelector('a.favicon'), suggestion.faviconUrl);
after.appendChild(item);
}
before.replaceWith(after);
});
}
/**
* Populate <a> node with hyperlinked URL.
*
* @param {Element} node
* @param {string} url
*/
function setLinkNode(node, url) {
node.textContent = url;
node.href = url;
}
/**
* Convert time to string for display.
*
......@@ -78,6 +120,7 @@ function setupEventListeners() {
// consider adding backend->frontend mojo communication to listen for
// updates, rather than waiting an arbitrary period of time.
setTimeout(updatePageWithLastFetchProperties, 1000);
setTimeout(updatePageWithCurrentContent, 1000);
});
}
......@@ -88,6 +131,7 @@ document.addEventListener('DOMContentLoaded', function() {
updatePageWithProperties();
updatePageWithUserClass();
updatePageWithLastFetchProperties();
updatePageWithCurrentContent();
setupEventListeners();
});
......
......@@ -35,6 +35,24 @@ struct LastFetchProperties {
Time? refresh_suppress_time;
};
// Models a single suggestion in the Feed.
struct Suggestion {
// Title of the suggestion.
string title;
// URL of the suggested page.
string url;
// Name of the content's publisher.
string publisher_name;
// URL of the image associated with the suggestion.
string image_url;
// URL of the suggested page's favicon.
string favicon_url;
};
// Time wrapper to allow for nullable objects.
struct Time {
double ms_since_epoch;
......@@ -58,4 +76,7 @@ interface PageHandler {
// Clear all data cached by the Feed library. Also triggers a refresh of the
// Feed.
ClearCachedDataAndRefreshFeed();
// Get the last known content with metadata.
GetCurrentContent() => (array<Suggestion> suggestions);
};
......@@ -10,10 +10,12 @@
#include "base/time/time.h"
#include "chrome/browser/android/feed/feed_lifecycle_bridge.h"
#include "components/feed/content/feed_host_service.h"
#include "components/feed/content/feed_offline_host.h"
#include "components/feed/core/feed_scheduler_host.h"
#include "components/feed/core/pref_names.h"
#include "components/feed/core/user_classifier.h"
#include "components/feed/feed_feature_list.h"
#include "components/offline_pages/core/prefetch/suggestions_provider.h"
#include "components/prefs/pref_service.h"
namespace {
......@@ -31,7 +33,9 @@ FeedInternalsPageHandler::FeedInternalsPageHandler(
PrefService* pref_service)
: binding_(this, std::move(request)),
feed_scheduler_host_(feed_host_service->GetSchedulerHost()),
pref_service_(pref_service) {}
feed_offline_host_(feed_host_service->GetOfflineHost()),
pref_service_(pref_service),
weak_ptr_factory_(this) {}
FeedInternalsPageHandler::~FeedInternalsPageHandler() = default;
......@@ -84,3 +88,29 @@ void FeedInternalsPageHandler::ClearUserClassifierProperties() {
void FeedInternalsPageHandler::ClearCachedDataAndRefreshFeed() {
feed::FeedLifecycleBridge::ClearCachedData();
}
void FeedInternalsPageHandler::GetCurrentContent(
GetCurrentContentCallback callback) {
feed_offline_host_->GetCurrentArticleSuggestions(base::BindOnce(
&FeedInternalsPageHandler::OnGetCurrentArticleSuggestionsDone,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FeedInternalsPageHandler::OnGetCurrentArticleSuggestionsDone(
GetCurrentContentCallback callback,
std::vector<offline_pages::PrefetchSuggestion> results) {
std::vector<feed_internals::mojom::SuggestionPtr> suggestions;
for (offline_pages::PrefetchSuggestion result : results) {
auto suggestion = feed_internals::mojom::Suggestion::New();
suggestion->title = std::move(result.article_title);
suggestion->url = result.article_url.spec();
suggestion->publisher_name = std::move(result.article_attribution);
suggestion->image_url = result.thumbnail_url.spec();
suggestion->favicon_url = result.favicon_url.spec();
suggestions.push_back(std::move(suggestion));
}
std::move(callback).Run(std::move(suggestions));
}
......@@ -5,7 +5,10 @@
#ifndef CHROME_BROWSER_UI_WEBUI_FEED_INTERNALS_FEED_INTERNALS_PAGE_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_FEED_INTERNALS_FEED_INTERNALS_PAGE_HANDLER_H_
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ui/webui/feed_internals/feed_internals.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
......@@ -13,9 +16,14 @@ class PrefService;
namespace feed {
class FeedHostService;
class FeedOfflineHost;
class FeedSchedulerHost;
} // namespace feed
namespace offline_pages {
struct PrefetchSuggestion;
} // namespace offline_pages
// Concrete implementation of feed_internals::mojom::PageHandler.
class FeedInternalsPageHandler : public feed_internals::mojom::PageHandler {
public:
......@@ -31,15 +39,23 @@ class FeedInternalsPageHandler : public feed_internals::mojom::PageHandler {
void ClearUserClassifierProperties() override;
void GetLastFetchProperties(GetLastFetchPropertiesCallback) override;
void ClearCachedDataAndRefreshFeed() override;
void GetCurrentContent(GetCurrentContentCallback) override;
private:
// Binding from the mojo interface to concrete implementation.
mojo::Binding<feed_internals::mojom::PageHandler> binding_;
void OnGetCurrentArticleSuggestionsDone(
GetCurrentContentCallback callback,
std::vector<offline_pages::PrefetchSuggestion> suggestions);
// Services that provide the data and functionality.
feed::FeedSchedulerHost* feed_scheduler_host_;
feed::FeedOfflineHost* feed_offline_host_;
PrefService* pref_service_;
base::WeakPtrFactory<FeedInternalsPageHandler> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(FeedInternalsPageHandler);
};
......
......@@ -226,7 +226,7 @@ class FeedSchedulerHost : web_resource::EulaAcceptedNotifier::Observer {
throttlers_;
// Status of the last fetch for debugging.
int last_fetch_status_;
int last_fetch_status_ = 0;
DISALLOW_COPY_AND_ASSIGN(FeedSchedulerHost);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment