Add initial product data views screen (#50981)

* Add product data views feature flag

* Add basic products app file

* Add lazy render for product app

* Only render if GB is enabled

* Add translation

* Add changelogs

* Address lint issues

* Address final lint error
This commit is contained in:
louwie17 2024-08-27 14:49:04 +02:00 committed by GitHub
parent cf042dfb0a
commit f2941d76e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 905 additions and 580 deletions

View File

@ -199,7 +199,8 @@
"@wordpress/viewport",
"@wordpress/interface",
"@wordpress/router",
"@wordpress/edit-site"
"@wordpress/edit-site",
"@wordpress/private-apis"
],
"packages": [
"@woocommerce/block-templates",

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add new product data views component for use on new product data views page.

View File

@ -71,6 +71,7 @@
"@wordpress/media-utils": "wp-6.0",
"@wordpress/plugins": "wp-6.0",
"@wordpress/preferences": "wp-6.0",
"@wordpress/private-apis": "^1.6.0",
"@wordpress/url": "wp-6.0",
"classnames": "^2.3.2",
"dompurify": "^2.4.7",

View File

@ -35,6 +35,11 @@ export * from './contexts/validation-context/types';
export { EditorLoadingContext as __experimentalEditorLoadingContext } from './contexts/editor-loading-context';
export { PostTypeContext } from './contexts/post-type-context';
/**
* Product data views page.
*/
export * from './products';
// Init the store
registerProductEditorUiStore();

View File

@ -0,0 +1,10 @@
/**
* External dependencies
*/
import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis';
export const { lock, unlock } =
__dangerousOptInToUnstableAPIsOnlyForCoreModules(
'I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.',
'@wordpress/edit-site'
);

View File

@ -0,0 +1,33 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import { privateApis as routerPrivateApis } from '@wordpress/router';
import {
UnsavedChangesWarning,
// @ts-expect-error No types for this exist yet.
privateApis as editorPrivateApis,
} from '@wordpress/editor';
/**
* Internal dependencies
*/
import { unlock } from '../lock-unlock';
const { RouterProvider } = unlock( routerPrivateApis );
const { GlobalStylesProvider } = unlock( editorPrivateApis );
function ProductsLayout() {
return <div>Initial Products Layout</div>;
}
export function ProductsApp() {
return (
<GlobalStylesProvider>
<UnsavedChangesWarning />
<RouterProvider>
<ProductsLayout />
</RouterProvider>
</GlobalStylesProvider>
);
}

View File

@ -0,0 +1,40 @@
@include wordpress-admin-schemes();
.woocommerce_page_woocommerce-products-dashboard #wpadminbar,
.woocommerce_page_woocommerce-products-dashboard #adminmenumain {
display: none;
}
.woocommerce_page_woocommerce-products-dashboard #wpcontent {
margin-left: 0;
}
body.woocommerce_page_woocommerce-products-dashboard
#woocommerce-products-dashboard {
@include wp-admin-reset("#woocommerce-products-dashboard");
@include reset;
display: block !important;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
min-height: 100vh;
}
body.js.is-fullscreen-mode {
@include break-medium {
// Reset the html.wp-topbar padding.
// Because this uses negative margins, we have to compensate for the height.
margin-top: -$admin-bar-height;
height: calc(100% + #{$admin-bar-height});
#adminmenumain,
#wpadminbar {
display: none;
}
#wpcontent,
#wpfooter {
margin-left: 0;
}
}
}

View File

@ -0,0 +1,53 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import {
StrictMode,
Suspense,
createElement,
// @ts-expect-error createRoot is available.
createRoot,
lazy,
} from '@wordpress/element';
/**
* Internal dependencies
*/
import { getGutenbergVersion } from './utils/get-gutenberg-version';
const ProductsApp = lazy( () =>
import( './products-app' ).then( ( module ) => ( {
default: module.ProductsApp,
} ) )
);
/**
* Initializes the "Products Dashboard".
*
* @param {string} id DOM element id.
*/
export function initializeProductsDashboard( id: string ) {
const target = document.getElementById( id );
const root = createRoot( target );
const isGutenbergEnabled = getGutenbergVersion() > 0;
root.render(
<StrictMode>
{ isGutenbergEnabled ? (
<Suspense fallback={ null }>
<ProductsApp />
</Suspense>
) : (
<div>
{ __(
'Please enabled Gutenberg for this feature',
'woocommerce'
) }
</div>
) }
</StrictMode>
);
return root;
}

View File

@ -60,3 +60,5 @@
/* Hooks */
@import "hooks/use-draggable/styles.scss";
@import "products.scss";

View File

@ -25,9 +25,21 @@ declare module '@wordpress/core-data' {
name: string,
id: number | string,
options?: { enabled: boolean }
): { record: T, editedRecord: T, isResolving: boolean, hasResolved: boolean };
): {
record: T;
editedRecord: T;
isResolving: boolean;
hasResolved: boolean;
};
}
declare module '@wordpress/keyboard-shortcuts' {
function useShortcut(name: string, callback: (event: KeyboardEvent) => void): void;
function useShortcut(
name: string,
callback: ( event: KeyboardEvent ) => void
): void;
const store;
}
declare module '@wordpress/router' {
const privateApis;
}

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add new feature for a product data views page.

