From 295a2d83e27ffd69c4c6f5f5ce9953ee3b26d664 Mon Sep 17 00:00:00 2001 From: Chi-Hsuan Huang Date: Wed, 13 Nov 2024 16:23:30 +0800 Subject: [PATCH] [Settings] Implement URL routing with query parameters and active sidebar item (#52721) * set up SidebarNavigationScreen * install deps * GlobalStylesProvider * Add labels to pages/sections * get types in order * get SettingItem working * tidy up * pass icon from PHP * add icons to each Page * layout styles * edit site styles * organize * edit-site to 6.10 * unit tests * lint * lint * Add changefile(s) from automation for the following project(s): @woocommerce/settings-editor, woocommerce, woocommerce/client/admin * lint * better linting * [Settings] Create a route file to handle populating Settings (#52692) * Add settings route * Add changelog * Add TODO comment * Add changelog * Rebase on sidebar changes * Fix types and tests * Fix path * Convert to tab * Update test * Update sidebar to reflect the route with the active item and linking * Add changelog * Add changelog * fix merge conflict errors * Revert pnpm-lock.yaml * [Settings] Update Modern Routes (#52757) * update Sidebar * cleanup * Add changefile(s) from automation for the following project(s): @woocommerce/settings-editor * export sidebar * export route methods * Revert "export route methods" This reverts commit 46a6cd1e0abadea54cc43ab317d4707d9e4e5fcc. * handle modern pages * Add changefile(s) from automation for the following project(s): @woocommerce/settings-editor, woocommerce * cleanup * remove export * update tests --------- Co-authored-by: github-actions Co-authored-by: Chi-Hsuan Huang --------- Co-authored-by: paul sealock Co-authored-by: github-actions --- .../52757-update-settings-sidebar-components | 4 + .../update-settings-sidebar-acitve-item | 4 + packages/js/settings-editor/src/route.tsx | 103 +++++++++++------- .../js/settings-editor/src/sidebar/index.tsx | 31 +++++- .../src/sidebar/setting-item.tsx | 8 +- .../settings-editor/src/tests/route.test.tsx | 21 +--- .../52757-update-settings-sidebar-components | 4 + .../admin/settings/class-wc-settings-page.php | 16 ++- 8 files changed, 130 insertions(+), 61 deletions(-) create mode 100644 packages/js/settings-editor/changelog/52757-update-settings-sidebar-components create mode 100644 packages/js/settings-editor/changelog/update-settings-sidebar-acitve-item create mode 100644 plugins/woocommerce/changelog/52757-update-settings-sidebar-components diff --git a/packages/js/settings-editor/changelog/52757-update-settings-sidebar-components b/packages/js/settings-editor/changelog/52757-update-settings-sidebar-components new file mode 100644 index 00000000000..d024e767862 --- /dev/null +++ b/packages/js/settings-editor/changelog/52757-update-settings-sidebar-components @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak +Comment: Organizes unreleased component + diff --git a/packages/js/settings-editor/changelog/update-settings-sidebar-acitve-item b/packages/js/settings-editor/changelog/update-settings-sidebar-acitve-item new file mode 100644 index 00000000000..8291dc26495 --- /dev/null +++ b/packages/js/settings-editor/changelog/update-settings-sidebar-acitve-item @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Update sidebar to reflect the route with the active item and linking diff --git a/packages/js/settings-editor/src/route.tsx b/packages/js/settings-editor/src/route.tsx index 864c5a7cb87..37fd700be73 100644 --- a/packages/js/settings-editor/src/route.tsx +++ b/packages/js/settings-editor/src/route.tsx @@ -16,8 +16,6 @@ import { } from '@wordpress/hooks'; /* eslint-disable @woocommerce/dependency-group */ // @ts-ignore No types for this exist yet. -import SidebarNavigationScreen from '@wordpress/edit-site/build-module/components/sidebar-navigation-screen'; -// @ts-ignore No types for this exist yet. import { privateApis as routerPrivateApis } from '@wordpress/router'; // @ts-ignore No types for this exist yet. import { unlock } from '@wordpress/edit-site/build-module/lock-unlock'; @@ -32,21 +30,29 @@ import { Route, Location } from './types'; const { useLocation } = unlock( routerPrivateApis ); const NotFound = () => { - return ( -

- { __( 'Page not found', 'woocommerce' ) } -

- ); + return

