Merge pull request woocommerce/woocommerce-admin#2280 from woocommerce/add/dashboard-section-example

Dashboard Extentions: Add a section
This commit is contained in:
Paul Sealock 2019-05-24 08:37:41 +12:00 committed by GitHub
commit 1c750474a0
9 changed files with 314 additions and 77 deletions

View File

@ -8,7 +8,7 @@ import { Component, Fragment } from '@wordpress/element';
import { compose } from '@wordpress/compose'; import { compose } from '@wordpress/compose';
import Gridicon from 'gridicons'; import Gridicon from 'gridicons';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { IconButton, NavigableMenu, SelectControl, TextControl } from '@wordpress/components'; import { IconButton, NavigableMenu, SelectControl } from '@wordpress/components';
import { withDispatch } from '@wordpress/data'; import { withDispatch } from '@wordpress/data';
/** /**
@ -79,24 +79,16 @@ class DashboardCharts extends Component {
); );
} ) } } ) }
{ window.wcAdminFeatures[ 'analytics-dashboard/customizable' ] && ( { window.wcAdminFeatures[ 'analytics-dashboard/customizable' ] && (
<Fragment>
<div className="woocommerce-ellipsis-menu__item">
<TextControl
label={ __( 'Section Title', 'woocommerce-admin' ) }
onBlur={ onTitleBlur }
onChange={ onTitleChange }
required
value={ titleInput }
/>
</div>
<Controls <Controls
onToggle={ onToggle } onToggle={ onToggle }
onMove={ onMove } onMove={ onMove }
onRemove={ onRemove } onRemove={ onRemove }
isFirst={ isFirst } isFirst={ isFirst }
isLast={ isLast } isLast={ isLast }
onTitleBlur={ onTitleBlur }
onTitleChange={ onTitleChange }
titleInput={ titleInput }
/> />
</Fragment>
) } ) }
</Fragment> </Fragment>
) } ) }

View File

@ -6,7 +6,7 @@ import { __ } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element'; import { Component, Fragment } from '@wordpress/element';
import { compose } from '@wordpress/compose'; import { compose } from '@wordpress/compose';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { SelectControl, TextControl } from '@wordpress/components'; import { SelectControl } from '@wordpress/components';
import { withDispatch } from '@wordpress/data'; import { withDispatch } from '@wordpress/data';
/** /**
@ -87,24 +87,16 @@ class Leaderboards extends Component {
onChange={ this.setRowsPerTable } onChange={ this.setRowsPerTable }
/> />
{ window.wcAdminFeatures[ 'analytics-dashboard/customizable' ] && ( { window.wcAdminFeatures[ 'analytics-dashboard/customizable' ] && (
<Fragment>
<div className="woocommerce-ellipsis-menu__item">
<TextControl
label={ __( 'Section Title', 'woocommerce-admin' ) }
onBlur={ onTitleBlur }
onChange={ onTitleChange }
required
value={ titleInput }
/>
</div>
<Controls <Controls
onToggle={ onToggle } onToggle={ onToggle }
onMove={ onMove } onMove={ onMove }
onRemove={ onRemove } onRemove={ onRemove }
isFirst={ isFirst } isFirst={ isFirst }
isLast={ isLast } isLast={ isLast }
onTitleBlur={ onTitleBlur }
onTitleChange={ onTitleChange }
titleInput={ titleInput }
/> />
</Fragment>
) } ) }
</Fragment> </Fragment>
) } ) }

View File

@ -3,8 +3,8 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { Icon } from '@wordpress/components'; import { Icon, TextControl } from '@wordpress/components';
import { Component } from '@wordpress/element'; import { Component, Fragment } from '@wordpress/element';
/** /**
* Internal dependencies * Internal dependencies
@ -33,9 +33,19 @@ class SectionControls extends Component {
} }
render() { render() {
const { onRemove, isFirst, isLast } = this.props; const { onRemove, isFirst, isLast, onTitleBlur, onTitleChange, titleInput } = this.props;
return ( return (
<Fragment>
<div className="woocommerce-ellipsis-menu__item">
<TextControl
label={ __( 'Section Title', 'woocommerce-admin' ) }
onBlur={ onTitleBlur }
onChange={ onTitleChange }
required
value={ titleInput }
/>
</div>
<div className="woocommerce-dashboard-section-controls"> <div className="woocommerce-dashboard-section-controls">
{ ! isFirst && ( { ! isFirst && (
<MenuItem isClickable onInvoke={ this.onMoveUp }> <MenuItem isClickable onInvoke={ this.onMoveUp }>
@ -54,6 +64,7 @@ class SectionControls extends Component {
{ __( 'Remove section', 'woocommerce-admin' ) } { __( 'Remove section', 'woocommerce-admin' ) }
</MenuItem> </MenuItem>
</div> </div>
</Fragment>
); );
} }
} }

View File

@ -8,7 +8,6 @@ import { compose } from '@wordpress/compose';
import { withDispatch } from '@wordpress/data'; import { withDispatch } from '@wordpress/data';
import moment from 'moment'; import moment from 'moment';
import { find } from 'lodash'; import { find } from 'lodash';
import { TextControl } from '@wordpress/components';
/** /**
* WooCommerce dependencies * WooCommerce dependencies
@ -73,24 +72,16 @@ class StorePerformance extends Component {
); );
} ) } } ) }
{ window.wcAdminFeatures[ 'analytics-dashboard/customizable' ] && ( { window.wcAdminFeatures[ 'analytics-dashboard/customizable' ] && (
<Fragment>
<div className="woocommerce-ellipsis-menu__item">
<TextControl
label={ __( 'Section Title', 'woocommerce-admin' ) }
onBlur={ onTitleBlur }
onChange={ onTitleChange }
required
value={ titleInput }
/>
</div>
<Controls <Controls
onToggle={ onToggle } onToggle={ onToggle }
onMove={ onMove } onMove={ onMove }
onRemove={ onRemove } onRemove={ onRemove }
isFirst={ isFirst } isFirst={ isFirst }
isLast={ isLast } isLast={ isLast }
onTitleBlur={ onTitleBlur }
onTitleChange={ onTitleChange }
titleInput={ titleInput }
/> />
</Fragment>
) } ) }
</Fragment> </Fragment>
) } ) }

View File

@ -0,0 +1,43 @@
/** @format */
/**
* External dependencies
*/
import moment from 'moment';
/**
* WooCommerce dependencies
*/
import { Card, Chart } from '@woocommerce/components';
import { formatCurrency } from '@woocommerce/currency';
const data = [];
for ( let i = 1; i <= 20; i++ ) {
const date = moment().subtract( i, 'days' );
data.push( {
date: date.format( 'YYYY-MM-DDT00:00:00' ),
primary: {
label: 'Global Apple Prices, last 20 days',
labelDate: date.format( 'YYYY-MM-DD 00:00:00' ),
value: Math.floor( Math.random() * 100 ),
},
} );
}
const GlobalPrices = () => {
return (
<Card className="woocommerce-dashboard__chart-block woocommerce-analytics__card" title="Global Apple Prices">
<Chart
title="Global Apple Prices"
interval="day"
data={ data.reverse() }
dateParser="%Y-%m-%dT%H:%M:%S"
showHeaderControls={ false }
valueType={ 'currency' }
tooltipValueFormat={ formatCurrency }
/>
</Card>
);
};
export default GlobalPrices;