View File

@ -3,6 +3,7 @@
"activity-panels": true,
"analytics": true,
"product-block-editor": true,
"product-data-views": false,
"experimental-blocks": false,
"coupons": true,
"core-profiler": true,

View File

@ -3,6 +3,7 @@
"activity-panels": true,
"analytics": true,
"product-block-editor": true,
"product-data-views": false,
"experimental-blocks": true,
"coupons": true,
"core-profiler": true,

View File

@ -0,0 +1,145 @@
<?php
/**
* WooCommerce Product Data Views
*/
declare( strict_types = 1 );
namespace Automattic\WooCommerce\Admin\Features\ProductDataViews;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Blocks\Utils\Utils;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
/**
* Loads assets related to the product block editor.
*/
class Init {
/**
* Constructor
*/
public function __construct() {
if ( $this->has_data_views_support() ) {
add_action( 'admin_menu', array( $this, 'woocommerce_add_new_products_dashboard' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
if ( $this->is_product_data_view_page() ) {
add_filter(
'admin_body_class',
static function ( $classes ) {
return "$classes is-fullscreen-mode";
}
);
}
}
}
/**
* Returns true if we are on a JS powered admin page.
*/
private static function is_product_data_view_page() {
// phpcs:disable WordPress.Security.NonceVerification
return isset( $_GET['page'] ) && 'woocommerce-products-dashboard' === $_GET['page'];
// phpcs:enable WordPress.Security.NonceVerification
}
/**
* Checks for data views support.
*/
private function has_data_views_support() {
if ( Utils::wp_version_compare( '6.6', '>=' ) ) {
return true;
}
if ( is_plugin_active( 'gutenberg/gutenberg.php' ) ) {
$gutenberg_version = '';
if ( defined( 'GUTENBERG_VERSION' ) ) {
$gutenberg_version = GUTENBERG_VERSION;
}
if ( ! $gutenberg_version ) {
$gutenberg_data = get_file_data(
WP_PLUGIN_DIR . '/gutenberg/gutenberg.php',
array( 'Version' => 'Version' )
);
$gutenberg_version = $gutenberg_data['Version'];
}
return version_compare( $gutenberg_version, '19.0', '>=' );
}
return false;
}
/**
* Enqueue styles needed for the rich text editor.
*/
public function enqueue_styles() {
if ( ! $this->is_product_data_view_page() ) {
return;
}
wp_enqueue_style( 'wc-product-editor' );
}
/**
* Enqueue scripts needed for the product form block editor.
*/
public function enqueue_scripts() {
if ( ! $this->is_product_data_view_page() ) {
return;
}
$script_handle = 'wc-admin-edit-product';
wp_register_script( $script_handle, '', array( 'wp-blocks' ), '0.1.0', true );
wp_enqueue_script( $script_handle );
wp_enqueue_media();
wp_register_style( 'wc-global-presets', false ); // phpcs:ignore
wp_add_inline_style( 'wc-global-presets', wp_get_global_stylesheet( array( 'presets' ) ) );
wp_enqueue_style( 'wc-global-presets' );
}
/**
* Replaces the default posts menu item with the new posts dashboard.
*/
public function woocommerce_add_new_products_dashboard() {
$gutenberg_experiments = get_option( 'gutenberg-experiments' );
if ( ! $gutenberg_experiments ) {
return;
}
$ptype_obj = get_post_type_object( 'product' );
add_submenu_page(
'woocommerce',
$ptype_obj->labels->name,
esc_html__( 'All Products', 'woocommerce' ),
'manage_woocommerce',
'woocommerce-products-dashboard',
array( $this, 'woocommerce_products_dashboard' ),
1
);
}
/**
* Renders the new posts dashboard page.
*/
public function woocommerce_products_dashboard() {
$suffix = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
$version = Constants::get_constant( 'WC_VERSION' );
if ( function_exists( 'gutenberg_url' ) ) {
// phpcs:disable WordPress.WP.EnqueuedResourceParameters.MissingVersion
wp_register_style(
'wp-gutenberg-posts-dashboard',
gutenberg_url( 'build/edit-site/posts.css', __FILE__ ),
array( 'wp-components' ),
);
// phpcs:enable WordPress.WP.EnqueuedResourceParameters.MissingVersion
wp_enqueue_style( 'wp-gutenberg-posts-dashboard' );
}
WCAdminAssets::get_instance();
wp_enqueue_script( 'wc-admin-product-editor', WC()->plugin_url() . '/assets/js/admin/product-editor' . $suffix . '.js', array( 'wc-product-editor' ), $version, false );
wp_add_inline_script( 'wp-edit-site', 'window.wc.productEditor.initializeProductsDashboard( "woocommerce-products-dashboard" );', 'after' );
wp_enqueue_script( 'wp-edit-site' );
echo '<div id="woocommerce-products-dashboard"></div>';
}
}

File diff suppressed because it is too large Load Diff