Commit 640ab571 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Media Feeds] Add basic webui for debugging

Add a basic webui at chrome://media-feeds
for debugging Media Feeds internals.

BUG=1058187

Change-Id: Ia769f103bdd5abfd6ff00754c26117e684d2fb03
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2086331
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Reviewed-by: default avatarcalamity <calamity@chromium.org>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748778}
parent 689bfd73
...@@ -1986,6 +1986,7 @@ jumbo_static_library("browser") { ...@@ -1986,6 +1986,7 @@ jumbo_static_library("browser") {
"//chrome/browser/image_decoder", "//chrome/browser/image_decoder",
"//chrome/browser/media:media_engagement_preload_proto", "//chrome/browser/media:media_engagement_preload_proto",
"//chrome/browser/media:mojo_bindings", "//chrome/browser/media:mojo_bindings",
"//chrome/browser/media/feeds:mojo_bindings",
"//chrome/browser/media/router", "//chrome/browser/media/router",
"//chrome/browser/metrics:expired_histograms_array", "//chrome/browser/metrics:expired_histograms_array",
"//chrome/browser/metrics/variations:chrome_ui_string_overrider_factory", "//chrome/browser/metrics/variations:chrome_ui_string_overrider_factory",
...@@ -5664,6 +5665,7 @@ grit("dev_ui_browser_resources") { ...@@ -5664,6 +5665,7 @@ grit("dev_ui_browser_resources") {
deps = [ deps = [
"//chrome/browser/engagement:mojo_bindings_js", "//chrome/browser/engagement:mojo_bindings_js",
"//chrome/browser/media:mojo_bindings_js", "//chrome/browser/media:mojo_bindings_js",
"//chrome/browser/media/feeds:mojo_bindings_js",
"//chrome/browser/ui/webui/interventions_internals:mojo_bindings_js", "//chrome/browser/ui/webui/interventions_internals:mojo_bindings_js",
] ]
if (is_android) { if (is_android) {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "chrome/browser/dom_distiller/dom_distiller_service_factory.h" #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h"
#include "chrome/browser/engagement/site_engagement_details.mojom.h" #include "chrome/browser/engagement/site_engagement_details.mojom.h"
#include "chrome/browser/language/translate_frame_binder.h" #include "chrome/browser/language/translate_frame_binder.h"
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "chrome/browser/media/history/media_history_store.mojom.h" #include "chrome/browser/media/history/media_history_store.mojom.h"
#include "chrome/browser/media/media_engagement_score_details.mojom.h" #include "chrome/browser/media/media_engagement_score_details.mojom.h"
#include "chrome/browser/navigation_predictor/navigation_predictor.h" #include "chrome/browser/navigation_predictor/navigation_predictor.h"
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
#include "chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom.h" #include "chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom.h"
#include "chrome/browser/ui/webui/interventions_internals/interventions_internals_ui.h" #include "chrome/browser/ui/webui/interventions_internals/interventions_internals_ui.h"
#include "chrome/browser/ui/webui/media/media_engagement_ui.h" #include "chrome/browser/ui/webui/media/media_engagement_ui.h"
#include "chrome/browser/ui/webui/media/media_feeds_ui.h"
#include "chrome/browser/ui/webui/media/media_history_ui.h" #include "chrome/browser/ui/webui/media/media_history_ui.h"
#include "chrome/browser/ui/webui/omnibox/omnibox.mojom.h" #include "chrome/browser/ui/webui/omnibox/omnibox.mojom.h"
#include "chrome/browser/ui/webui/omnibox/omnibox_ui.h" #include "chrome/browser/ui/webui/omnibox/omnibox_ui.h"
...@@ -430,6 +432,9 @@ void PopulateChromeWebUIFrameBinders( ...@@ -430,6 +432,9 @@ void PopulateChromeWebUIFrameBinders(
media::mojom::MediaEngagementScoreDetailsProvider, MediaEngagementUI>( media::mojom::MediaEngagementScoreDetailsProvider, MediaEngagementUI>(
map); map);
RegisterWebUIControllerInterfaceBinder<media_feeds::mojom::MediaFeedsStore,
MediaFeedsUI>(map);
RegisterWebUIControllerInterfaceBinder< RegisterWebUIControllerInterfaceBinder<
media_history::mojom::MediaHistoryStore, MediaHistoryUI>(map); media_history::mojom::MediaHistoryStore, MediaHistoryUI>(map);
......
...@@ -43,6 +43,9 @@ This file specifies browser resources for developer-facing chrome:// pages ...@@ -43,6 +43,9 @@ This file specifies browser resources for developer-facing chrome:// pages
<include name="IDR_MEDIA_ENGAGEMENT_HTML" file="resources\media\media_engagement.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" /> <include name="IDR_MEDIA_ENGAGEMENT_HTML" file="resources\media\media_engagement.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
<include name="IDR_MEDIA_ENGAGEMENT_JS" file="resources\media\media_engagement.js" flattenhtml="true" type="BINDATA" compress="gzip" /> <include name="IDR_MEDIA_ENGAGEMENT_JS" file="resources\media\media_engagement.js" flattenhtml="true" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_ENGAGEMENT_SCORE_DETAILS_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\media_engagement_score_details.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" /> <include name="IDR_MEDIA_ENGAGEMENT_SCORE_DETAILS_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\media_engagement_score_details.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_FEEDS_HTML" file="resources\media\media_feeds.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
<include name="IDR_MEDIA_FEEDS_JS" file="resources\media\media_feeds.js" flattenhtml="true" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_FEEDS_STORE_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\feeds\media_feeds_store.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_HISTORY_HTML" file="resources\media\media_history.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" /> <include name="IDR_MEDIA_HISTORY_HTML" file="resources\media\media_history.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
<include name="IDR_MEDIA_HISTORY_JS" file="resources\media\media_history.js" flattenhtml="true" type="BINDATA" compress="gzip" /> <include name="IDR_MEDIA_HISTORY_JS" file="resources\media\media_history.js" flattenhtml="true" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_HISTORY_STORE_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\history\media_history_store.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" /> <include name="IDR_MEDIA_HISTORY_STORE_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\history\media_history_store.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
......
# Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojo_bindings") {
sources = [ "media_feeds_store.mojom" ]
public_deps = [ "//url/mojom:url_mojom_origin" ]
}
...@@ -4,3 +4,6 @@ ...@@ -4,3 +4,6 @@
beccahughes@chromium.org beccahughes@chromium.org
sgbowen@google.com sgbowen@google.com
steimel@chromium.org steimel@chromium.org
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module media_feeds.mojom;
import "url/mojom/url.mojom";
struct MediaFeed {
// The ID of the field in storage.
int64 id;
// The URL for the discovered feed.
url.mojom.Url url;
};
// MediaFeedStore allows the Media Feeds WebUI to access data from the Media
// Feeds backend in the browser process for diagnostic purposes.
interface MediaFeedsStore {
// Gets all the discovered media feeds.
GetMediaFeeds() => (array<MediaFeed> feeds);
};
...@@ -74,4 +74,29 @@ bool MediaHistoryFeedsTable::SaveFeed(const GURL& url) { ...@@ -74,4 +74,29 @@ bool MediaHistoryFeedsTable::SaveFeed(const GURL& url) {
return statement.Run(); return statement.Run();
} }
std::vector<media_feeds::mojom::MediaFeedPtr>
MediaHistoryFeedsTable::GetRows() {
std::vector<media_feeds::mojom::MediaFeedPtr> feeds;
if (!CanAccessDatabase())
return feeds;
sql::Statement statement(
DB()->GetUniqueStatement(base::StringPrintf("SELECT id, url "
"FROM %s",
kTableName)
.c_str()));
while (statement.Step()) {
media_feeds::mojom::MediaFeedPtr feed(media_feeds::mojom::MediaFeed::New());
feed->id = statement.ColumnInt64(0);
feed->url = GURL(statement.ColumnString(1));
feeds.push_back(std::move(feed));
}
DCHECK(statement.Succeeded());
return feeds;
}
} // namespace media_history } // namespace media_history
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_FEEDS_TABLE_H_ #ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_FEEDS_TABLE_H_
#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_FEEDS_TABLE_H_ #define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_FEEDS_TABLE_H_
#include <vector>
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "chrome/browser/media/history/media_history_table_base.h" #include "chrome/browser/media/history/media_history_table_base.h"
#include "sql/init_status.h" #include "sql/init_status.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -33,6 +36,9 @@ class MediaHistoryFeedsTable : public MediaHistoryTableBase { ...@@ -33,6 +36,9 @@ class MediaHistoryFeedsTable : public MediaHistoryTableBase {
// Saves a newly discovered feed in the database. // Saves a newly discovered feed in the database.
bool SaveFeed(const GURL& url); bool SaveFeed(const GURL& url);
// Returns the feed rows in the database.
std::vector<media_feeds::mojom::MediaFeedPtr> GetRows();
}; };
} // namespace media_history } // namespace media_history
......
...@@ -185,4 +185,10 @@ void MediaHistoryKeyedService::PostTaskToDBForTest(base::OnceClosure callback) { ...@@ -185,4 +185,10 @@ void MediaHistoryKeyedService::PostTaskToDBForTest(base::OnceClosure callback) {
store_->GetForRead()->PostTaskToDBForTest(std::move(callback)); store_->GetForRead()->PostTaskToDBForTest(std::move(callback));
} }
void MediaHistoryKeyedService::GetMediaFeedsForDebug(
base::OnceCallback<void(std::vector<media_feeds::mojom::MediaFeedPtr>)>
callback) {
store_->GetForRead()->GetMediaFeedsForDebug(std::move(callback));
}
} // namespace media_history } // namespace media_history
...@@ -91,6 +91,12 @@ class MediaHistoryKeyedService : public KeyedService, ...@@ -91,6 +91,12 @@ class MediaHistoryKeyedService : public KeyedService,
// for waiting for database operations in tests. // for waiting for database operations in tests.
void PostTaskToDBForTest(base::OnceClosure callback); void PostTaskToDBForTest(base::OnceClosure callback);
// Returns all the rows in the media feeds table. This is only used for
// debugging because it loads all rows in the table.
void GetMediaFeedsForDebug(
base::OnceCallback<void(std::vector<media_feeds::mojom::MediaFeedPtr>)>
callback);
private: private:
class StoreHolder; class StoreHolder;
......
...@@ -73,6 +73,8 @@ class MediaHistoryStoreInternal ...@@ -73,6 +73,8 @@ class MediaHistoryStoreInternal
std::vector<mojom::MediaHistoryPlaybackRowPtr> std::vector<mojom::MediaHistoryPlaybackRowPtr>
GetMediaHistoryPlaybackRowsForDebug(); GetMediaHistoryPlaybackRowsForDebug();
std::vector<media_feeds::mojom::MediaFeedPtr> GetMediaFeedsForDebug();
void SavePlaybackSession( void SavePlaybackSession(
const GURL& url, const GURL& url,
const media_session::MediaMetadata& metadata, const media_session::MediaMetadata& metadata,
...@@ -313,6 +315,15 @@ MediaHistoryStoreInternal::GetMediaHistoryPlaybackRowsForDebug() { ...@@ -313,6 +315,15 @@ MediaHistoryStoreInternal::GetMediaHistoryPlaybackRowsForDebug() {
return playback_table_->GetPlaybackRows(); return playback_table_->GetPlaybackRows();
} }
std::vector<media_feeds::mojom::MediaFeedPtr>
MediaHistoryStoreInternal::GetMediaFeedsForDebug() {
DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!initialization_successful_ || !feeds_table_)
return std::vector<media_feeds::mojom::MediaFeedPtr>();
return feeds_table_->GetRows();
}
int MediaHistoryStoreInternal::GetTableRowCount(const std::string& table_name) { int MediaHistoryStoreInternal::GetTableRowCount(const std::string& table_name) {
DCHECK(db_task_runner_->RunsTasksInCurrentSequence()); DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!initialization_successful_) if (!initialization_successful_)
...@@ -542,6 +553,15 @@ void MediaHistoryStore::GetMediaHistoryPlaybackRowsForDebug( ...@@ -542,6 +553,15 @@ void MediaHistoryStore::GetMediaHistoryPlaybackRowsForDebug(
std::move(callback)); std::move(callback));
} }
void MediaHistoryStore::GetMediaFeedsForDebug(
base::OnceCallback<void(std::vector<media_feeds::mojom::MediaFeedPtr>)>
callback) {
base::PostTaskAndReplyWithResult(
db_->db_task_runner_.get(), FROM_HERE,
base::BindOnce(&MediaHistoryStoreInternal::GetMediaFeedsForDebug, db_),
std::move(callback));
}
void MediaHistoryStore::SavePlaybackSession( void MediaHistoryStore::SavePlaybackSession(
const GURL& url, const GURL& url,
const media_session::MediaMetadata& metadata, const media_session::MediaMetadata& metadata,
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/updateable_sequenced_task_runner.h" #include "base/updateable_sequenced_task_runner.h"
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "chrome/browser/media/history/media_history_origin_table.h" #include "chrome/browser/media/history/media_history_origin_table.h"
#include "chrome/browser/media/history/media_history_playback_table.h" #include "chrome/browser/media/history/media_history_playback_table.h"
#include "chrome/browser/media/history/media_history_store.mojom.h" #include "chrome/browser/media/history/media_history_store.mojom.h"
...@@ -74,6 +75,12 @@ class MediaHistoryStore { ...@@ -74,6 +75,12 @@ class MediaHistoryStore {
base::OnceCallback<void(std::vector<mojom::MediaHistoryPlaybackRowPtr>)> base::OnceCallback<void(std::vector<mojom::MediaHistoryPlaybackRowPtr>)>
callback); callback);
// Returns all the rows in the media feeds table. This is only used for
// debugging because it loads all rows in the table.
void GetMediaFeedsForDebug(
base::OnceCallback<void(std::vector<media_feeds::mojom::MediaFeedPtr>)>
callback);
// Gets the playback sessions from the media history store. The results will // Gets the playback sessions from the media history store. The results will
// be ordered by most recent first and be limited to the first |num_sessions|. // be ordered by most recent first and be limited to the first |num_sessions|.
// For each session it calls |filter| and if that returns |true| then that // For each session it calls |filter| and if that returns |true| then that
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h" #include "base/test/test_timeouts.h"
#include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "chrome/browser/media/history/media_history_feeds_table.h" #include "chrome/browser/media/history/media_history_feeds_table.h"
#include "chrome/browser/media/history/media_history_images_table.h" #include "chrome/browser/media/history/media_history_images_table.h"
#include "chrome/browser/media/history/media_history_keyed_service.h" #include "chrome/browser/media/history/media_history_keyed_service.h"
...@@ -141,6 +142,21 @@ class MediaHistoryStoreUnitTest : public testing::Test, ...@@ -141,6 +142,21 @@ class MediaHistoryStoreUnitTest : public testing::Test,
return out; return out;
} }
std::vector<media_feeds::mojom::MediaFeedPtr> GetMediaFeedsSync(
MediaHistoryKeyedService* service) {
base::RunLoop run_loop;
std::vector<media_feeds::mojom::MediaFeedPtr> out;
service->GetMediaFeedsForDebug(base::BindLambdaForTesting(
[&](std::vector<media_feeds::mojom::MediaFeedPtr> rows) {
out = std::move(rows);
run_loop.Quit();
}));
run_loop.Run();
return out;
}
MediaHistoryKeyedService* service() const { MediaHistoryKeyedService* service() const {
// If the param is true then we use the OTR service to simulate being in // If the param is true then we use the OTR service to simulate being in
// incognito. // incognito.
...@@ -524,13 +540,22 @@ TEST_P(MediaHistoryStoreFeedsTest, SaveMediaFeed) { ...@@ -524,13 +540,22 @@ TEST_P(MediaHistoryStoreFeedsTest, SaveMediaFeed) {
{ {
// Check the feeds were recorded. // Check the feeds were recorded.
mojom::MediaHistoryStatsPtr stats = GetStatsSync(service()); std::vector<media_feeds::mojom::MediaFeedPtr> feeds =
GetMediaFeedsSync(service());
EXPECT_EQ(IsReadOnly() ? 0 : 2, if (IsReadOnly()) {
stats->table_row_counts[MediaHistoryFeedsTable::kTableName]); EXPECT_TRUE(feeds.empty());
} else {
EXPECT_EQ(2u, feeds.size());
EXPECT_EQ(1, feeds[0]->id);
EXPECT_EQ(url_a, feeds[0]->url);
EXPECT_EQ(2, feeds[1]->id);
EXPECT_EQ(url_b, feeds[1]->url);
}
// The OTR service should have the same data. // The OTR service should have the same data.
EXPECT_EQ(stats, GetStatsSync(otr_service())); EXPECT_EQ(feeds, GetMediaFeedsSync(otr_service()));
} }
service()->SaveMediaFeed(url_c); service()->SaveMediaFeed(url_c);
...@@ -538,12 +563,22 @@ TEST_P(MediaHistoryStoreFeedsTest, SaveMediaFeed) { ...@@ -538,12 +563,22 @@ TEST_P(MediaHistoryStoreFeedsTest, SaveMediaFeed) {
{ {
// Check the feeds were recorded. // Check the feeds were recorded.
mojom::MediaHistoryStatsPtr stats = GetStatsSync(service()); std::vector<media_feeds::mojom::MediaFeedPtr> feeds =
EXPECT_EQ(IsReadOnly() ? 0 : 2, GetMediaFeedsSync(service());
stats->table_row_counts[MediaHistoryFeedsTable::kTableName]);
if (IsReadOnly()) {
EXPECT_TRUE(feeds.empty());
} else {
EXPECT_EQ(2u, feeds.size());
EXPECT_EQ(2, feeds[0]->id);
EXPECT_EQ(url_b, feeds[0]->url);
EXPECT_EQ(3, feeds[1]->id);
EXPECT_EQ(url_c, feeds[1]->url);
}
// The OTR service should have the same data. // The OTR service should have the same data.
EXPECT_EQ(stats, GetStatsSync(otr_service())); EXPECT_EQ(feeds, GetMediaFeedsSync(otr_service()));
} }
} }
......
...@@ -17,6 +17,7 @@ if (closure_compile) { ...@@ -17,6 +17,7 @@ if (closure_compile) {
"components:closure_compile", "components:closure_compile",
"engagement:closure_compile", "engagement:closure_compile",
"interventions_internals:closure_compile", "interventions_internals:closure_compile",
"media:closure_compile",
"reset_password:closure_compile", "reset_password:closure_compile",
] ]
if (is_linux || is_win || is_mac) { if (is_linux || is_win || is_mac) {
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
import("//tools/grit/grit_rule.gni") import("//tools/grit/grit_rule.gni")
grit("webrtc_logs_resources") { grit("webrtc_logs_resources") {
...@@ -18,3 +19,15 @@ grit("webrtc_logs_resources") { ...@@ -18,3 +19,15 @@ grit("webrtc_logs_resources") {
"root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir), "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
] ]
} }
js_type_check("closure_compile") {
deps = [ ":media_feeds" ]
}
js_library("media_feeds") {
deps = [
"//chrome/browser/media/feeds:mojo_bindings_js_library_for_compile",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:util",
]
}
<!doctype html>
<html lang="en">
<head>
<title>Media Feeds</title>
<meta charset="utf-8">
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
<script src="chrome://resources/js/promise_resolver.js"></script>
<script src="chrome://resources/mojo/url/mojom/url.mojom-lite.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="chrome/browser/media/feeds/media_feeds_store.mojom-lite.js">
</script>
<script src="chrome://media-feeds/media-feeds.js"></script>
<style>
body {
font-family: 'Roboto', 'Noto', sans-serif;
font-size: 14px;
}
button {
margin-bottom: 20px;
}
table {
border-collapse: collapse;
margin-bottom: 20px;
}
table td,
table th {
border: 1px solid #777;
padding-inline-end: 4px;
padding-inline-start: 4px;
}
table th {
background: rgb(224, 236, 255);
cursor: pointer;
padding-bottom: 4px;
padding-inline-end: 4px;
padding-top: 4px;
white-space: nowrap;
}
.url-cell {
background-color: rgba(230, 230, 230, 0.5);
}
.name-cell {
background-color: rgba(230, 230, 230, 0.5);
}
table tr:hover {
background: rgb(255, 255, 187);
}
th.sort-column {
padding-inline-end: 16px;
}
th.sort-column::after {
content: '▲';
position: absolute;
}
th[sort-reverse].sort-column::after {
content: '▼';
position: absolute;
}
</style>
</head>
<body>
<h1>Media Feeds</h1>
<button id="copy-all-to-clipboard">Copy all to clipboard</button>
<table>
<thead>
<tr id="feed-table-header">
<th sort-key="id" class="sort-column" sort-reverse>
ID
</th>
<th sort-key="url">
Url
</th>
</tr>
</thead>
<tbody id="feed-table-body">
</tbody>
</table>
<template id="datarow">
<tr>
<td class="id-cell"></td>
<td class="url-cell"></td>
</tr>
</template>
</body>
</html>
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(https://crbug.com/1059352): Factor out the sortable table.
'use strict';
// Allow a function to be provided by tests, which will be called when
// the page has been populated with media feeds details.
const pageIsPopulatedResolver = new PromiseResolver();
function whenPageIsPopulatedForTest() {
return pageIsPopulatedResolver.promise;
}
(function() {
let detailsProvider = null;
let info = null;
let feedTableBody = null;
let sortReverse = true;
let sortKey = 'id';
/**
* Creates a single row in the feeds table.
* @param {!mediaFeeds.mojom.MediaFeed} rowInfo The info to create the row.
* @return {!Node}
*/
function createRow(rowInfo) {
const template = $('datarow');
const td = template.content.querySelectorAll('td');
td[0].textContent = rowInfo.id;
td[1].textContent = rowInfo.url.url;
return document.importNode(template.content, true);
}
/**
* Remove all rows from the feeds table.
*/
function clearTable() {
feedTableBody.innerHTML = '';
}
/**
* Sort the feed info based on |sortKey| and |sortReverse|.
*/
function sortInfo() {
info.sort((a, b) => {
return (sortReverse ? -1 : 1) * compareTableItem(sortKey, a, b);
});
}
/**
* Compares two MediaFeed objects based on |sortKey|.
* @param {string} sortKey The name of the property to sort by.
* @param {mediaFeeds.mojom.MediaFeed} a First object to compare.
* @param {mediaFeeds.mojom.MediaFeed} b Second object to compare.
* @return {number|boolean} A negative number if |a| should be ordered before
* |b|, a positive number otherwise.
*/
function compareTableItem(sortKey, a, b) {
if (sortKey == 'url') {
return a.url.url > b.url.url ? 1 : -1;
} else if (sortKey == 'id') {
return a.id > b.id;
}
assertNotReached('Unsupported sort key: ' + sortKey);
return 0;
}
/**
* Regenerates the feed table from |info|.
*/
function renderTable() {
clearTable();
sortInfo();
info.forEach(rowInfo => feedTableBody.appendChild(createRow(rowInfo)));
}
/**
* Retrieve feed info and render the feed table.
*/
function updateFeedTable() {
detailsProvider.getMediaFeeds().then(response => {
info = response.feeds;
renderTable();
pageIsPopulatedResolver.resolve();
});
}
document.addEventListener('DOMContentLoaded', () => {
detailsProvider = mediaFeeds.mojom.MediaFeedsStore.getRemote();
feedTableBody = $('feed-table-body');
updateFeedTable();
// Set table header sort handlers.
const feedTableHeader = $('feed-table-header');
const headers = feedTableHeader.children;
for (let i = 0; i < headers.length; i++) {
headers[i].addEventListener('click', (e) => {
const newSortKey = e.target.getAttribute('sort-key');
if (sortKey == newSortKey) {
sortReverse = !sortReverse;
} else {
sortKey = newSortKey;
sortReverse = false;
}
const oldSortColumn = document.querySelector('.sort-column');
oldSortColumn.classList.remove('sort-column');
e.target.classList.add('sort-column');
if (sortReverse) {
e.target.setAttribute('sort-reverse', '');
} else {
e.target.removeAttribute('sort-reverse');
}
renderTable();
});
}
// Add handler to 'copy all to clipboard' button
const copyAllToClipboardButton = $('copy-all-to-clipboard');
copyAllToClipboardButton.addEventListener('click', (e) => {
// Make sure nothing is selected
window.getSelection().removeAllRanges();
document.execCommand('selectAll');
document.execCommand('copy');
// And deselect everything at the end.
window.getSelection().removeAllRanges();
});
});
})();
...@@ -257,6 +257,8 @@ jumbo_static_library("ui") { ...@@ -257,6 +257,8 @@ jumbo_static_library("ui") {
"webui/log_web_ui_url.h", "webui/log_web_ui_url.h",
"webui/media/media_engagement_ui.cc", "webui/media/media_engagement_ui.cc",
"webui/media/media_engagement_ui.h", "webui/media/media_engagement_ui.h",
"webui/media/media_feeds_ui.cc",
"webui/media/media_feeds_ui.h",
"webui/media/media_history_ui.cc", "webui/media/media_history_ui.cc",
"webui/media/media_history_ui.h", "webui/media/media_history_ui.h",
"webui/media/webrtc_logs_ui.cc", "webui/media/webrtc_logs_ui.cc",
...@@ -399,6 +401,7 @@ jumbo_static_library("ui") { ...@@ -399,6 +401,7 @@ jumbo_static_library("ui") {
"//chrome/browser/engagement:mojo_bindings", "//chrome/browser/engagement:mojo_bindings",
"//chrome/browser/image_decoder", "//chrome/browser/image_decoder",
"//chrome/browser/media:mojo_bindings", "//chrome/browser/media:mojo_bindings",
"//chrome/browser/media/feeds:mojo_bindings",
"//chrome/browser/notifications/scheduler/public", "//chrome/browser/notifications/scheduler/public",
"//chrome/browser/profiling_host", "//chrome/browser/profiling_host",
"//chrome/browser/resources/invalidations:invalidations_resources", "//chrome/browser/resources/invalidations:invalidations_resources",
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "chrome/browser/buildflags.h" #include "chrome/browser/buildflags.h"
#include "chrome/browser/devtools/devtools_ui_bindings.h" #include "chrome/browser/devtools/devtools_ui_bindings.h"
#include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/browser/engagement/site_engagement_service.h"
#include "chrome/browser/media/feeds/media_feeds_service.h"
#include "chrome/browser/media/history/media_history_keyed_service.h" #include "chrome/browser/media/history/media_history_keyed_service.h"
#include "chrome/browser/media/media_engagement_service.h" #include "chrome/browser/media/media_engagement_service.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -48,6 +49,7 @@ ...@@ -48,6 +49,7 @@
#include "chrome/browser/ui/webui/local_state/local_state_ui.h" #include "chrome/browser/ui/webui/local_state/local_state_ui.h"
#include "chrome/browser/ui/webui/log_web_ui_url.h" #include "chrome/browser/ui/webui/log_web_ui_url.h"
#include "chrome/browser/ui/webui/media/media_engagement_ui.h" #include "chrome/browser/ui/webui/media/media_engagement_ui.h"
#include "chrome/browser/ui/webui/media/media_feeds_ui.h"
#include "chrome/browser/ui/webui/media/media_history_ui.h" #include "chrome/browser/ui/webui/media/media_history_ui.h"
#include "chrome/browser/ui/webui/media/webrtc_logs_ui.h" #include "chrome/browser/ui/webui/media/webrtc_logs_ui.h"
#include "chrome/browser/ui/webui/memory_internals_ui.h" #include "chrome/browser/ui/webui/memory_internals_ui.h"
...@@ -776,6 +778,11 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui, ...@@ -776,6 +778,11 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
return &NewWebUI<MediaEngagementUI>; return &NewWebUI<MediaEngagementUI>;
} }
if (media_feeds::MediaFeedsService::IsEnabled() &&
url.host_piece() == chrome::kChromeUIMediaFeedsHost) {
return &NewWebUI<MediaFeedsUI>;
}
if (media_history::MediaHistoryKeyedService::IsEnabled() && if (media_history::MediaHistoryKeyedService::IsEnabled() &&
url.host_piece() == chrome::kChromeUIMediaHistoryHost) { url.host_piece() == chrome::kChromeUIMediaHistoryHost) {
return &NewWebUI<MediaHistoryUI>; return &NewWebUI<MediaHistoryUI>;
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/media/media_feeds_ui.h"
#include "base/bind.h"
#include "base/macros.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/media/history/media_history_keyed_service.h"
#include "chrome/browser/media/history/media_history_keyed_service_factory.h"
#include "chrome/browser/media/history/media_history_store.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/dev_ui_browser_resources.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_data_source.h"
MediaFeedsUI::MediaFeedsUI(content::WebUI* web_ui)
: ui::MojoWebUIController(web_ui) {
// Setup the data source behind chrome://media-feeds.
std::unique_ptr<content::WebUIDataSource> source(
content::WebUIDataSource::Create(chrome::kChromeUIMediaFeedsHost));
source->AddResourcePath("media-feeds.js", IDR_MEDIA_FEEDS_JS);
source->AddResourcePath(
"chrome/browser/media/feeds/media_feeds_store.mojom-lite.js",
IDR_MEDIA_FEEDS_STORE_MOJOM_LITE_JS);
source->SetDefaultResource(IDR_MEDIA_FEEDS_HTML);
content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source.release());
}
WEB_UI_CONTROLLER_TYPE_IMPL(MediaFeedsUI)
MediaFeedsUI::~MediaFeedsUI() = default;
void MediaFeedsUI::BindInterface(
mojo::PendingReceiver<media_feeds::mojom::MediaFeedsStore> pending) {
receiver_.Add(this, std::move(pending));
}
void MediaFeedsUI::GetMediaFeeds(GetMediaFeedsCallback callback) {
return GetMediaHistoryService()->GetMediaFeedsForDebug(std::move(callback));
}
media_history::MediaHistoryKeyedService*
MediaFeedsUI::GetMediaHistoryService() {
Profile* profile = Profile::FromWebUI(web_ui());
DCHECK(profile);
media_history::MediaHistoryKeyedService* service =
media_history::MediaHistoryKeyedServiceFactory::GetForProfile(profile);
DCHECK(service);
return service;
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_MEDIA_MEDIA_FEEDS_UI_H_
#define CHROME_BROWSER_UI_WEBUI_MEDIA_MEDIA_FEEDS_UI_H_
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "ui/webui/mojo_web_ui_controller.h"
namespace media_history {
class MediaHistoryKeyedService;
} // namespace media_history
// The UI for chrome://media-feeds.
class MediaFeedsUI : public ui::MojoWebUIController,
public media_feeds::mojom::MediaFeedsStore {
public:
explicit MediaFeedsUI(content::WebUI* web_ui);
MediaFeedsUI(const MediaFeedsUI&) = delete;
MediaFeedsUI& operator=(const MediaFeedsUI&) = delete;
~MediaFeedsUI() override;
// Instantiates the implementor of the MediaFeedsStore mojo interface passing
// the pending receiver that will be internally bound.
void BindInterface(
mojo::PendingReceiver<media_feeds::mojom::MediaFeedsStore> pending);
// media_history::mojom::MediaHistoryStore:
void GetMediaFeeds(GetMediaFeedsCallback callback) override;
private:
media_history::MediaHistoryKeyedService* GetMediaHistoryService();
mojo::ReceiverSet<media_feeds::mojom::MediaFeedsStore> receiver_;
WEB_UI_CONTROLLER_TYPE_DECL();
};
#endif // CHROME_BROWSER_UI_WEBUI_MEDIA_MEDIA_FEEDS_UI_H_
...@@ -97,6 +97,7 @@ const char kChromeUIManagementURL[] = "chrome://management"; ...@@ -97,6 +97,7 @@ const char kChromeUIManagementURL[] = "chrome://management";
const char kChromeUIMdUserManagerHost[] = "md-user-manager"; const char kChromeUIMdUserManagerHost[] = "md-user-manager";
const char kChromeUIMdUserManagerUrl[] = "chrome://md-user-manager/"; const char kChromeUIMdUserManagerUrl[] = "chrome://md-user-manager/";
const char kChromeUIMediaEngagementHost[] = "media-engagement"; const char kChromeUIMediaEngagementHost[] = "media-engagement";
const char kChromeUIMediaFeedsHost[] = "media-feeds";
const char kChromeUIMediaHistoryHost[] = "media-history"; const char kChromeUIMediaHistoryHost[] = "media-history";
const char kChromeUIMediaRouterInternalsHost[] = "media-router-internals"; const char kChromeUIMediaRouterInternalsHost[] = "media-router-internals";
const char kChromeUIMemoryInternalsHost[] = "memory-internals"; const char kChromeUIMemoryInternalsHost[] = "memory-internals";
......
...@@ -103,6 +103,7 @@ extern const char kChromeUIManagementURL[]; ...@@ -103,6 +103,7 @@ extern const char kChromeUIManagementURL[];
extern const char kChromeUIMdUserManagerHost[]; extern const char kChromeUIMdUserManagerHost[];
extern const char kChromeUIMdUserManagerUrl[]; extern const char kChromeUIMdUserManagerUrl[];
extern const char kChromeUIMediaEngagementHost[]; extern const char kChromeUIMediaEngagementHost[];
extern const char kChromeUIMediaFeedsHost[];
extern const char kChromeUIMediaHistoryHost[]; extern const char kChromeUIMediaHistoryHost[];
extern const char kChromeUIMediaRouterInternalsHost[]; extern const char kChromeUIMediaRouterInternalsHost[];
extern const char kChromeUIMemoryInternalsHost[]; extern const char kChromeUIMemoryInternalsHost[];
......
...@@ -285,6 +285,7 @@ js2gtest("browser_tests_js_mojo_lite_webui") { ...@@ -285,6 +285,7 @@ js2gtest("browser_tests_js_mojo_lite_webui") {
"engagement/site_engagement_browsertest.js", "engagement/site_engagement_browsertest.js",
"interventions_internals_browsertest.js", "interventions_internals_browsertest.js",
"media/media_engagement_browsertest.js", "media/media_engagement_browsertest.js",
"media/media_feeds_webui_browsertest.js",
"media/media_history_webui_browsertest.js", "media/media_history_webui_browsertest.js",
"new_tab_page/new_tab_page_browsertest.js", "new_tab_page/new_tab_page_browsertest.js",
"usb_internals_browsertest.js", "usb_internals_browsertest.js",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Test suite for the Media Feeds WebUI.
*/
GEN('#include "chrome/browser/ui/browser.h"');
GEN('#include "media/base/media_switches.h"');
function MediaFeedsWebUIBrowserTest() {}
MediaFeedsWebUIBrowserTest.prototype = {
__proto__: testing.Test.prototype,
browsePreload: 'chrome://media-feeds',
featureList: {enabled: ['media::kMediaFeeds']},
isAsync: true,
extraLibraries: [
'//third_party/mocha/mocha.js',
'//chrome/test/data/webui/mocha_adapter.js',
],
};
TEST_F('MediaFeedsWebUIBrowserTest', 'All', function() {
suiteSetup(function() {
return whenPageIsPopulatedForTest();
});
test('check feeds table is loaded', function() {
let feedHeaders =
Array.from(document.querySelector('#feed-table-header').children);
assertDeepEquals(['ID', 'Url'], feedHeaders.map(x => x.textContent.trim()));
});
mocha.run();
});
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