Add product data forms to data views (#51071)
* Add DataForms for products * Fix list view * Revert pnpm lock changes * Add changelog * Reference core store versus using string * Revert pnpm-lock
This commit is contained in:
parent
f8677c45d1
commit
907b591a42
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
Add DataForms panel to the experimental product data views list.
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useMemo } from '@wordpress/element';
|
||||||
|
import { edit } from '@wordpress/icons';
|
||||||
|
import { privateApis as routerPrivateApis } from '@wordpress/router';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { Product } from '@woocommerce/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { unlock } from '../../lock-unlock';
|
||||||
|
|
||||||
|
const { useHistory, useLocation } = unlock( routerPrivateApis );
|
||||||
|
|
||||||
|
export const useEditProductAction = ( { postType }: { postType: string } ) => {
|
||||||
|
const history = useHistory();
|
||||||
|
const location = useLocation();
|
||||||
|
return useMemo(
|
||||||
|
() => ( {
|
||||||
|
id: 'edit-product',
|
||||||
|
label: __( 'Edit', 'woocommerce' ),
|
||||||
|
isPrimary: true,
|
||||||
|
icon: edit,
|
||||||
|
supportsBulk: true,
|
||||||
|
isEligible( product: Product ) {
|
||||||
|
if ( product.status === 'trash' ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
callback( items: Product[] ) {
|
||||||
|
const product = items[ 0 ];
|
||||||
|
history.push( {
|
||||||
|
...location.params,
|
||||||
|
postId: product.id,
|
||||||
|
postType,
|
||||||
|
quickEdit: true,
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
} ),
|
||||||
|
[ history, location.params ]
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,160 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { DataForm, isItemValid } from '@wordpress/dataviews';
|
||||||
|
import type { Form } from '@wordpress/dataviews';
|
||||||
|
import { createElement, useState, useMemo } from '@wordpress/element';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { useSelect } from '@wordpress/data';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import {
|
||||||
|
// @ts-expect-error missing types.
|
||||||
|
__experimentalHeading as Heading,
|
||||||
|
// @ts-expect-error missing types.
|
||||||
|
__experimentalText as Text,
|
||||||
|
// @ts-expect-error missing types.
|
||||||
|
__experimentalHStack as HStack,
|
||||||
|
// @ts-expect-error missing types.
|
||||||
|
__experimentalVStack as VStack,
|
||||||
|
FlexItem,
|
||||||
|
Button,
|
||||||
|
} from '@wordpress/components';
|
||||||
|
// @ts-expect-error missing types.
|
||||||
|
// eslint-disable-next-line @woocommerce/dependency-group
|
||||||
|
import { privateApis as editorPrivateApis } from '@wordpress/editor';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { unlock } from '../../lock-unlock';
|
||||||
|
import { productFields } from '../product-list/fields';
|
||||||
|
|
||||||
|
const { NavigableRegion } = unlock( editorPrivateApis );
|
||||||
|
|
||||||
|
const form: Form = {
|
||||||
|
type: 'panel',
|
||||||
|
fields: [ 'name', 'status' ],
|
||||||
|
};
|
||||||
|
|
||||||
|
type ProductEditProps = {
|
||||||
|
subTitle?: string;
|
||||||
|
className?: string;
|
||||||
|
hideTitleFromUI?: boolean;
|
||||||
|
actions?: React.JSX.Element;
|
||||||
|
postType: string;
|
||||||
|
postId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ProductEdit( {
|
||||||
|
subTitle,
|
||||||
|
actions,
|
||||||
|
className,
|
||||||
|
hideTitleFromUI = true,
|
||||||
|
postType,
|
||||||
|
postId = '',
|
||||||
|
}: ProductEditProps ) {
|
||||||
|
const classes = classNames( 'edit-product-page', className, {
|
||||||
|
'is-empty': ! postId,
|
||||||
|
} );
|
||||||
|
const ids = useMemo( () => postId.split( ',' ), [ postId ] );
|
||||||
|
const { initialEdits } = useSelect(
|
||||||
|
( select ) => {
|
||||||
|
return {
|
||||||
|
initialEdits:
|
||||||
|
ids.length === 1
|
||||||
|
? select( 'wc/admin/products' ).getProduct( ids[ 0 ] )
|
||||||
|
: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ postType, ids ]
|
||||||
|
);
|
||||||
|
const [ edits, setEdits ] = useState( {} );
|
||||||
|
const itemWithEdits = useMemo( () => {
|
||||||
|
return {
|
||||||
|
...initialEdits,
|
||||||
|
...edits,
|
||||||
|
};
|
||||||
|
}, [ initialEdits, edits ] );
|
||||||
|
const isUpdateDisabled = ! isItemValid(
|
||||||
|
itemWithEdits,
|
||||||
|
productFields,
|
||||||
|
form
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSubmit = async ( event: Event ) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if ( ! isItemValid( itemWithEdits, productFields, form ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Empty save.
|
||||||
|
|
||||||
|
setEdits( {} );
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavigableRegion
|
||||||
|
className={ classes }
|
||||||
|
ariaLabel={ __( 'Product Edit', 'woocommerce' ) }
|
||||||
|
>
|
||||||
|
<div className="edit-product-content">
|
||||||
|
{ ! hideTitleFromUI && (
|
||||||
|
<VStack
|
||||||
|
className="edit-site-page-header"
|
||||||
|
as="header"
|
||||||
|
spacing={ 0 }
|
||||||
|
>
|
||||||
|
<HStack className="edit-site-page-header__page-title">
|
||||||
|
<Heading
|
||||||
|
as="h2"
|
||||||
|
level={ 3 }
|
||||||
|
weight={ 500 }
|
||||||
|
className="edit-site-page-header__title"
|
||||||
|
truncate
|
||||||
|
>
|
||||||
|
{ __( 'Product Edit', 'woocommerce' ) }
|
||||||
|
</Heading>
|
||||||
|
<FlexItem className="edit-site-page-header__actions">
|
||||||
|
{ actions }
|
||||||
|
</FlexItem>
|
||||||
|
</HStack>
|
||||||
|
{ subTitle && (
|
||||||
|
<Text
|
||||||
|
variant="muted"
|
||||||
|
as="p"
|
||||||
|
className="edit-site-page-header__sub-title"
|
||||||
|
>
|
||||||
|
{ subTitle }
|
||||||
|
</Text>
|
||||||
|
) }
|
||||||
|
</VStack>
|
||||||
|
) }
|
||||||
|
{ ! postId && (
|
||||||
|
<p>{ __( 'Select a product to edit', 'woocommerce' ) }</p>
|
||||||
|
) }
|
||||||
|
{ postId && (
|
||||||
|
<VStack spacing={ 4 } as="form" onSubmit={ onSubmit }>
|
||||||
|
<DataForm
|
||||||
|
data={ itemWithEdits }
|
||||||
|
fields={ productFields }
|
||||||
|
form={ form }
|
||||||
|
onChange={ setEdits }
|
||||||
|
/>
|
||||||
|
<FlexItem>
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
// @ts-expect-error missing type.
|
||||||
|
accessibleWhenDisabled
|
||||||
|
disabled={ isUpdateDisabled }
|
||||||
|
__next40pxDefaultSize
|
||||||
|
>
|
||||||
|
{ __( 'Update', 'woocommerce' ) }
|
||||||
|
</Button>
|
||||||
|
</FlexItem>
|
||||||
|
</VStack>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
</NavigableRegion>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
.edit-product-page {
|
||||||
|
padding: $grid-unit-30;
|
||||||
|
background: #fff;
|
||||||
|
color: #2f2f2f;
|
||||||
|
container: edit-site-page/inline-size;
|
||||||
|
height: 100%;
|
||||||
|
transition: width .2s ease-out;
|
||||||
|
|
||||||
|
.edit-product-content {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-empty .edit-product-content {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { createElement, Fragment } from '@wordpress/element';
|
||||||
|
import { Product } from '@woocommerce/data';
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { Field } from '@wordpress/dataviews';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { OPERATOR_IS } from '../constants';
|
||||||
|
|
||||||
|
const STATUSES = [
|
||||||
|
{ value: 'draft', label: __( 'Draft', 'woocommerce' ) },
|
||||||
|
{ value: 'future', label: __( 'Scheduled', 'woocommerce' ) },
|
||||||
|
{ value: 'private', label: __( 'Private', 'woocommerce' ) },
|
||||||
|
{ value: 'publish', label: __( 'Published', 'woocommerce' ) },
|
||||||
|
{ value: 'trash', label: __( 'Trash', 'woocommerce' ) },
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: auto convert some of the product editor blocks ( from the blocks directory ) to this format.
|
||||||
|
* The edit function should work relatively well with the edit from the blocks, the only difference is that the blocks rely on getEntityProp to get the value
|
||||||
|
*/
|
||||||
|
export const productFields: Field< Product >[] = [
|
||||||
|
{
|
||||||
|
id: 'name',
|
||||||
|
label: __( 'Name', 'woocommerce' ),
|
||||||
|
enableHiding: false,
|
||||||
|
type: 'text',
|
||||||
|
render: function nameRender( { item }: { item: Product } ) {
|
||||||
|
return <>{ item.name }</>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'sku',
|
||||||
|
label: __( 'SKU', 'woocommerce' ),
|
||||||
|
enableHiding: false,
|
||||||
|
enableSorting: false,
|
||||||
|
render: ( { item }: { item: Product } ) => {
|
||||||
|
return <>{ item.sku }</>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'date',
|
||||||
|
label: __( 'Date', 'woocommerce' ),
|
||||||
|
render: ( { item }: { item: Product } ) => {
|
||||||
|
return <time>{ item.date_created }</time>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __( 'Status', 'woocommerce' ),
|
||||||
|
id: 'status',
|
||||||
|
getValue: ( { item }: { item: Product } ) =>
|
||||||
|
STATUSES.find( ( { value } ) => value === item.status )?.label ??
|
||||||
|
item.status,
|
||||||
|
elements: STATUSES,
|
||||||
|
filterBy: {
|
||||||
|
operators: [ OPERATOR_IS ],
|
||||||
|
},
|
||||||
|
enableSorting: false,
|
||||||
|
},
|
||||||
|
];
|
|
@ -1,17 +1,19 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { Action, DataViews, View } from '@wordpress/dataviews';
|
import { DataViews, View } from '@wordpress/dataviews';
|
||||||
import {
|
import {
|
||||||
createElement,
|
createElement,
|
||||||
useState,
|
useState,
|
||||||
useMemo,
|
useMemo,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
|
Fragment,
|
||||||
} from '@wordpress/element';
|
} from '@wordpress/element';
|
||||||
import { Product, ProductQuery } from '@woocommerce/data';
|
import { Product, ProductQuery } from '@woocommerce/data';
|
||||||
import { drawerRight } from '@wordpress/icons';
|
import { drawerRight } from '@wordpress/icons';
|
||||||
import { privateApis as routerPrivateApis } from '@wordpress/router';
|
import { privateApis as routerPrivateApis } from '@wordpress/router';
|
||||||
|
import { store as coreStore } from '@wordpress/core-data';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { useSelect } from '@wordpress/data';
|
import { useSelect } from '@wordpress/data';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
@ -39,63 +41,13 @@ import {
|
||||||
useDefaultViews,
|
useDefaultViews,
|
||||||
defaultLayouts,
|
defaultLayouts,
|
||||||
} from '../sidebar-dataviews/default-views';
|
} from '../sidebar-dataviews/default-views';
|
||||||
import { LAYOUT_LIST, OPERATOR_IS } from '../constants';
|
import { LAYOUT_LIST } from '../constants';
|
||||||
|
import { productFields } from './fields';
|
||||||
|
import { useEditProductAction } from '../dataviews-actions';
|
||||||
|
|
||||||
const { NavigableRegion } = unlock( editorPrivateApis );
|
const { NavigableRegion, usePostActions } = unlock( editorPrivateApis );
|
||||||
const { useHistory, useLocation } = unlock( routerPrivateApis );
|
const { useHistory, useLocation } = unlock( routerPrivateApis );
|
||||||
|
|
||||||
const STATUSES = [
|
|
||||||
{ value: 'draft', label: __( 'Draft', 'woocommerce' ) },
|
|
||||||
{ value: 'future', label: __( 'Scheduled', 'woocommerce' ) },
|
|
||||||
{ value: 'private', label: __( 'Private', 'woocommerce' ) },
|
|
||||||
{ value: 'publish', label: __( 'Published', 'woocommerce' ) },
|
|
||||||
{ value: 'trash', label: __( 'Trash', 'woocommerce' ) },
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: auto convert some of the product editor blocks ( from the blocks directory ) to this format.
|
|
||||||
* The edit function should work relatively well with the edit from the blocks, the only difference is that the blocks rely on getEntityProp to get the value
|
|
||||||
*/
|
|
||||||
const fields = [
|
|
||||||
{
|
|
||||||
id: 'name',
|
|
||||||
label: __( 'Name', 'woocommerce' ),
|
|
||||||
enableHiding: false,
|
|
||||||
type: 'text',
|
|
||||||
render: function nameRender( { item }: { item: Product } ) {
|
|
||||||
return item.name;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'sku',
|
|
||||||
label: __( 'SKU', 'woocommerce' ),
|
|
||||||
enableHiding: false,
|
|
||||||
enableSorting: false,
|
|
||||||
render: ( { item }: { item: Product } ) => {
|
|
||||||
return item.sku;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'date',
|
|
||||||
label: __( 'Date', 'woocommerce' ),
|
|
||||||
render: ( { item }: { item: Product } ) => {
|
|
||||||
return <time>{ item.date_created }</time>;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __( 'Status', 'woocommerce' ),
|
|
||||||
id: 'status',
|
|
||||||
getValue: ( { item }: { item: Product } ) =>
|
|
||||||
STATUSES.find( ( { value } ) => value === item.status )?.label ??
|
|
||||||
item.status,
|
|
||||||
elements: STATUSES,
|
|
||||||
filterBy: {
|
|
||||||
operators: [ OPERATOR_IS ],
|
|
||||||
},
|
|
||||||
enableSorting: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export type ProductListProps = {
|
export type ProductListProps = {
|
||||||
subTitle?: string;
|
subTitle?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
@ -105,7 +57,6 @@ export type ProductListProps = {
|
||||||
|
|
||||||
const PAGE_SIZE = 25;
|
const PAGE_SIZE = 25;
|
||||||
const EMPTY_ARRAY: Product[] = [];
|
const EMPTY_ARRAY: Product[] = [];
|
||||||
const EMPTY_ACTIONS_ARRAY: Action< Product >[] = [];
|
|
||||||
|
|
||||||
const getDefaultView = (
|
const getDefaultView = (
|
||||||
defaultViews: Array< { slug: string; view: View } >,
|
defaultViews: Array< { slug: string; view: View } >,
|
||||||
|
@ -265,6 +216,33 @@ export default function ProductList( {
|
||||||
[ totalCount, view.perPage ]
|
[ totalCount, view.perPage ]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { labels, canCreateRecord } = useSelect(
|
||||||
|
( select ) => {
|
||||||
|
const { getPostType, canUser } = select( coreStore );
|
||||||
|
const postTypeData:
|
||||||
|
| { labels: Record< string, string > }
|
||||||
|
| undefined = getPostType( postType );
|
||||||
|
return {
|
||||||
|
labels: postTypeData?.labels,
|
||||||
|
canCreateRecord: canUser( 'create', {
|
||||||
|
kind: 'postType',
|
||||||
|
name: postType,
|
||||||
|
} ),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ postType ]
|
||||||
|
);
|
||||||
|
|
||||||
|
const postTypeActions = usePostActions( {
|
||||||
|
postType,
|
||||||
|
context: 'list',
|
||||||
|
} );
|
||||||
|
const editAction = useEditProductAction( { postType } );
|
||||||
|
const actions = useMemo(
|
||||||
|
() => [ editAction, ...postTypeActions ],
|
||||||
|
[ postTypeActions, editAction ]
|
||||||
|
);
|
||||||
|
|
||||||
const classes = classNames( 'edit-site-page', className );
|
const classes = classNames( 'edit-site-page', className );
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -290,7 +268,18 @@ export default function ProductList( {
|
||||||
{ __( 'Products', 'woocommerce' ) }
|
{ __( 'Products', 'woocommerce' ) }
|
||||||
</Heading>
|
</Heading>
|
||||||
<FlexItem className="edit-site-page-header__actions">
|
<FlexItem className="edit-site-page-header__actions">
|
||||||
{ /* { actions } */ }
|
{ labels?.add_new_item && canCreateRecord && (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
disabled={ true }
|
||||||
|
// @ts-expect-error missing type.
|
||||||
|
__next40pxDefaultSize
|
||||||
|
>
|
||||||
|
{ labels.add_new_item }
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
) }
|
||||||
</FlexItem>
|
</FlexItem>
|
||||||
</HStack>
|
</HStack>
|
||||||
{ subTitle && (
|
{ subTitle && (
|
||||||
|
@ -307,12 +296,11 @@ export default function ProductList( {
|
||||||
<DataViews
|
<DataViews
|
||||||
key={ activeView + isCustom }
|
key={ activeView + isCustom }
|
||||||
paginationInfo={ paginationInfo }
|
paginationInfo={ paginationInfo }
|
||||||
// @ts-expect-error types seem rather strict for this still.
|
fields={ productFields }
|
||||||
fields={ fields }
|
|
||||||
actions={ EMPTY_ACTIONS_ARRAY }
|
|
||||||
data={ records || EMPTY_ARRAY }
|
data={ records || EMPTY_ARRAY }
|
||||||
isLoading={ isLoading }
|
isLoading={ isLoading }
|
||||||
view={ view }
|
view={ view }
|
||||||
|
actions={ actions }
|
||||||
onChangeView={ setView }
|
onChangeView={ setView }
|
||||||
onChangeSelection={ onChangeSelection }
|
onChangeSelection={ onChangeSelection }
|
||||||
getItemId={ getItemId }
|
getItemId={ getItemId }
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { privateApis as routerPrivateApis } from '@wordpress/router';
|
||||||
*/
|
*/
|
||||||
import { unlock } from '../lock-unlock';
|
import { unlock } from '../lock-unlock';
|
||||||
import ProductList from './product-list';
|
import ProductList from './product-list';
|
||||||
|
import ProductEdit from './product-edit';
|
||||||
import DataViewsSidebarContent from './sidebar-dataviews';
|
import DataViewsSidebarContent from './sidebar-dataviews';
|
||||||
import SidebarNavigationScreen from './sidebar-navigation-screen';
|
import SidebarNavigationScreen from './sidebar-navigation-screen';
|
||||||
|
|
||||||
|
@ -32,7 +33,13 @@ export type Route = {
|
||||||
|
|
||||||
export default function useLayoutAreas() {
|
export default function useLayoutAreas() {
|
||||||
const { params = {} } = useLocation();
|
const { params = {} } = useLocation();
|
||||||
const { postType = 'product', layout = 'table', canvas } = params;
|
const {
|
||||||
|
postType = 'product',
|
||||||
|
layout = 'table',
|
||||||
|
canvas,
|
||||||
|
quickEdit: showQuickEdit,
|
||||||
|
postId,
|
||||||
|
} = params;
|
||||||
// Products list.
|
// Products list.
|
||||||
if ( [ 'product' ].includes( postType ) ) {
|
if ( [ 'product' ].includes( postType ) ) {
|
||||||
const isListLayout = layout === 'list' || ! layout;
|
const isListLayout = layout === 'list' || ! layout;
|
||||||
|
@ -49,9 +56,13 @@ export default function useLayoutAreas() {
|
||||||
content: <ProductList />,
|
content: <ProductList />,
|
||||||
preview: false,
|
preview: false,
|
||||||
mobile: <ProductList postType={ postType } />,
|
mobile: <ProductList postType={ postType } />,
|
||||||
|
edit: showQuickEdit && (
|
||||||
|
<ProductEdit postType={ postType } postId={ postId } />
|
||||||
|
),
|
||||||
},
|
},
|
||||||
widths: {
|
widths: {
|
||||||
content: isListLayout ? 380 : undefined,
|
content: isListLayout ? 380 : undefined,
|
||||||
|
edit: showQuickEdit && ! isListLayout ? 380 : undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,3 +41,4 @@ body.js.is-fullscreen-mode {
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "products-app/sidebar-dataviews/style.scss";
|
@import "products-app/sidebar-dataviews/style.scss";
|
||||||
|
@import "products-app/product-edit/style.scss";
|
||||||
|
|
Loading…
Reference in New Issue