diff --git a/browser/about_flags.cc b/browser/about_flags.cc index 716ff4e1a42..9a6c81be502 100644 --- a/browser/about_flags.cc +++ b/browser/about_flags.cc @@ -253,15 +253,23 @@ brave_wallet::features::kBraveWalletDappsSupportFeature), \ }) -#define BRAVE_NEWS_FEATURE_ENTRIES \ - EXPAND_FEATURE_ENTRIES({ \ - "brave-news-peek", \ - "Brave News prompts on New Tab Page", \ - "Prompt Brave News via the top featured article peeking up from " \ - "the bottom of the New Tab Page, after a short delay.", \ - kOsDesktop, \ - FEATURE_VALUE_TYPE(brave_news::features::kBraveNewsCardPeekFeature), \ - }) +#define BRAVE_NEWS_FEATURE_ENTRIES \ + EXPAND_FEATURE_ENTRIES( \ + { \ + "brave-news-peek", \ + "Brave News prompts on New Tab Page", \ + "Prompt Brave News via the top featured article peeking up from " \ + "the bottom of the New Tab Page, after a short delay.", \ + kOsDesktop, \ + FEATURE_VALUE_TYPE(brave_news::features::kBraveNewsCardPeekFeature), \ + }, \ + { \ + "brave-news-feed-update", \ + "Brave News Feed Update", \ + "Use the updated Brave News feed", \ + kOsDesktop, \ + FEATURE_VALUE_TYPE(brave_news::features::kBraveNewsFeedUpdate), \ + }) #define BRAVE_FEDERATED_FEATURE_ENTRIES \ EXPAND_FEATURE_ENTRIES({ \ diff --git a/browser/brave_content_browser_client.cc b/browser/brave_content_browser_client.cc index 8cc8b9704eb..dd5dcbc1d99 100644 --- a/browser/brave_content_browser_client.cc +++ b/browser/brave_content_browser_client.cc @@ -205,6 +205,7 @@ using extensions::ChromeContentBrowserClientExtensionsPart; #if !BUILDFLAG(IS_ANDROID) #include "brave/browser/new_tab/new_tab_shows_navigation_throttle.h" +#include "brave/browser/ui/webui/brave_news_internals/brave_news_internals_ui.h" #include "brave/browser/ui/webui/brave_rewards/rewards_panel_ui.h" #include "brave/browser/ui/webui/brave_rewards/tip_panel_ui.h" #include "brave/browser/ui/webui/brave_settings_ui.h" @@ -216,6 +217,7 @@ using extensions::ChromeContentBrowserClientExtensionsPart; #include "brave/browser/ui/webui/private_new_tab_page/brave_private_new_tab_ui.h" #include "brave/components/brave_new_tab_ui/brave_new_tab_page.mojom.h" #include "brave/components/brave_news/common/brave_news.mojom.h" +#include "brave/components/brave_news/common/features.h" #include "brave/components/brave_private_new_tab_ui/common/brave_private_new_tab.mojom.h" #include "brave/components/brave_rewards/common/features.h" #include "brave/components/brave_rewards/common/mojom/rewards_panel.mojom.h" @@ -565,6 +567,14 @@ void BraveContentBrowserClient::RegisterWebUIInterfaceBrokers( if (base::FeatureList::IsEnabled(skus::features::kSkusFeature)) { registry.ForWebUI().Add(); } + +#if !BUILDFLAG(IS_ANDROID) + if (base::FeatureList::IsEnabled( + brave_news::features::kBraveNewsFeedUpdate)) { + registry.ForWebUI() + .Add(); + } +#endif } bool BraveContentBrowserClient::AllowWorkerFingerprinting( diff --git a/browser/ui/BUILD.gn b/browser/ui/BUILD.gn index 1f3f3f0a71a..feb979414ce 100644 --- a/browser/ui/BUILD.gn +++ b/browser/ui/BUILD.gn @@ -935,6 +935,8 @@ source_set("ui") { "views/wallet_bubble_focus_observer.h", "wallet_bubble_manager_delegate_impl.cc", "wallet_bubble_manager_delegate_impl.h", + "webui/brave_news_internals/brave_news_internals_ui.cc", + "webui/brave_news_internals/brave_news_internals_ui.h", "webui/brave_wallet/ledger/ledger_ui.cc", "webui/brave_wallet/ledger/ledger_ui.h", "webui/brave_wallet/market/market_ui.cc", @@ -958,6 +960,8 @@ source_set("ui") { "//brave/browser/ui/brave_wallet", "//brave/browser/ui/webui/brave_wallet/common_handler", "//brave/browser/ui/webui/brave_wallet/panel_handler", + "//brave/components/brave_news/browser", + "//brave/components/brave_news/browser/resources:generated_resources", "//brave/components/brave_wallet/common", "//brave/components/brave_wallet/common:mojom", "//brave/components/brave_wallet_ui:resources", diff --git a/browser/ui/webui/brave_news_internals/brave_news_internals_ui.cc b/browser/ui/webui/brave_news_internals/brave_news_internals_ui.cc new file mode 100644 index 00000000000..ef493dc0118 --- /dev/null +++ b/browser/ui/webui/brave_news_internals/brave_news_internals_ui.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "brave/browser/ui/webui/brave_news_internals/brave_news_internals_ui.h" + +#include +#include + +#include "brave/browser/brave_news/brave_news_controller_factory.h" +#include "brave/browser/ui/webui/brave_webui_source.h" +#include "brave/components/brave_news/browser/brave_news_controller.h" +#include "brave/components/brave_news/browser/resources/grit/brave_news_internals_generated_map.h" +#include "chrome/browser/profiles/profile.h" +#include "components/grit/brave_components_resources.h" + +BraveNewsInternalsUI::BraveNewsInternalsUI(content::WebUI* web_ui, + const std::string& host) + : content::WebUIController(web_ui) { + auto* source = CreateAndAddWebUIDataSource( + web_ui, host, kBraveNewsInternalsGenerated, + kBraveNewsInternalsGeneratedSize, IDR_BRAVE_NEWS_INTERNALS_HTML); + DCHECK(source); +} + +BraveNewsInternalsUI::~BraveNewsInternalsUI() = default; +WEB_UI_CONTROLLER_TYPE_IMPL(BraveNewsInternalsUI) + +void BraveNewsInternalsUI::BindInterface( + mojo::PendingReceiver receiver) { + auto* profile = Profile::FromWebUI(web_ui()); + auto* controller = + brave_news::BraveNewsControllerFactory::GetForContext(profile); + if (!controller) { + return; + } + + controller->Bind(std::move(receiver)); +} diff --git a/browser/ui/webui/brave_news_internals/brave_news_internals_ui.h b/browser/ui/webui/brave_news_internals/brave_news_internals_ui.h new file mode 100644 index 00000000000..496807aa15b --- /dev/null +++ b/browser/ui/webui/brave_news_internals/brave_news_internals_ui.h @@ -0,0 +1,31 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +#ifndef BRAVE_BROWSER_UI_WEBUI_BRAVE_NEWS_INTERNALS_BRAVE_NEWS_INTERNALS_UI_H_ +#define BRAVE_BROWSER_UI_WEBUI_BRAVE_NEWS_INTERNALS_BRAVE_NEWS_INTERNALS_UI_H_ + +#include +#include + +#include "brave/components/brave_news/common/brave_news.mojom-forward.h" +#include "content/public/browser/web_ui_controller.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" + +class BraveNewsInternalsUI : public content::WebUIController { + public: + explicit BraveNewsInternalsUI(content::WebUI* web_ui, + const std::string& host); + BraveNewsInternalsUI(const BraveNewsInternalsUI&) = delete; + BraveNewsInternalsUI& operator=(const BraveNewsInternalsUI&) = delete; + ~BraveNewsInternalsUI() override; + + void BindInterface( + mojo::PendingReceiver receiver); + + private: + WEB_UI_CONTROLLER_TYPE_DECL(); +}; + +#endif // BRAVE_BROWSER_UI_WEBUI_BRAVE_NEWS_INTERNALS_BRAVE_NEWS_INTERNALS_UI_H_ diff --git a/browser/ui/webui/brave_web_ui_controller_factory.cc b/browser/ui/webui/brave_web_ui_controller_factory.cc index 6b766f75526..8deaab609ce 100644 --- a/browser/ui/webui/brave_web_ui_controller_factory.cc +++ b/browser/ui/webui/brave_web_ui_controller_factory.cc @@ -36,6 +36,7 @@ #if !BUILDFLAG(IS_ANDROID) #include "brave/browser/brave_wallet/brave_wallet_context_utils.h" +#include "brave/browser/ui/webui/brave_news_internals/brave_news_internals_ui.h" #include "brave/browser/ui/webui/brave_rewards/rewards_panel_ui.h" #include "brave/browser/ui/webui/brave_rewards/tip_panel_ui.h" #include "brave/browser/ui/webui/brave_settings_ui.h" @@ -48,6 +49,7 @@ #include "brave/browser/ui/webui/speedreader/speedreader_toolbar_ui.h" #include "brave/browser/ui/webui/webcompat_reporter_ui.h" #include "brave/browser/ui/webui/welcome_page/brave_welcome_ui.h" +#include "brave/components/brave_news/common/features.h" #include "brave/components/brave_wallet/browser/brave_wallet_utils.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/commands/common/features.h" @@ -149,6 +151,10 @@ WebUIController* NewWebUI(WebUI* web_ui, const GURL& url) { } else if (host == kBraveTipPanelHost && brave_rewards::IsSupportedForProfile(profile)) { return new brave_rewards::TipPanelUI(web_ui); + } else if (base::FeatureList::IsEnabled( + brave_news::features::kBraveNewsFeedUpdate) && + host == kBraveNewsInternalsHost) { + return new BraveNewsInternalsUI(web_ui, url.host()); #endif // !BUILDFLAG(IS_ANDROID) #if !BUILDFLAG(IS_ANDROID) } else if (host == kWelcomeHost && !profile->IsGuestSession()) { @@ -204,6 +210,9 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui, url.path() == kWalletSendPagePath || url.path() == kWalletBuyPagePath || url.path() == kWalletDepositPagePath)) || #else + (base::FeatureList::IsEnabled( + brave_news::features::kBraveNewsFeedUpdate) && + url.host_piece() == kBraveNewsInternalsHost) || ((url.host_piece() == kWalletPanelHost || url.host_piece() == kWalletPageHost) && brave_wallet::IsAllowedForContext(profile)) || diff --git a/components/brave_news/browser/resources/BUILD.gn b/components/brave_news/browser/resources/BUILD.gn new file mode 100644 index 00000000000..5c713e5a8e4 --- /dev/null +++ b/components/brave_news/browser/resources/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright (c) 2023 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + +import("//brave/components/common/typescript.gni") + +transpile_web_ui("brave_news_internals") { + entry_points = [ [ + "brave_news_internals", + rebase_path("internals.tsx"), + ] ] + + deps = [ + "//brave/components/brave_news/common", + "//brave/components/brave_news/common:mojom", + "//brave/components/brave_news/common:mojom_js", + ] + + resource_name = "brave_news_internals" +} + +pack_web_resources("generated_resources") { + resource_name = "brave_news_internals" + + output_dir = "$root_gen_dir/brave/components/brave_news/browser/resources" + deps = [ ":brave_news_internals" ] +} diff --git a/components/brave_news/browser/resources/FeedPage.tsx b/components/brave_news/browser/resources/FeedPage.tsx new file mode 100644 index 00000000000..a2cfd14ca28 --- /dev/null +++ b/components/brave_news/browser/resources/FeedPage.tsx @@ -0,0 +1,15 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +import * as React from 'react'; + +interface Props { +} + +export default function FeedPage (props: Props) { + return
+ The Feed +
+} diff --git a/components/brave_news/browser/resources/PageInfo.tsx b/components/brave_news/browser/resources/PageInfo.tsx new file mode 100644 index 00000000000..f92a9f48d5c --- /dev/null +++ b/components/brave_news/browser/resources/PageInfo.tsx @@ -0,0 +1,31 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +import Dropdown from '@brave/leo/react/dropdown'; +import * as React from 'react'; +import { pages, useInspectContext } from './context'; + +interface Props { +} + +export default function PageInfo(props: Props) { + const { page, setPage, publishers, locale, setLocale } = useInspectContext(); + const locales = React.useMemo(() => Array.from(new Set(Object.values(publishers).flatMap(p => p.locales.map(l => l.locale)))), [publishers]) + + return
+
+ setPage(e.detail.value)}> + Page + {pages.map(p => {p})} + +
+
+ setLocale(e.detail.value)}> + Locale + {locales.map(l => {l})} + +
+
+} diff --git a/components/brave_news/browser/resources/SignalsPage.tsx b/components/brave_news/browser/resources/SignalsPage.tsx new file mode 100644 index 00000000000..1b9e7132c02 --- /dev/null +++ b/components/brave_news/browser/resources/SignalsPage.tsx @@ -0,0 +1,15 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +import * as React from 'react'; + +interface Props { +} + +export default function SignalsPage (props: Props) { + return
+ Signals Page +
+} diff --git a/components/brave_news/browser/resources/context.tsx b/components/brave_news/browser/resources/context.tsx new file mode 100644 index 00000000000..93c63d8ace6 --- /dev/null +++ b/components/brave_news/browser/resources/context.tsx @@ -0,0 +1,58 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +import { + BraveNewsController, Channel, Publisher +} from 'gen/brave/components/brave_news/common/brave_news.mojom.m' +import * as React from 'react' +import usePromise from '../../../brave_new_tab_ui/hooks/usePromise' + + +export const pages = ['feed', 'signals'] as const; +export type Page = (typeof pages)[number] + +export interface InspectContext { + publishers: { [key: string]: Publisher }, + channels: { [key: string]: Channel }, + page: Page, + setPage: (page: Page) => void, + locale: string, + setLocale: (locale: string) => void +} + +export const api = BraveNewsController.getRemote(); + +const Context = React.createContext({ + publishers: {}, + channels: {}, + page: 'feed', + setPage: () => { }, + locale: 'en_US', + setLocale: () => { } +}) + +export const useInspectContext = () => { + return React.useContext(Context); +} + +export default function InspectContext(props: React.PropsWithChildren<{}>) { + const { result: publishers } = usePromise(() => api.getPublishers().then(p => p.publishers as { [key: string]: Publisher }), []) + const { result: channels } = usePromise(() => api.getChannels().then(c => c.channels as { [key: string]: Channel }), []) + const [page, setPage] = React.useState('feed') + const [locale, setLocale] = React.useState('en_US') + + const context = React.useMemo(() => ({ + publishers: publishers ?? {}, + channels: channels ?? {}, + page, + setPage, + locale, + setLocale + }), [publishers, channels, page, locale]) + + return + {props.children} + +} diff --git a/components/brave_news/browser/resources/internals.html b/components/brave_news/browser/resources/internals.html new file mode 100644 index 00000000000..ef09be1c7d8 --- /dev/null +++ b/components/brave_news/browser/resources/internals.html @@ -0,0 +1,28 @@ + + + + + + + Brave News Internals + + + + + + + +
+ + + + diff --git a/components/brave_news/browser/resources/internals.tsx b/components/brave_news/browser/resources/internals.tsx new file mode 100644 index 00000000000..8abfb91d219 --- /dev/null +++ b/components/brave_news/browser/resources/internals.tsx @@ -0,0 +1,51 @@ +// Copyright (c) 2023 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +import * as React from 'react' +import { render } from 'react-dom' + +import styled from 'styled-components' +import InspectContext, { useInspectContext } from './context' +import PageInfo from './PageInfo' +import FeedPage from './FeedPage' +import SignalsPage from './SignalsPage' + +const Grid = styled.div` + display: grid; + grid-template-columns: 200px auto 200px; + padding: 16px; + gap: 8px; +` + +const Container = styled.div` + display: flex; + flex-direction: column; + gap: var(--leo-spacing-8); + max-width: 800px; + margin: 0 auto; +` + +function App() { + const { page, publishers, channels } = useInspectContext() + + return ( + + + + {page === 'feed' && } + {page === 'signals' && } + +
+ Publishers: {Object.keys(publishers).length} +
+ Channels: {Object.keys(channels).length} +
+
+ ) +} + +render( + +, document.getElementById('root')) diff --git a/components/brave_news/browser/resources/news_resources.grdp b/components/brave_news/browser/resources/news_resources.grdp new file mode 100644 index 00000000000..f3781a82598 --- /dev/null +++ b/components/brave_news/browser/resources/news_resources.grdp @@ -0,0 +1,4 @@ + + + + diff --git a/components/brave_news/browser/resources/tsconfig.json b/components/brave_news/browser/resources/tsconfig.json new file mode 100644 index 00000000000..062328d5a12 --- /dev/null +++ b/components/brave_news/browser/resources/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../../../tsconfig", + "include": ["**/*.ts", "**/*.tsx", "**/*.d.ts", "../../definitions/*.d.ts"] +} diff --git a/components/brave_news/common/features.cc b/components/brave_news/common/features.cc index f3ed7f84f44..bc621457154 100644 --- a/components/brave_news/common/features.cc +++ b/components/brave_news/common/features.cc @@ -13,4 +13,8 @@ BASE_FEATURE(kBraveNewsCardPeekFeature, "BraveNewsCardPeek", base::FEATURE_ENABLED_BY_DEFAULT); +BASE_FEATURE(kBraveNewsFeedUpdate, + "BraveNewsFeedUpdate", + base::FEATURE_DISABLED_BY_DEFAULT); + } // namespace brave_news::features diff --git a/components/brave_news/common/features.h b/components/brave_news/common/features.h index 09a83476329..96d3c36f26a 100644 --- a/components/brave_news/common/features.h +++ b/components/brave_news/common/features.h @@ -11,6 +11,7 @@ namespace brave_news::features { BASE_DECLARE_FEATURE(kBraveNewsCardPeekFeature); +BASE_DECLARE_FEATURE(kBraveNewsFeedUpdate); } // namespace brave_news::features diff --git a/components/constants/webui_url_constants.cc b/components/constants/webui_url_constants.cc index 656be09de23..8b8b50b9f1d 100644 --- a/components/constants/webui_url_constants.cc +++ b/components/constants/webui_url_constants.cc @@ -25,6 +25,7 @@ const char kBraveRewardsPanelHost[] = "rewards-panel.top-chrome"; const char kBraveTipPanelURL[] = "chrome://tip-panel.top-chrome"; const char kBraveTipPanelHost[] = "tip-panel.top-chrome"; const char kBraveNewTabJS[] = "brave_new_tab.js"; +const char kBraveNewsInternalsHost[] = "news-internals"; const char kBraveUIRewardsURL[] = "chrome://rewards/"; const char kBraveUIAdblockURL[] = "chrome://adblock/"; const char kBraveUIWebcompatReporterURL[] = "chrome://webcompat/"; diff --git a/components/constants/webui_url_constants.h b/components/constants/webui_url_constants.h index 4e0c7ed8773..6169d6988a1 100644 --- a/components/constants/webui_url_constants.h +++ b/components/constants/webui_url_constants.h @@ -23,6 +23,7 @@ extern const char kRewardsInternalsHost[]; extern const char kWelcomeHost[]; extern const char kWelcomeJS[]; extern const char kBraveNewTabJS[]; +extern const char kBraveNewsInternalsHost[]; extern const char kBraveRewardsPanelURL[]; extern const char kBraveRewardsPanelHost[]; extern const char kBraveTipPanelURL[]; diff --git a/components/resources/BUILD.gn b/components/resources/BUILD.gn index 3d8b59f7a72..d3b84768761 100644 --- a/components/resources/BUILD.gn +++ b/components/resources/BUILD.gn @@ -72,6 +72,8 @@ repack("resources") { if (!is_android && !is_ios) { deps += [ "//brave/components/brave_new_tab_ui:generated_resources", + "//brave/components/brave_news/browser/resources:generated_resources", + "//brave/components/brave_news/browser/resources:generated_resources", "//brave/components/brave_private_new_tab_ui/resources/page:generated_resources", "//brave/components/brave_shields/resources/cookie_list_opt_in:cookie_list_opt_in_generated", "//brave/components/brave_shields/resources/panel:brave_shields_panel_generated", @@ -82,6 +84,7 @@ repack("resources") { sources += [ "$root_gen_dir/brave/components/brave_new_tab/resources/brave_new_tab_generated.pak", + "$root_gen_dir/brave/components/brave_news/browser/resources/brave_news_internals_generated.pak", "$root_gen_dir/brave/components/brave_private_new_tab/resources/page/brave_private_new_tab_generated.pak", "$root_gen_dir/brave/components/brave_shields/resources/cookie_list_opt_in/cookie_list_opt_in_generated.pak", "$root_gen_dir/brave/components/brave_shields/resources/panel/brave_shields_panel_generated.pak", diff --git a/components/resources/brave_components_resources.grd b/components/resources/brave_components_resources.grd index 841547ef30d..4da309274e7 100644 --- a/components/resources/brave_components_resources.grd +++ b/components/resources/brave_components_resources.grd @@ -82,6 +82,7 @@ + diff --git a/resources/resource_ids.spec b/resources/resource_ids.spec index 722e2413645..c408a24097b 100644 --- a/resources/resource_ids.spec +++ b/resources/resource_ids.spec @@ -234,5 +234,9 @@ "<(SHARED_INTERMEDIATE_DIR)/brave/web-ui-skus_internals/skus_internals.grd": { "META": {"sizes": {"includes": [100]}}, "includes": [63550], + }, + "<(SHARED_INTERMEDIATE_DIR)/brave/web-ui-brave_news_internals/brave_news_internals.grd": { + "META": {"sizes": {"includes": [100]}}, + "includes": [63650], } }