diff --git a/packages/extension/src/view/devtools/app.tsx b/packages/extension/src/view/devtools/app.tsx index cc03ccf88..ce1b5ff7a 100644 --- a/packages/extension/src/view/devtools/app.tsx +++ b/packages/extension/src/view/devtools/app.tsx @@ -17,20 +17,10 @@ * External dependencies. */ import React, { useRef, useEffect, useCallback, useState } from 'react'; -import { Resizable } from 're-resizable'; import { - CookieIcon, - CookieIconWhite, ExtensionReloadNotification, - Sidebar, - useSidebar, - type SidebarItems, - InspectButton, + SidebarProvider, } from '@ps-analysis-tool/design-system'; -import { - UNKNOWN_FRAME_KEY, - type CookieTableData, -} from '@ps-analysis-tool/common'; /** * Internal dependencies. @@ -38,40 +28,20 @@ import { import TABS from './tabs'; import { useCookieStore } from './stateProviders/syncCookieStore'; import './app.css'; -import { Cookies } from './components'; -import useFrameOverlay from './hooks/useFrameOverlay'; +import { Layout } from './components'; import { getCurrentTabId } from '../../utils/getCurrentTabId'; import { useSettingsStore } from './stateProviders/syncSettingsStore'; const App: React.FC = () => { - const [sidebarWidth, setSidebarWidth] = useState(200); const [sidebarData, setSidebarData] = useState(TABS); const contextInvalidatedRef = useRef(null); - const { - contextInvalidated, - setContextInvalidated, - tabFrames, - selectedFrame, - setSelectedFrame, - isInspecting, - setIsInspecting, - canStartInspecting, - tabUrl, - frameHasCookies, - } = useCookieStore(({ state, actions }) => ({ - contextInvalidated: state.contextInvalidated, - setContextInvalidated: actions.setContextInvalidated, - tabCookies: state.tabCookies, - tabFrames: state.tabFrames, - selectedFrame: state.selectedFrame, - setSelectedFrame: actions.setSelectedFrame, - isInspecting: state.isInspecting, - setIsInspecting: actions.setIsInspecting, - canStartInspecting: state.canStartInspecting, - tabUrl: state.tabUrl, - frameHasCookies: state.frameHasCookies, - })); + const { contextInvalidated, setContextInvalidated } = useCookieStore( + ({ state, actions }) => ({ + contextInvalidated: state.contextInvalidated, + setContextInvalidated: actions.setContextInvalidated, + }) + ); const { allowedNumberOfTabs } = useSettingsStore(({ state }) => ({ allowedNumberOfTabs: state.allowedNumberOfTabs, @@ -109,126 +79,6 @@ const App: React.FC = () => { })(); }, []); - const { - activePanel, - selectedItemKey, - currentItemKey, - sidebarItems, - isSidebarFocused, - setIsSidebarFocused, - updateSelectedItemKey, - onKeyNavigation, - toggleDropdown, - isKeyAncestor, - isKeySelected, - } = useSidebar({ - data: sidebarData, - defaultSelectedItemKey, - }); - - useEffect(() => { - setSidebarData((prev) => { - const data = { ...prev }; - const psData = data['privacySandbox']; - - psData.children['cookies'].panel = ( - - ); - psData.children['cookies'].children = Object.keys(tabFrames || {}) - .filter((url) => { - return url === UNKNOWN_FRAME_KEY ? frameHasCookies[url] : true; - }) - .reduce((acc, url) => { - acc[url] = { - title: url, - popupTitle: `Cookies used by frames from ${url}`, - panel: , - icon: , - selectedIcon: , - children: {}, - isBlurred: !frameHasCookies?.[url], - }; - - return acc; - }, {}); - - const showInspectButton = - canStartInspecting && Boolean(Object.keys(tabFrames || {}).length); - - if (showInspectButton) { - psData.children['cookies'].extraInterfaceToTitle = ( - - ); - } else { - psData.children['cookies'].extraInterfaceToTitle = null; - } - - return data; - }); - }, [ - canStartInspecting, - frameHasCookies, - isInspecting, - isKeySelected, - isSidebarFocused, - setIsInspecting, - tabFrames, - ]); - - useEffect(() => { - if (Object.keys(tabFrames || {}).includes(currentItemKey || '')) { - setSelectedFrame(currentItemKey); - } else { - setSelectedFrame(null); - } - }, [currentItemKey, setSelectedFrame, tabFrames]); - - useEffect(() => { - (async () => { - const tabId = chrome.devtools.inspectedWindow.tabId.toString(); - - const data = await chrome.storage.local.get(); - - if (!data?.[tabId]) { - data[tabId] = {}; - } - - if (!data[tabId]?.['selectedSidebarItem']) { - data[tabId]['selectedSidebarItem'] = 'cookies'; - } - - data[tabId]['selectedSidebarItem'] = selectedItemKey; - - await chrome.storage.local.set(data); - })(); - }, [selectedItemKey]); - - const lastUrl = useRef(tabUrl); - - useEffect(() => { - if (lastUrl.current === tabUrl || lastUrl.current === null) { - lastUrl.current = tabUrl; - return; - } - - lastUrl.current = tabUrl; - - updateSelectedItemKey(selectedFrame || 'cookies'); - }, [selectedFrame, tabUrl, updateSelectedItemKey]); - - const [filteredCookies, setFilteredCookies] = useState([]); - - const handleUpdate = useCallback( - (key: string | null) => { - updateSelectedItemKey(key || 'cookies'); - }, - [updateSelectedItemKey] - ); - useEffect(() => { (async () => { const localStorageFlag = localStorage.getItem('contextInvalidated'); @@ -248,52 +98,23 @@ const App: React.FC = () => { })(); }, [allowedNumberOfTabs]); - useFrameOverlay(filteredCookies, handleUpdate); - return ( -
- {contextInvalidated && ( -
- -
- )} - {!contextInvalidated && ( -
- { - setSidebarWidth((prevState) => prevState + d.width); - }} - minWidth={'150px'} - maxWidth={'90%'} - enable={{ - right: true, - }} - className="h-full" - > - - -
-
{activePanel}
-
-
- )} -
+
+ {contextInvalidated && ( +
+ +
+ )} + {!contextInvalidated && } +
+ ); }; diff --git a/packages/extension/src/view/devtools/components/index.ts b/packages/extension/src/view/devtools/components/index.ts index 88a630178..1d225e910 100644 --- a/packages/extension/src/view/devtools/components/index.ts +++ b/packages/extension/src/view/devtools/components/index.ts @@ -20,3 +20,4 @@ export { default as Cookies } from './cookies'; export { default as PrivacySandbox } from './privacySandbox'; export { default as Settings } from './settings'; export { default as FacilitatedTesting } from './facilitatedTesting'; +export { default as Layout } from './layout'; diff --git a/packages/extension/src/view/devtools/components/layout.tsx b/packages/extension/src/view/devtools/components/layout.tsx new file mode 100644 index 000000000..8416ddbd7 --- /dev/null +++ b/packages/extension/src/view/devtools/components/layout.tsx @@ -0,0 +1,235 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * External dependencies. + */ +import React, { memo, useCallback, useEffect, useRef, useState } from 'react'; +import { + UNKNOWN_FRAME_KEY, + type CookieTableData, +} from '@ps-analysis-tool/common'; +import { + Sidebar, + useSidebar, + type SidebarItems, + CookieIconWhite, + CookieIcon, + InspectButton, +} from '@ps-analysis-tool/design-system'; +import { Resizable } from 're-resizable'; + +/** + * Internal dependencies. + */ +import Cookies from './cookies'; +import useFrameOverlay from '../hooks/useFrameOverlay'; +import { useCookieStore } from '../stateProviders/syncCookieStore'; + +interface LayoutProps { + setSidebarData: React.Dispatch>; +} + +const Layout = ({ setSidebarData }: LayoutProps) => { + const [sidebarWidth, setSidebarWidth] = useState(200); + const { + tabFrames, + frameHasCookies, + canStartInspecting, + tabUrl, + isInspecting, + setIsInspecting, + selectedFrame, + setSelectedFrame, + } = useCookieStore(({ state, actions }) => ({ + tabFrames: state.tabFrames, + frameHasCookies: state.frameHasCookies, + canStartInspecting: state.canStartInspecting, + tabUrl: state.tabUrl, + isInspecting: state.isInspecting, + setIsInspecting: actions.setIsInspecting, + selectedFrame: state.selectedFrame, + setSelectedFrame: actions.setSelectedFrame, + })); + + const { + activePanel, + selectedItemKey, + currentItemKey, + sidebarItems, + isSidebarFocused, + setIsSidebarFocused, + updateSelectedItemKey, + onKeyNavigation, + toggleDropdown, + isKeyAncestor, + isKeySelected, + } = useSidebar(({ state, actions }) => ({ + activePanel: state.activePanel, + selectedItemKey: state.selectedItemKey, + currentItemKey: state.currentItemKey, + sidebarItems: state.sidebarItems, + isSidebarFocused: state.isSidebarFocused, + setIsSidebarFocused: actions.setIsSidebarFocused, + updateSelectedItemKey: actions.updateSelectedItemKey, + onKeyNavigation: actions.onKeyNavigation, + toggleDropdown: actions.toggleDropdown, + isKeyAncestor: actions.isKeyAncestor, + isKeySelected: actions.isKeySelected, + })); + + useEffect(() => { + setSidebarData((prev) => { + const data = { ...prev }; + const psData = data['privacySandbox']; + + psData.children['cookies'].panel = ( + + ); + psData.children['cookies'].children = Object.keys(tabFrames || {}) + .filter((url) => { + return url === UNKNOWN_FRAME_KEY ? frameHasCookies[url] : true; + }) + .reduce((acc, url) => { + acc[url] = { + title: url, + popupTitle: `Cookies used by frames from ${url}`, + panel: , + icon: , + selectedIcon: , + children: {}, + isBlurred: !frameHasCookies?.[url], + }; + + return acc; + }, {}); + + const showInspectButton = + canStartInspecting && Boolean(Object.keys(tabFrames || {}).length); + + if (showInspectButton) { + psData.children['cookies'].extraInterfaceToTitle = ( + + ); + } else { + psData.children['cookies'].extraInterfaceToTitle = null; + } + + return data; + }); + }, [ + canStartInspecting, + frameHasCookies, + isInspecting, + isKeySelected, + isSidebarFocused, + setIsInspecting, + setSidebarData, + tabFrames, + ]); + + useEffect(() => { + if (Object.keys(tabFrames || {}).includes(currentItemKey || '')) { + setSelectedFrame(currentItemKey); + } else { + setSelectedFrame(null); + } + }, [currentItemKey, setSelectedFrame, tabFrames]); + + useEffect(() => { + (async () => { + const tabId = chrome.devtools.inspectedWindow.tabId.toString(); + + const data = await chrome.storage.local.get(); + + if (!data?.[tabId]) { + data[tabId] = {}; + } + + if (!data[tabId]?.['selectedSidebarItem']) { + data[tabId]['selectedSidebarItem'] = 'cookies'; + } + + data[tabId]['selectedSidebarItem'] = selectedItemKey; + + await chrome.storage.local.set(data); + })(); + }, [selectedItemKey]); + + const lastUrl = useRef(tabUrl); + + useEffect(() => { + if (lastUrl.current === tabUrl || lastUrl.current === null) { + lastUrl.current = tabUrl; + return; + } + + lastUrl.current = tabUrl; + + updateSelectedItemKey(selectedFrame || 'cookies'); + }, [selectedFrame, setSelectedFrame, tabUrl, updateSelectedItemKey]); + + const [filteredCookies, setFilteredCookies] = useState([]); + + const handleUpdate = useCallback( + (key: string | null) => { + updateSelectedItemKey(key || 'cookies'); + }, + [updateSelectedItemKey] + ); + + useFrameOverlay(filteredCookies, handleUpdate); + + return ( +
+ { + setSidebarWidth((prevState) => prevState + d.width); + }} + minWidth={'150px'} + maxWidth={'90%'} + enable={{ + right: true, + }} + className="h-full" + > + + +
+
{activePanel}
+
+
+ ); +}; + +export default memo(Layout);