{ __( 'Page not found', 'woocommerce' ) }

; }; /** - * Default route when a page is not found. + * Default route when active page is not found. + * + * @param {string} activePage - The active page. + * @param {typeof window.wcSettings.admin.settingsPages} pages - The pages. * */ -const getNotFoundRoute = ( page: string ): Route => ( { - key: page, +const getNotFoundRoute = ( + activePage: string, + pages: typeof window.wcSettings.admin.settingsPages +): Route => ( { + key: activePage, areas: { - sidebar: null, + sidebar: ( + + ), content: , edit: null, }, @@ -59,29 +65,35 @@ const getNotFoundRoute = ( page: string ): Route => ( { /** * Creates a route configuration for legacy settings pages. * - * @param {string} page - The page identifier. + * @param {string} activePage - The active page. + * @param {typeof window.wcSettings.admin.settingsPages} pages - The pages. */ const getLegacyRoute = ( - page: string, + activePage: string, pages: typeof window.wcSettings.admin.settingsPages -): Route => ( { - key: page, - areas: { - sidebar: ( - } - /> - ), - content:
Content Placeholder: current tab: { page }
, - edit: null, - }, - widths: { - content: undefined, - edit: undefined, - }, -} ); +): Route => { + const pageTitle = + pages[ activePage ]?.label || __( 'Settings', 'woocommerce' ); + + return { + key: activePage, + areas: { + sidebar: ( + + ), + content:
Content Placeholder
, + edit: null, + }, + widths: { + content: undefined, + edit: undefined, + }, + }; +}; const PAGES_FILTER = 'woocommerce_admin_settings_pages'; @@ -139,19 +151,36 @@ export const useActiveRoute = () => { const modernRoutes = useModernRoutes(); return useMemo( () => { - const { tab: page = 'general' } = location.params; - const pageSettings = settingsPages?.[ page ]; + const { tab: activePage = 'general' } = location.params; + const pageSettings = settingsPages?.[ activePage ]; if ( ! pageSettings ) { - return getNotFoundRoute( page ); + return getNotFoundRoute( activePage, settingsPages ); } // Handle legacy pages. if ( ! pageSettings.is_modern ) { - return getLegacyRoute( page, settingsPages ); + return getLegacyRoute( activePage, settingsPages ); } + const modernRoute = modernRoutes[ activePage ]; + // Handle modern pages. - return modernRoutes[ page ] || getNotFoundRoute( page ); - }, [ settingsPages, location, modernRoutes ] ); + if ( ! modernRoute ) { + return getNotFoundRoute( activePage, settingsPages ); + } + + // Sidebar is responsibility of WooCommerce, not extensions so add it here. + modernRoute.areas.sidebar = ( + + ); + // Make sure we have a key. + modernRoute.key = activePage; + + return modernRoute; + }, [ settingsPages, location.params, modernRoutes ] ); }; diff --git a/packages/js/settings-editor/src/sidebar/index.tsx b/packages/js/settings-editor/src/sidebar/index.tsx index 44ce92a6cf5..4444a8d9147 100644 --- a/packages/js/settings-editor/src/sidebar/index.tsx +++ b/packages/js/settings-editor/src/sidebar/index.tsx @@ -6,6 +6,8 @@ import { createElement } from '@wordpress/element'; // @ts-expect-error missing type. // eslint-disable-next-line @wordpress/no-unsafe-wp-apis import { __experimentalItemGroup as ItemGroup } from '@wordpress/components'; +// @ts-ignore No types for this exist yet. +import SidebarNavigationScreen from '@wordpress/edit-site/build-module/components/sidebar-navigation-screen'; import * as IconPackage from '@wordpress/icons'; /* eslint-enable @woocommerce/dependency-group */ @@ -16,9 +18,11 @@ import { SettingItem } from './setting-item'; const { Icon, ...icons } = IconPackage; -export const Sidebar = ( { +const SidebarNavigationScreenContent = ( { + activePage, pages, }: { + activePage: string; pages: typeof window.wcSettings.admin.settingsPages; } ) => { return ( @@ -30,7 +34,7 @@ export const Sidebar = ( { key={ slug } slug={ slug } label={ label } - isActive={ false } + isActive={ activePage === slug } icon={ ); }; + +export const Sidebar = ( { + activePage, + pages, + pageTitle, +}: { + activePage: string; + pages: typeof window.wcSettings.admin.settingsPages; + pageTitle: string; +} ) => { + return ( + + } + /> + ); +}; diff --git a/packages/js/settings-editor/src/sidebar/setting-item.tsx b/packages/js/settings-editor/src/sidebar/setting-item.tsx index 37d28b2c9ce..bad23f775c1 100644 --- a/packages/js/settings-editor/src/sidebar/setting-item.tsx +++ b/packages/js/settings-editor/src/sidebar/setting-item.tsx @@ -63,11 +63,12 @@ export function SettingItem( { params: { postType, page }, } = useLocation(); - const linkInfo = useLink( { + const { href, onClick } = useLink( { page, postType, - slug, + tab: slug, } ); + return ( { label } diff --git a/packages/js/settings-editor/src/tests/route.test.tsx b/packages/js/settings-editor/src/tests/route.test.tsx index f00ce782009..172926484a7 100644 --- a/packages/js/settings-editor/src/tests/route.test.tsx +++ b/packages/js/settings-editor/src/tests/route.test.tsx @@ -33,19 +33,11 @@ jest.mock( '@wordpress/edit-site/build-module/lock-unlock', () => ( { unlock: jest.fn( ( apis ) => apis ), } ) ); -jest.mock( - '@wordpress/edit-site/build-module/components/sidebar-navigation-screen', - () => ( { - __esModule: true, - default: ( { children }: { children: React.ReactNode } ) => ( -
{ children }
- ), - } ) -); - jest.mock( '../sidebar', () => ( { __esModule: true, - Sidebar: jest.fn(), + Sidebar: ( { children }: { children: React.ReactNode } ) => ( +
{ children }
+ ), } ) ); const mockSettingsPages = { @@ -141,11 +133,11 @@ describe( 'route.tsx', () => { admin: { settingsPages: { modern: { - is_modern: true, label: 'Modern', + icon: 'published', slug: 'modern', - icon: 'settings', sections: [], + is_modern: true, }, }, }, @@ -153,9 +145,7 @@ describe( 'route.tsx', () => { ( applyFilters as jest.Mock ).mockReturnValue( { modern: { - key: 'modern', areas: { - sidebar: null, content:
Modern Page
, }, }, @@ -163,6 +153,7 @@ describe( 'route.tsx', () => { const { result } = renderHook( () => useActiveRoute() ); expect( result.current.key ).toBe( 'modern' ); + expect( result.current.areas.sidebar ).toBeDefined(); } ); } ); diff --git a/plugins/woocommerce/changelog/52757-update-settings-sidebar-components b/plugins/woocommerce/changelog/52757-update-settings-sidebar-components new file mode 100644 index 00000000000..d024e767862 --- /dev/null +++ b/plugins/woocommerce/changelog/52757-update-settings-sidebar-components @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak +Comment: Organizes unreleased component + diff --git a/plugins/woocommerce/includes/admin/settings/class-wc-settings-page.php b/plugins/woocommerce/includes/admin/settings/class-wc-settings-page.php index 0a995243723..0d6a8a86687 100644 --- a/plugins/woocommerce/includes/admin/settings/class-wc-settings-page.php +++ b/plugins/woocommerce/includes/admin/settings/class-wc-settings-page.php @@ -38,6 +38,13 @@ if ( ! class_exists( 'WC_Settings_Page', false ) ) : */ protected $label = ''; + /** + * Setting page is modern. + * + * @var bool + */ + protected $is_modern = false; + /** * Constructor. */ @@ -130,10 +137,11 @@ if ( ! class_exists( 'WC_Settings_Page', false ) ) : } $pages[ $this->id ] = array( - 'label' => html_entity_decode( $this->label ), - 'slug' => $this->id, - 'icon' => $this->icon, - 'sections' => $sections_data, + 'label' => html_entity_decode( $this->label ), + 'slug' => $this->id, + 'icon' => $this->icon, + 'sections' => $sections_data, + 'is_modern' => $this->is_modern, ); return $pages;