View File

@ -0,0 +1,126 @@
/** @format */
/**
* External dependencies
*/
import { addFilter } from '@wordpress/hooks';
import { Component, Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
/**
* WooCommerce dependencies
*/
import { EllipsisMenu, MenuTitle, MenuItem, SectionHeader } from '@woocommerce/components';
/**
* Internal dependencies
*/
import UpcomingEvents from './upcoming-events';
import GlobalPrices from './global-prices';
const config = [
{
title: 'Granny Smith',
events: [ { date: '2020-01-02', title: 'The Granny Apple Fair' } ],
},
{
title: 'Golden Delicious',
events: [
{ date: '2020-04-15', title: 'Madrid Manzana Dorada' },
{ date: '2020-05-07', title: 'Golden CO Golden Delicious Day' },
],
},
{
title: 'Gala',
events: [ { date: '2020-08-31', title: 'The Met Gala Pomme' } ],
},
{
title: 'Braeburn',
events: [ { date: '2020-08-18', title: 'Mt. Aoraki Crisper' } ],
},
];
const dashboardItems = [
{ title: 'Upcoming Events', component: UpcomingEvents, key: 'upcoming-events' },
{ title: 'Global Apple Prices', component: GlobalPrices, key: 'global-prices' },
];
class Section extends Component {
renderMenu() {
const {
hiddenBlocks,
onToggleHiddenBlock,
onTitleBlur,
onTitleChange,
titleInput,
onMove,
onRemove,
isFirst,
isLast,
controls: Controls,
} = this.props;
return (
<EllipsisMenu
label={ __( 'Choose Apples', 'woocommerce-admin' ) }
renderContent={ ( { onToggle } ) => (
<Fragment>
<MenuTitle>{ __( 'My Apples', 'woocommerce-admin' ) }</MenuTitle>
{ dashboardItems.map( item => (
<MenuItem
checked={ ! hiddenBlocks.includes( item.key ) }
isCheckbox
isClickable
key={ item.key }
onInvoke={ () => onToggleHiddenBlock( item.key )() }
>
{ item.title }
</MenuItem>
) ) }
<Controls
onToggle={ onToggle }
onMove={ onMove }
onRemove={ onRemove }
isFirst={ isFirst }
isLast={ isLast }
onTitleBlur={ onTitleBlur }
onTitleChange={ onTitleChange }
titleInput={ titleInput }
/>
</Fragment>
) }
/>
);
}
render() {
const { title, hiddenBlocks } = this.props;
return (
<Fragment>
<SectionHeader title={ title } menu={ this.renderMenu() } />
<div className="woocommerce-dashboard__columns">
{ dashboardItems.map( item => {
return hiddenBlocks.includes( item.key ) ? null : (
<item.component key={ item.key } config={ config } />
);
} ) }
</div>
</Fragment>
);
}
}
addFilter( 'woocommerce_dashboard_default_sections', 'plugin-domain', sections => {
return [
...sections,
{
key: 'dashboard-apples',
component: Section,
title: __( 'Apples', 'woocommerce-admin' ),
isVisible: true,
icon: 'carrot',
hiddenBlocks: [],
},
];
} );

View File

@ -0,0 +1,39 @@
/** @format */
/**
* External dependencies
*/
import { flatten } from 'lodash';
/**
* WooCommerce dependencies
*/
import { TableCard } from '@woocommerce/components';
const UpcomingEvents = ( { config } ) => {
const rows = flatten(
config.map( apple => {
return apple.events.map( event => {
return [
{ display: apple.title, value: 'variety' },
{ display: event.title, value: 'event' },
{ display: event.date, value: 'date' },
];
} );
} )
);
return (
<TableCard
title={ 'Upcoming Events' }
headers={ [
{ label: 'Variety', key: 'variety' },
{ label: 'Event', key: 'event' },
{ label: 'Date', key: 'date' },
] }
rows={ rows }
rowsPerPage={ 100 }
totalRows={ 1 }
/>
);
};
export default UpcomingEvents;

View File

@ -0,0 +1,32 @@
<?php
/**
* Plugin Name: WooCommerce Admin Dashboard Section Example
*
* @package WC_Admin
*/
/**
* Register the JS.
*/
function dashboard_section_register_script() {
if ( ! class_exists( 'WC_Admin_Loader' ) || ! WC_Admin_Loader::is_admin_page() ) {
return;
}
wp_register_script(
'add-report',
plugins_url( '/dist/index.js', __FILE__ ),
array(
'wp-hooks',
'wp-element',
'wp-i18n',
'wc-components',
),
filemtime( dirname( __FILE__ ) . '/dist/index.js' ),
true
);
wp_enqueue_script( 'add-report' );
}
add_action( 'admin_enqueue_scripts', 'dashboard_section_register_script' );

View File

@ -6,6 +6,7 @@ const path = require( 'path' );
const CopyWebpackPlugin = require( 'copy-webpack-plugin' ); const CopyWebpackPlugin = require( 'copy-webpack-plugin' );
const fs = require( 'fs' ); const fs = require( 'fs' );
const woocommerceAdminConfig = require( path.resolve( __dirname, '../../../webpack.config.js' ) ); const woocommerceAdminConfig = require( path.resolve( __dirname, '../../../webpack.config.js' ) );
const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' );
const extArg = process.argv.find( arg => arg.startsWith( '--ext=' ) ); const extArg = process.argv.find( arg => arg.startsWith( '--ext=' ) );
@ -55,6 +56,13 @@ const webpackConfig = {
}, },
}, },
}, },
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
],
},
], ],
}, },
resolve: { resolve: {
@ -73,6 +81,9 @@ const webpackConfig = {
to: path.resolve( __dirname, `../../../../${ extension }/` ), to: path.resolve( __dirname, `../../../../${ extension }/` ),
}, },
] ), ] ),
new MiniCssExtractPlugin( {
filename: '[name]/dist/style.css',
} ),
], ],
}; };