Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@wordpress/dataviews
Advanced tools
DataViews is a component that provides an API to render datasets using different types of layouts (table, grid, list, etc.).
@wordpress/dataviews
packageThe DataViews package offers two React components and a few utilities to work with a list of data:
DataViews
: to render the dataset using different types of layouts (table, grid, list) and interaction capabilities (search, filters, sorting, etc.).DataForm
: to edit the items of the dataset.Install the module
npm install @wordpress/dataviews --save
DataViews
Important note If you're trying to use the DataViews
component in a WordPress plugin or theme and you're building your scripts using the @wordpress/scripts
package, you need to import the components from @wordpress/dataviews/wp
instead of @wordpress/dataviews
.
The DataViews
component receives data and some other configuration to render the dataset. It'll call the onChangeView
callback every time the user has interacted with the dataset in some way (sorted, filtered, changed layout, etc.):
Example:
const Example = () => {
const onChangeView = () => { /* React to user changes. */ }
return (
<DataViews
data={ data }
fields={ fields }
view={ view }
onChangeView={ onChangeView }
defaultLayouts={ defaultLayouts }
actions={ actions }
paginationInfo={ paginationInfo }
/>
);
};
data
: Object[]
A one-dimensional array of objects.
Example:
const data = [
{
id: 1,
title: 'Title',
author: 'Admin',
date: '2012-04-23T18:25:43.511Z',
},
{
/* ... */
},
];
The data can come from anywhere, from a static JSON file to a dynamic source like an HTTP Request. It's the consumer's responsibility to query the data source appropriately and update the dataset based on the user's choices for sorting, filtering, etc.
Each record should have an id
that identifies them uniquely. If they don't, the consumer should provide the getItemId
property to DataViews
: a function that returns an unique identifier for the record.
getItemId
: function
A function that receives an item and returns a unique identifier for it.
It's optional. The field will get a default implementation by DataViews
that returns the value of the item[ id ]
.
Example:
// Custom getItemId function.
{
getItemId={ ( item ) => item.name ?? item.id }
}
fields
: Object[]
The fields describe the visible items for each record in the dataset and how they behave (how to sort them, display them, etc.). See "Fields API" for a description of every property.
Example:
const STATUSES = [
{ value: 'draft', label: __( 'Draft' ) },
{ value: 'future', label: __( 'Scheduled' ) },
{ value: 'pending', label: __( 'Pending Review' ) },
{ value: 'private', label: __( 'Private' ) },
{ value: 'publish', label: __( 'Published' ) },
{ value: 'trash', label: __( 'Trash' ) },
];
const fields = [
{
id: 'title',
label: 'Title',
enableHiding: false,
},
{
id: 'date',
label: 'Date',
render: ( { item } ) => {
return <time>{ getFormattedDate( item.date ) }</time>;
},
},
{
id: 'author',
label: 'Author',
render: ( { item } ) => {
return <a href="...">{ item.author }</a>;
},
elements: [
{ value: 1, label: 'Admin' },
{ value: 2, label: 'User' },
],
filterBy: {
operators: [ 'is', 'isNot' ],
},
enableSorting: false,
},
{
id: 'status',
label: 'Status',
getValue: ( { item } ) =>
STATUSES.find( ( { value } ) => value === item.status )?.label ??
item.status,
elements: STATUSES,
filterBy: {
operators: [ 'isAny' ],
},
enableSorting: false,
},
];
view
: Object
The view object configures how the dataset is visible to the user.
Example:
const view = {
type: 'table',
search: '',
filters: [
{ field: 'author', operator: 'is', value: 2 },
{ field: 'status', operator: 'isAny', value: [ 'publish', 'draft' ] },
],
page: 1,
perPage: 5,
sort: {
field: 'date',
direction: 'desc',
},
titleField: 'title',
fields: [ 'author', 'status' ],
layout: {},
};
Properties:
type
: view type, one of table
, grid
, list
. See "Layout types".
search
: the text search applied to the dataset.
filters
: the filters applied to the dataset. Each item describes:
field
: which field this filter is bound to.operator
: which type of filter it is. See "Operator types".value
: the actual value selected by the user.perPage
: number of records to show per page.
page
: the page that is visible.
sort
:
field
: the field used for sorting the dataset.direction
: the direction to use for sorting, one of asc
or desc
.titleField
: The id of the field representing the title of the record.
mediaField
: The id of the field representing the media of the record.
descriptionField
: The id of the field representing the description of the record.
showTitle
: Whether the title should be shown in the UI. true
by default.
showMedia
: Whether the media should be shown in the UI. true
by default.
showDescription
: Whether the description should be shown in the UI. true
by default.
fields
: a list of remaining field id
that are visible in the UI and the specific order in which they are displayed.
layout
: config that is specific to a particular layout type.
layout
Properties of layout | Table | Grid | List |
---|---|---|---|
badgeFields : a list of field's id to render without label and styled as badges. | ✓ | ||
styles : additional width , maxWidth , minWidth styles for each field column. | ✓ |
onChangeView
: function
Callback executed when the view has changed. It receives the new view object as a parameter.
The view is a representation of the visible state of the dataset: what type of layout is used to display it (table, grid, etc.), how the dataset is filtered, and how it is sorted or paginated. The consumer is responsible for using the view config to query the data provider and ensure the user decisions (sort, pagination, filters, etc.) are respected.
The following example shows how a view object is used to query the WordPress REST API via the entities abstraction. The same can be done with any other data provider.
function MyCustomPageTable() {
const [ view, setView ] = useState( {
type: 'table',
perPage: 5,
page: 1,
sort: {
field: 'date',
direction: 'desc',
},
search: '',
filters: [
{ field: 'author', operator: 'is', value: 2 },
{
field: 'status',
operator: 'isAny',
value: [ 'publish', 'draft' ],
},
],
titleField: 'title',
fields: [ 'author', 'status' ],
layout: {},
} );
const queryArgs = useMemo( () => {
const filters = {};
view.filters.forEach( ( filter ) => {
if ( filter.field === 'status' && filter.operator === 'isAny' ) {
filters.status = filter.value;
}
if ( filter.field === 'author' && filter.operator === 'is' ) {
filters.author = filter.value;
}
} );
return {
per_page: view.perPage,
page: view.page,
_embed: 'author',
order: view.sort?.direction,
orderby: view.sort?.field,
search: view.search,
...filters,
};
}, [ view ] );
const { records } = useEntityRecords( 'postType', 'page', queryArgs );
return (
<DataViews
data={ records }
view={ view }
onChangeView={ setView }
// ...
/>
);
}
actions
: Object[]
A list of actions that can be performed on the dataset. See "Actions API" for more details.
Example:
const actions = [
{
id: 'view',
label: 'View',
isPrimary: true,
icon: <Icon icon={ view } />,
isEligible: ( item ) => item.status === 'published'
callback: ( items ) => {
console.log( 'Viewing item:', items[0] );
},
},
{
id: 'edit',
label: 'Edit',
icon: <Icon icon={ edit } />,
supportsBulk: true,
callback: ( items ) => {
console.log( 'Editing items:', items );
}
},
{
id: 'delete',
label: 'Delete',
isDestructive: true,
supportsBulk: true,
RenderModal: ( { items, closeModal, onActionPerformed } ) => (
<div>
<p>Are you sure you want to delete { items.length } item(s)?</p>
<Button
variant="primary"
onClick={() => {
console.log( 'Deleting items:', items );
onActionPerformed();
closeModal();
}}
>
Confirm Delete
</Button>
</div>
)
}
];
paginationInfo
: Object
totalItems
: the total number of items in the datasets.totalPages
: the total number of pages, taking into account the total items in the dataset and the number of items per page provided by the user.search
: boolean
Whether the search input is enabled. true
by default.
searchLabel
: string
What text to show in the search input. "Search" by default.
isLoading
: boolean
Whether the data is loading. false
by default.
defaultLayouts
: Record< string, view >
This property provides layout information about active view types. If empty, this enables all layout types (see "Layout Types") with empty layout data.
For example, this is how you'd enable only the table view type:
const defaultLayouts = {
table: {
showMedia: false,
},
grid: {
showMedia: true,
}
};
The defaultLayouts
property should be an object that includes properties named table
, grid
, or list
. These properties are applied to the view object each time the user switches to the corresponding layout.
selection
: string[]
The list of selected items' ids.
If selection
and onChangeSelection
are provided, the DataViews
component behaves like a controlled component. Otherwise, it behaves like an uncontrolled component.
onChangeSelection
: function
Callback that signals the user selected one of more items. It receives the list of selected items' IDs as a parameter.
If selection
and onChangeSelection
are provided, the DataViews
component behaves like a controlled component. Otherwise, it behaves like an uncontrolled component.
isItemClickable
: function
A function that determines if a media field or a primary field is clickable. It receives an item as an argument and returns a boolean value indicating whether the item can be clicked.
onClickItem
: function
A callback function that is triggered when a user clicks on a media field or primary field. This function is currently implemented only in the grid
and list
views.
header
: React componentReact component to be rendered next to the view config button.
DataForm
const Example = () => {
// Declare data, fields, etc.
return (
<DataForm
data={ data }
fields={ fields }
form={ form }
onChange={ onChange }
/>
)
}
data
: Object
A single item to be edited.
It can be thought of as a single record coming from the data
property of DataViews
— though it doesn't need to be. It can be totally separated or a mix of records if your app supports bulk editing.
fields
: Object[]
The fields describe which parts of the data are visible and how they behave (how to edit them, validate them, etc.). See "Fields API" for a description of every property.
Example:
const fields = [
{
id: 'title',
type: 'text',
label: 'Title',
},
{
id: 'date',
type: 'datetime',
label: 'Date',
},
{
id: 'author',
type: 'text'
label: 'Author',
elements: [
{ value: 1, label: 'Admin' },
{ value: 2, label: 'User' },
],
},
];
form
: Object[]
type
: either regular
or panel
.fields
: a list of fields ids that should be rendered.onChange
: function
Callback function that receives an object with the edits done by the user.
Example:
const data = {
id: 1,
title: 'Title',
author: 'Admin',
date: '2012-04-23T18:25:43.511Z',
};
const onChange = ( edits ) => {
/*
* edits will contain user edits.
* For example, if the user edited the title
* edits will be:
*
* {
* title: 'New title'
* }
*
*/
};
return (
<DataForm
data={data}
fields={fields}
form={form}
onChange={onChange}
/>
);
filterSortAndPaginate
Utility to apply the view config (filters, search, sorting, and pagination) to a dataset client-side.
Parameters:
data
: the dataset, as described in the "data" property of DataViews.view
: the view config, as described in the "view" property of DataViews.fields
: the fields config, as described in the "fields" property of DataViews.Returns an object containing:
data
: the new dataset, with the view config applied.paginationInfo
: object containing the following properties:
totalItems
: total number of items for the current view config.totalPages
: total number of pages for the current view config.isItemValid
Utility is used to determine whether or not the given item's value is valid according to the current fields and form configuration.
Parameters:
item
: the item, as described in the "data" property of DataForm.fields
: the fields config, as described in the "fields" property of DataForm.form
: the form config, as described in the "form" property of DataForm.Returns a boolean indicating if the item is valid (true) or not (false).
id
The unique identifier of the action.
string
move-to-trash
label
The user facing description of the action.
string | function
{
label: Move to Trash
}
or
{
label: ( items ) => items.length > 1 ? 'Delete items' : 'Delete item'
}
isPrimary
Whether the action should be displayed inline (primary) or only displayed in the "More actions" menu (secondary).
boolean
icon
Icon to show for primary actions.
isEligible
Function that determines whether the action can be performed for a given record.
function
{
isEligible: ( item ) => item.status === 'published'
}
isDestructive
Whether the action can delete data, in which case the UI communicates it via a red color.
boolean
supportsBulk
Whether the action can operate over multiple items at once.
boolean
false
disabled
Whether the action is disabled.
boolean
false
context
Where this action would be visible.
string
list
, single
callback
Function that performs the required action.
function
callback
or RenderModal
must be provided. If RenderModal
is provided, callback
will be ignored{
callback: ( items, { onActionPerformed } ) => {
// Perform action.
onActionPerformed?.( items );
}
}
RenderModal
Component to render UI in a modal for the action.
ReactElement
callback
or RenderModal
must be provided. If RenderModal
is provided, callback
will be ignored.{
RenderModal: ( { items, closeModal, onActionPerformed } ) => {
const onSubmit = ( event ) => {
event.preventDefault();
// Perform action.
closeModal?.();
onActionPerformed?.( items );
};
return (
<form onSubmit={ onSubmit }>
<p>Modal UI</p>
<HStack>
<Button variant="tertiary" onClick={ closeModal }>
Cancel
</Button>
<Button variant="primary" type="submit">
Submit
</Button>
</HStack>
</form>
);
}
}
hideModalHeader
Controls visibility of the modal's header when using RenderModal
.
boolean
RenderModal
, the action's label is used in modal headermodalHeader
The header text to show in the modal.
string
id
The unique identifier of the field.
string
.Example:
{ id: 'field_id' }
type
Field type. One of text
, integer
, datetime
.
If a field declares a type
, it gets default implementations for the sort
, isValid
, and Edit
functions if no other values are specified.
string
.Example:
{ type: 'text' }
label
The field's name. This will be used across the UI.
string
.id
value.Example:
{ label: 'Title' }
header
React component used by the layouts to display the field name — useful to add icons, etc. It's complementary to the label
property.
label
value.Example:
{
header: () => { /* Returns a react element. */ }
}
getValue
React component that returns the value of a field. This value is used to sort or filter the fields.
item[ id ]
.item
value to be processed.Example:
{
getValue: ( { item } ) => { /* The field's value. */ };
}
render
React component that renders the field. This is used by the layouts.
getValue
.item
value to be processed.Example:
{
render: ( { item} ) => { /* React element to be displayed. */ }
}
Edit
React component that renders the control to edit the field.
string
. If it's a string, it needs to be one of text
, integer
, datetime
, radio
, select
.type
.data
: the item to be processedfield
: the field definitiononChange
: the callback with the updateshideLabelFromVision
: boolean representing if the label should be hiddenExample:
// A custom control defined by the field.
{
Edit: ( {
data,
field,
onChange,
hideLabelFromVision
} ) => {
const value = field.getValue( { item: data } );
return (
<CustomTimePicker
value={ value }
onChange={ onChange }
hideLabelFromVision
/>
);
}
}
// Use one of the core controls.
{
Edit: 'radio'
}
// Edit is optional when field's type is present.
// The field will use the default Edit function for text.
{
type: 'text'
}
// Edit can be provided even if field's type is present.
// The field will use its own custom control.
{
type: 'text',
Edit: 'radio'
}
sort
Function to sort the records.
function
.a
: the first item to compareb
: the second item to comparedirection
: either asc
(ascending) or desc
(descending)a
should come before b
a
should come after b
a
and b
are considered equalExample:
// A custom sort function defined by the field.
{
sort: ( a, b, direction ) => {
return direction === 'asc'
? a.localeCompare( b )
: b.localeCompare( a );
}
}
// If field type is provided,
// the field gets a default sort function.
{
type: 'number'
}
// Even if a field type is provided,
// fields can override the default sort function assigned for that type.
{
type: 'number'
sort: ( a, b, direction ) => { /* Custom sort */ }
}
isValid
Function to validate a field's value.
item
: the data to validatecontext
: an object containing the following props:
elements
: the elements defined by the fieldExample:
// Custom isValid function.
{
isValid: ( item, context ) => {
return !! item;
}
}
// If the field defines a type,
// it'll get a default isValid function for the type.
{
type: 'number',
}
// Even if the field provides a type,
// the field can override the default isValid function.
{
type: 'number',
isValid: ( item, context ) => { /* Custom function. */ }
}
isVisible
Function that indicates if the field should be visible.
function
.item
: the data to be processedboolean
indicating if the field should be visible (true
) or not (false
).Example:
// Custom isVisible function.
{
isVisible: ( item ) => { /* Custom implementation. */ }
}
enableSorting
Boolean indicating if the field is sortable.
boolean
.true
.Example:
{ enableSorting: true }
enableHiding
Boolean indicating if the field can be hidden.
boolean
.true
.Example:
{ enableHiding: true }
enableGlobalSearch
Boolean indicating if the field is searchable.
boolean
.false
.Example:
{ enableGlobalSearch: true }
elements
List of valid values for a field. If provided, it creates a DataViews' filter for the field. DataForm's edit control will also use these values. (See Edit
field property.)
array
of objects.value
: the value to match against the field's value. (Required)label
: the name to display to users. (Required)description
: optional, a longer description of the item.Example:
{
elements: [
{ value: '1', label: 'Product A' },
{ value: '2', label: 'Product B' },
{ value: '3', label: 'Product C' },
{ value: '4', label: 'Product D' },
]
}
filterBy
Configuration of the filters.
object
.operators
: the list of operators supported by the field. See "operators" below. A filter will support the isAny
and isNone
multi-selection operators by default.isPrimary
: boolean, optional. Indicates if the filter is primary. A primary filter is always visible and is not listed in the "Add filter" component, except for the list layout where it behaves like a secondary filter.Operators:
Operator | Selection | Description | Example |
---|---|---|---|
is | Single item | EQUAL TO . The item's field is equal to a single value. | Author is Admin |
isNot | Single item | NOT EQUAL TO . The item's field is not equal to a single value. | Author is not Admin |
isAny | Multiple items | OR . The item's field is present in a list of values. | Author is any: Admin, Editor |
isNone | Multiple items | NOT OR . The item's field is not present in a list of values. | Author is none: Admin, Editor |
isAll | Multiple items | AND . The item's field has all of the values in the list. | Category is all: Book, Review, Science Fiction |
isNotAll | Multiple items | NOT AND . The item's field doesn't have all of the values in the list. | Category is not all: Book, Review, Science Fiction |
is
and isNot
are single-selection operators, while isAny
, isNone
, isAll
, and isNotALl
are multi-selection. A filter with no operators declared will support the isAny
and isNone
multi-selection operators by default. A filter cannot mix single-selection & multi-selection operators; if a single-selection operator is present in the list of valid operators, the multi-selection ones will be discarded, and the filter won't allow selecting more than one item.
Example:
// Set a filter as primary.
{
filterBy: {
isPrimary: true
}
}
// Configure a filter as single-selection.
{
filterBy: {
operators: [ `is`, `isNot` ]
}
}
// Configure a filter as multi-selection with all the options.
{
filterBy: {
operators: [ `isAny`, `isNone`, `isAll`, `isNotAll` ]
}
}
This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to npm and used by WordPress as well as other software projects.
To find out more about contributing to this package or Gutenberg as a whole, please read the project's main contributor guide.
FAQs
DataViews is a component that provides an API to render datasets using different types of layouts (table, grid, list, etc.).
The npm package @wordpress/dataviews receives a total of 19,196 weekly downloads. As such, @wordpress/dataviews popularity was classified as popular.
We found that @wordpress/dataviews demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.