diff --git a/src/components/app/ProfileFilterNavigator.tsx b/src/components/app/ProfileFilterNavigator.tsx index 936fd8003d..dd1041d4da 100644 --- a/src/components/app/ProfileFilterNavigator.tsx +++ b/src/components/app/ProfileFilterNavigator.tsx @@ -20,7 +20,7 @@ import { import { getTabFilter } from 'firefox-profiler/selectors/url-state'; import { getFormattedTimelineValue } from 'firefox-profiler/profile-logic/committed-ranges'; import { FilterNavigatorBar } from 'firefox-profiler/components/shared/FilterNavigatorBar'; -import { Icon } from 'firefox-profiler/components/shared/Icon'; +import { PageSelectorIcon } from 'firefox-profiler/components/shared/PageSelectorIcon'; import { TabSelectorMenu } from '../shared/TabSelectorMenu'; import type { @@ -94,7 +94,10 @@ class ProfileFilterNavigatorBarImpl extends React.PureComponent { const itemContents = pageData ? ( <> {/* Show the page data if the profile is filtered by tab */} - {pageData.favicon ? : null} + {pageData.hostname} ( {getFormattedTimelineValue( diff --git a/src/components/shared/PageSelectorIcon.tsx b/src/components/shared/PageSelectorIcon.tsx new file mode 100644 index 0000000000..94056fd8b6 --- /dev/null +++ b/src/components/shared/PageSelectorIcon.tsx @@ -0,0 +1,31 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +import { Icon } from './Icon'; +import ExtensionFavicon from '../../../res/img/svg/extension-outline.svg'; +import DefaultLinkFavicon from '../../../res/img/svg/globe.svg'; + +type Props = { + readonly favicon: string | null; + readonly origin: string; +}; + +/** + * PageSelectorIcon wraps the Icon component and provides fallback icons + * for pages that don't have a favicon in the profile data. + * + * Fallback logic: + * - If favicon exists (Firefox 134+ provides base64 data URI), use it + * - If origin is moz-extension://, fallback to extension-outline.svg + * - Otherwise (regular pages, about: pages), fallback to globe.svg + */ +export function PageSelectorIcon({ favicon, origin }: Props) { + const iconUrl = + favicon ?? + (origin.startsWith('moz-extension://') + ? ExtensionFavicon + : DefaultLinkFavicon); + + return ; +} diff --git a/src/components/shared/TabSelectorMenu.tsx b/src/components/shared/TabSelectorMenu.tsx index 59101c23a3..0f493b04d0 100644 --- a/src/components/shared/TabSelectorMenu.tsx +++ b/src/components/shared/TabSelectorMenu.tsx @@ -11,7 +11,7 @@ import explicitConnect from 'firefox-profiler/utils/connect'; import { changeTabFilter } from 'firefox-profiler/actions/receive-profile'; import { getTabFilter } from '../../selectors/url-state'; import { getProfileFilterSortedPageData } from 'firefox-profiler/selectors/profile'; -import { Icon } from 'firefox-profiler/components/shared/Icon'; +import { PageSelectorIcon } from 'firefox-profiler/components/shared/PageSelectorIcon'; import type { TabID, SortedTabPageData } from 'firefox-profiler/types'; import type { ConnectedProps } from 'firefox-profiler/utils/connect'; @@ -73,7 +73,10 @@ class TabSelectorMenuImpl extends React.PureComponent { 'aria-checked': tabFilter === tabID ? 'false' : 'true', }} > - + {pageData.hostname} ))} diff --git a/src/profile-logic/profile-data.ts b/src/profile-logic/profile-data.ts index 21af66fcd8..97525c5502 100644 --- a/src/profile-logic/profile-data.ts +++ b/src/profile-logic/profile-data.ts @@ -35,8 +35,6 @@ import { numberSeriesFromDeltas, numberSeriesToDeltas, } from 'firefox-profiler/utils/number-series'; -import ExtensionFavicon from '../../res/img/svg/extension-outline.svg'; -import DefaultLinkFavicon from '../../res/img/svg/globe.svg'; import type { StringTable } from 'firefox-profiler/utils/string-table'; import type { @@ -3307,7 +3305,7 @@ export function extractProfileFilterPageData( pageDataByTabID.set(tabID, { origin: pageUrl, hostname: pageUrl, - favicon: DefaultLinkFavicon, + favicon: null, }); continue; } @@ -3321,12 +3319,11 @@ export function extractProfileFilterPageData( // moz-extension:// protocol on platforms outside of Firefox. Only Firefox // can parse it properly. Chrome and node will output a URL with no `origin`. const isExtension = pageUrl.startsWith('moz-extension://'); - const defaultFavicon = isExtension ? ExtensionFavicon : DefaultLinkFavicon; const pageData: ProfileFilterPageData = { // These will be used as a fallback if the urls have been sanitized. origin: pageUrl, hostname: pageUrl, - favicon: currentPage.favicon ?? defaultFavicon, + favicon: currentPage.favicon ?? null, }; try { diff --git a/src/test/unit/profile-data.test.ts b/src/test/unit/profile-data.test.ts index 1d4a47ec5b..6b1f3ef34e 100644 --- a/src/test/unit/profile-data.test.ts +++ b/src/test/unit/profile-data.test.ts @@ -1301,7 +1301,7 @@ describe('extractProfileFilterPageData', function () { { origin: 'about:blank', hostname: 'about:blank', - favicon: 'test-file-stub', + favicon: null, }, ], ]); diff --git a/src/types/profile-derived.ts b/src/types/profile-derived.ts index 3ee00c355b..c37e45319e 100644 --- a/src/types/profile-derived.ts +++ b/src/types/profile-derived.ts @@ -696,7 +696,7 @@ export type InitialSelectedTrackReference = HTMLElement; export type ProfileFilterPageData = { origin: string; hostname: string; - favicon: string; + favicon: string | null; }; /**