From 84e23d2eb88bc9ad2ec7a292ebcabba5d5b88f0f Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Mon, 21 Oct 2024 14:12:37 -0300 Subject: [PATCH 01/15] Connected DataViews to /plugins/manage --- client/my-sites/plugins/main.jsx | 8 + .../my-sites/plugins/plugins-list/index.jsx | 50 +--- .../plugins-list/plugins-list-dataviews.tsx | 253 ++++++++++++++++++ .../my-sites/plugins/plugins-list/style.scss | 29 ++ 4 files changed, 300 insertions(+), 40 deletions(-) create mode 100644 client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx diff --git a/client/my-sites/plugins/main.jsx b/client/my-sites/plugins/main.jsx index 50a0621034ddec..18c4403ec8fb6f 100644 --- a/client/my-sites/plugins/main.jsx +++ b/client/my-sites/plugins/main.jsx @@ -385,6 +385,10 @@ export class PluginsMain extends Component { searchTerm={ search } filter={ this.props.filter } requestPluginsError={ this.props.requestPluginsError } + pluginsWithUpdates={ this.props.pluginsWithUpdates } + activePlugins={ this.props.activePlugins } + inactivePlugins={ this.props.inactivePlugins } + onSearch={ this.props.doSearch } /> ); @@ -585,6 +589,8 @@ export default flow( const visibleSiteIds = siteObjectsToSiteIds( getVisibleSites( sites ) ) ?? []; const siteIds = siteObjectsToSiteIds( sites ) ?? []; const pluginsWithUpdates = getPlugins( state, siteIds, 'updates' ); + const activePlugins = getPlugins( state, siteIds, 'active' ); + const inactivePlugins = getPlugins( state, siteIds, 'inactive' ); const allPlugins = getPlugins( state, siteIds, 'all' ); const jetpackNonAtomic = isJetpackSite( state, selectedSiteId ) && ! isAtomicSite( state, selectedSiteId ); @@ -614,6 +620,8 @@ export default flow( currentPluginsOnVisibleSites: getPlugins( state, visibleSiteIds, filter ), pluginUpdateCount: pluginsWithUpdates && pluginsWithUpdates.length, pluginsWithUpdates, + activePlugins, + inactivePlugins, allPluginsCount: allPlugins && allPlugins.length, requestingPluginsForSites: isRequestingForSites( state, siteIds ) || isRequestingForAllSites( state ), diff --git a/client/my-sites/plugins/plugins-list/index.jsx b/client/my-sites/plugins/plugins-list/index.jsx index fce41641e48c71..cfcc3f34daea7b 100644 --- a/client/my-sites/plugins/plugins-list/index.jsx +++ b/client/my-sites/plugins/plugins-list/index.jsx @@ -5,8 +5,6 @@ import { isEqual, reduce } from 'lodash'; import PropTypes from 'prop-types'; import { Component } from 'react'; import { connect } from 'react-redux'; -import QueryProductsList from 'calypso/components/data/query-products-list'; -import PluginsListHeader from 'calypso/my-sites/plugins/plugin-list-header'; import { recordGoogleEvent } from 'calypso/state/analytics/actions'; import { warningNotice } from 'calypso/state/notices/actions'; import { @@ -29,8 +27,8 @@ import { isJetpackSite } from 'calypso/state/sites/selectors'; import { getSelectedSite, getSelectedSiteSlug } from 'calypso/state/ui/selectors'; import { PluginActions } from '../hooks/types'; import { withShowPluginActionDialog } from '../hooks/use-show-plugin-action-dialog'; -import PluginManagementV2 from '../plugin-management-v2'; import { handleUpdatePlugins } from '../utils'; +import PluginsListDataViews from './plugins-list-dataviews'; import './style.scss'; @@ -64,6 +62,8 @@ export class PluginsList extends Component { selectedSiteSlug: PropTypes.string, siteIsAtomic: PropTypes.bool, siteIsJetpack: PropTypes.bool, + pluginsWithUpdates: PropTypes.array, + onSearch: PropTypes.func.isRequired, }; static defaultProps = { @@ -413,43 +413,13 @@ export class PluginsList extends Component { return (
- - this.removePluginDialog() } - setSelectionState={ this.setBulkSelectionState } - activatePluginNotice={ () => this.bulkActionDialog( PluginActions.ACTIVATE ) } - deactivatePluginNotice={ () => this.bulkActionDialog( PluginActions.DEACTIVATE ) } - autoupdateEnablePluginNotice={ () => - this.bulkActionDialog( PluginActions.ENABLE_AUTOUPDATES ) - } - autoupdateDisablePluginNotice={ () => - this.bulkActionDialog( PluginActions.DISABLE_AUTOUPDATES ) - } - updatePluginNotice={ () => this.bulkActionDialog( PluginActions.UPDATE ) } - isJetpackCloud={ this.props.isJetpackCloud } - /> -
); diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx new file mode 100644 index 00000000000000..af899fad742383 --- /dev/null +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -0,0 +1,253 @@ +import { Button } from '@wordpress/components'; +import { filterSortAndPaginate } from '@wordpress/dataviews'; +import { Icon, link, linkOff, plugins, trash } from '@wordpress/icons'; +import { useTranslate } from 'i18n-calypso'; +import { find } from 'lodash'; +import { useEffect, useMemo, useState } from 'react'; +import ItemsDataViews from 'calypso/a8c-for-agencies/components/items-dashboard/items-dataviews'; +import { navigate } from 'calypso/lib/navigate'; + +import './style.scss'; + +interface Props { + currentPlugins: Array; + initialSearch?: string; + pluginsWithUpdates: Array; + activePlugins: Array; + inactivePlugins: Array; + onSearch?: ( search: string ) => void; +} + +export const PLUGINS_STATUS = { + ACTIVE: 1, + INACTIVE: 2, + UPDATE: 3, +}; + +export default function PluginsListDataViews( { + currentPlugins, + initialSearch, + pluginsWithUpdates, + activePlugins, + inactivePlugins, + onSearch, +}: Props ) { + // return <>something; + + // Add flags for plugins status: active, inactive, updates + // TODO: Check the best way of doind this. We can probably move this to the backend + currentPlugins.map( ( plugin ) => { + plugin.status = []; + + if ( find( pluginsWithUpdates, { slug: plugin.slug } ) ) { + plugin.status.push( PLUGINS_STATUS.UPDATE ); + } + + if ( find( inactivePlugins, { slug: plugin.slug } ) ) { + plugin.status.push( PLUGINS_STATUS.INACTIVE ); + } + + if ( find( activePlugins, { slug: plugin.slug } ) ) { + plugin.status.push( PLUGINS_STATUS.ACTIVE ); + } + + return plugin; + } ); + + const translate = useTranslate(); + + const fields = useMemo( + () => [ + { + id: 'status', + label: translate( 'Status' ), + getValue: ( { item }: { item } ) => { + return item.status; + }, + render: () => null, + elements: [ + { + value: PLUGINS_STATUS.ACTIVE, + label: + translate( 'Active' ) + + ( activePlugins?.length > 0 ? ' - ' + activePlugins?.length : '' ), + }, + { + value: PLUGINS_STATUS.INACTIVE, + label: + translate( 'Inactive' ) + + ( inactivePlugins?.length > 0 ? ' - ' + inactivePlugins?.length : '' ), + }, + { + value: PLUGINS_STATUS.UPDATE, + label: + translate( 'Needs update' ) + + ( pluginsWithUpdates?.length > 0 ? ' - ' + pluginsWithUpdates?.length : '' ), + }, + ], + filterBy: { + operators: [ 'isAny' ], + isPrimary: true, + }, + enableHiding: false, + enableSorting: false, + }, + { + id: 'plugins', + label: 'Installed Plugins', + getValue: ( { item }: { item } ) => item.name, + enableGlobalSearch: true, + render: ( { item } ) => { + return ( + <> + { item.icon && } + { ! item.icon && ( + + ) } + { item.name } + + ); + }, + enableSorting: false, + }, + { + id: 'sites', + label: 'Sites', + enableHiding: false, + render: ( { item } ) => { + return { item.sites && Object.keys( item.sites ).length }; + }, + }, + { + id: 'update', + label: 'Update available', + enableHiding: false, + render: ( { item } ) => { + if ( item.status?.includes( PLUGINS_STATUS.UPDATE ) ) { + return ; + } + }, + }, + ], + [] + ); + + const pluginsPerPage = 10; + const initialDataViewsState = { + type: 'table', + search: initialSearch || '', + filters: [], + page: 1, + perPage: pluginsPerPage, + sort: { + field: 'date', + direction: 'desc', + }, + fields: [ 'plugins', 'sites', 'update' ], + layout: {}, + }; + + const actions = [ + { + href: `some-url`, + callback: ( data ) => { + data.length && navigate( '/plugins/' + data[ 0 ].slug ); + }, + label: translate( 'Manage Plugin' ), + isExternalLink: true, + isEnabled: true, + supportsBulk: false, + }, + { + href: `some-url`, + callback: ( data ) => { + console.log( 'Activate Plugin, data: ', data ); + }, + label: translate( 'Activate' ), + isExternalLink: true, + isEnabled: true, + supportsBulk: true, + icon: , + }, + { + href: `some-url`, + callback: () => { + console.log( 'Deactivate' ); + }, + label: translate( 'Deactivate' ), + isExternalLink: true, + isEnabled: true, + supportsBulk: true, + icon: , + }, + { + href: `some-url`, + callback: () => { + console.log( 'Enable Autoupdate' ); + }, + label: translate( 'Enable Autoupdate' ), + isExternalLink: true, + isEnabled: true, + supportsBulk: true, + }, + { + href: `some-url`, + callback: () => { + console.log( 'Disable Autoupdate' ); + }, + label: translate( 'Disable Autoupdate' ), + isExternalLink: true, + isEnabled: true, + supportsBulk: true, + }, + { + href: `some-url`, + callback: () => { + console.log( 'Remove' ); + }, + label: translate( 'Remove' ), + isExternalLink: true, + isEnabled: true, + supportsBulk: true, + icon: , + }, + ]; + + const [ dataViewsState, setDataViewsState ] = useState( initialDataViewsState ); + + // When search changes, notify the parent component + useEffect( () => { + onSearch && onSearch( dataViewsState.search ); + }, [ dataViewsState.search, onSearch ] ); + + const { data, paginationInfo } = useMemo( () => { + console.log( 'dataViewsState', dataViewsState ); + return filterSortAndPaginate( currentPlugins, dataViewsState, fields ); + }, [ currentPlugins, dataViewsState, fields ] ); + + return ( +
+ `${ item.id }`, + fields, + pagination: paginationInfo, + searchLabel: translate( 'Search for plugins' ), + enableSearch: true, + actions: actions, + dataViewsState: dataViewsState, + setDataViewsState: setDataViewsState, + onSelectionChange: ( items ) => { + console.log( 'items: ', items ); + }, + defaultLayouts: { table: {} }, + } } + /> +
+ ); +} diff --git a/client/my-sites/plugins/plugins-list/style.scss b/client/my-sites/plugins/plugins-list/style.scss index bfa874b6881f0c..238fbdfc254ce9 100644 --- a/client/my-sites/plugins/plugins-list/style.scss +++ b/client/my-sites/plugins/plugins-list/style.scss @@ -54,3 +54,32 @@ flex-flow: row wrap; padding: 0; } + + + + +body.is-section-plugins .plugin-management-wrapper { + + .dataviews-wrapper { + .dataviews-view-table { + border: 1px solid var(--color-neutral-5); + border-radius: 2px; + + .dataviews-view-table__row { + img, .dataviews-view-table__row svg { + max-width: 35px; + margin-right: 15px; + } + + .dataviews-view-table-selection-checkbox{ + padding-left: 0; + } + } + + .dataviews-view-table__checkbox-column { + padding-left: 18px; + } + } + } + +} From 47959d94f0d644941da9900e7fa4b7dcf6c30294 Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Mon, 21 Oct 2024 14:23:26 -0300 Subject: [PATCH 02/15] Removed unnecessary filters --- client/my-sites/plugins/main.jsx | 106 +------------------------------ 1 file changed, 3 insertions(+), 103 deletions(-) diff --git a/client/my-sites/plugins/main.jsx b/client/my-sites/plugins/main.jsx index 18c4403ec8fb6f..54460c972025c6 100644 --- a/client/my-sites/plugins/main.jsx +++ b/client/my-sites/plugins/main.jsx @@ -4,12 +4,12 @@ import { WPCOM_FEATURES_UPLOAD_PLUGINS, } from '@automattic/calypso-products/src'; import page from '@automattic/calypso-router'; -import { Button, Count } from '@automattic/components'; +import { Button } from '@automattic/components'; import { subscribeIsWithinBreakpoint, isWithinBreakpoint } from '@automattic/viewport'; import { Icon, upload } from '@wordpress/icons'; import clsx from 'clsx'; import { localize } from 'i18n-calypso'; -import { capitalize, find, flow, isEmpty } from 'lodash'; +import { capitalize, flow, isEmpty } from 'lodash'; import { Component } from 'react'; import { connect } from 'react-redux'; import DocumentHead from 'calypso/components/data/document-head'; @@ -18,10 +18,6 @@ import QueryPlugins from 'calypso/components/data/query-plugins'; import QuerySiteFeatures from 'calypso/components/data/query-site-features'; import EmptyContent from 'calypso/components/empty-content'; import NavigationHeader from 'calypso/components/navigation-header'; -import Search from 'calypso/components/search'; -import SectionNav from 'calypso/components/section-nav'; -import NavItem from 'calypso/components/section-nav/item'; -import NavTabs from 'calypso/components/section-nav/tabs'; import MissingPaymentNotification from 'calypso/jetpack-cloud/components/missing-payment-notification'; import PageViewTracker from 'calypso/lib/analytics/page-view-tracker'; import urlSearch from 'calypso/lib/url-search'; @@ -186,38 +182,6 @@ export class PluginsMain extends Component { ); } - getFilters() { - const { translate, search } = this.props; - const siteFilter = `${ this.props.selectedSiteSlug ? '/' + this.props.selectedSiteSlug : '' }${ - search ? '?s=' + search : '' - }`; - - return [ - { - title: isWithinBreakpoint( '<480px' ) - ? translate( 'All Plugins', { context: 'Filter label for plugins list' } ) - : translate( 'All', { context: 'Filter label for plugins list' } ), - path: '/plugins/manage' + siteFilter, - id: 'all', - }, - { - title: translate( 'Active', { context: 'Filter label for plugins list' } ), - path: '/plugins/active' + siteFilter, - id: 'active', - }, - { - title: translate( 'Inactive', { context: 'Filter label for plugins list' } ), - path: '/plugins/inactive' + siteFilter, - id: 'inactive', - }, - { - title: translate( 'Updates', { context: 'Filter label for plugins list' } ), - path: '/plugins/updates' + siteFilter, - id: 'updates', - }, - ]; - } - isFetchingPlugins() { return this.props.requestingPluginsForSites; } @@ -236,15 +200,6 @@ export class PluginsMain extends Component { return count; } - getSelectedText() { - const found = find( this.getFilters(), ( filterItem ) => this.props.filter === filterItem.id ); - if ( 'undefined' !== typeof found ) { - const count = this.getPluginCount( found.id ); - return { title: found.title, count }; - } - return ''; - } - getEmptyContentUpdateData() { const { translate } = this.props; const emptyContentData = { illustration: '/calypso/images/illustrations/illustration-ok.svg' }; @@ -436,21 +391,6 @@ export class PluginsMain extends Component { return ; } - const navItems = this.getFilters().map( ( filterItem ) => { - if ( 'updates' === filterItem.id && ! this.getUpdatesTabVisibility() ) { - return null; - } - - const attr = { - key: filterItem.id, - path: filterItem.path, - selected: filterItem.id === this.props.filter, - count: this.getPluginCount( filterItem.id ), - }; - - return { filterItem.title }; - } ); - const { isJetpackCloud, selectedSite } = this.props; let pageTitle; @@ -460,15 +400,6 @@ export class PluginsMain extends Component { pageTitle = this.props.translate( 'Installed Plugins', { textOnly: true } ); } - const { title, count } = this.getSelectedText(); - - const selectedTextContent = ( - - { title } - { count ? : null } - - ); - const currentPlugins = this.getCurrentPlugins(); return ( @@ -532,19 +463,6 @@ export class PluginsMain extends Component { ) } -
-
- - - { navItems } - - -
-
-
- { - // Hide the search box only when the request to fetch plugins fail, and there are no sites. - ! ( this.props.requestPluginsError && ! currentPlugins?.length ) && ( -
- -
- ) - } - { this.renderPluginsContent() } -
+
{ this.renderPluginsContent() }
From 68078637322a843ba6ef1ac3099afaffa3d32327 Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Mon, 21 Oct 2024 15:08:21 -0300 Subject: [PATCH 03/15] Finished bulk actions connections --- .../my-sites/plugins/plugins-list/index.jsx | 12 ++----- .../plugins-list/plugins-list-dataviews.tsx | 31 +++++++++---------- .../my-sites/plugins/plugins-list/style.scss | 2 +- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/client/my-sites/plugins/plugins-list/index.jsx b/client/my-sites/plugins/plugins-list/index.jsx index cfcc3f34daea7b..e3a858c40ac960 100644 --- a/client/my-sites/plugins/plugins-list/index.jsx +++ b/client/my-sites/plugins/plugins-list/index.jsx @@ -232,9 +232,8 @@ export class PluginsList extends Component { } ); } - bulkActionDialog = ( actionName, selectedPlugin ) => { - const { plugins, allSites, showPluginActionDialog } = this.props; - const selectedPlugins = selectedPlugin ? [ selectedPlugin ] : plugins.filter( this.isSelected ); + bulkActionDialog = ( actionName, selectedPlugins ) => { + const { allSites, showPluginActionDialog } = this.props; const isJetpackIncluded = selectedPlugins.some( ( { slug } ) => slug === 'jetpack' ); const ALL_ACTION_CALLBACKS = { @@ -361,10 +360,6 @@ export class PluginsList extends Component { this.removePluginStatuses(); }; - removePluginDialog = ( selectedPlugin ) => { - this.bulkActionDialog( PluginActions.REMOVE, selectedPlugin ); - }; - maybeShowDisconnectNotice() { if ( ! this.state.disconnectJetpackNotice ) { return; @@ -409,8 +404,6 @@ export class PluginsList extends Component { } render() { - const selectedSiteSlug = this.props.selectedSiteSlug ? this.props.selectedSiteSlug : ''; - return (
); diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index af899fad742383..8428b17d907401 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -6,6 +6,7 @@ import { find } from 'lodash'; import { useEffect, useMemo, useState } from 'react'; import ItemsDataViews from 'calypso/a8c-for-agencies/components/items-dashboard/items-dataviews'; import { navigate } from 'calypso/lib/navigate'; +import { PluginActions } from '../hooks/types'; import './style.scss'; @@ -16,6 +17,7 @@ interface Props { activePlugins: Array; inactivePlugins: Array; onSearch?: ( search: string ) => void; + bulkActionDialog: ( action: string, plugins: Array ) => void; } export const PLUGINS_STATUS = { @@ -31,9 +33,8 @@ export default function PluginsListDataViews( { activePlugins, inactivePlugins, onSearch, + bulkActionDialog, }: Props ) { - // return <>something; - // Add flags for plugins status: active, inactive, updates // TODO: Check the best way of doind this. We can probably move this to the backend currentPlugins.map( ( plugin ) => { @@ -100,7 +101,7 @@ export default function PluginsListDataViews( { render: ( { item } ) => { return ( <> - { item.icon && } + { item.icon && { } { ! item.icon && ( { - console.log( 'Activate Plugin, data: ', data ); + callback: ( plugins ) => { + bulkActionDialog( PluginActions.ACTIVATE, plugins ); }, label: translate( 'Activate' ), isExternalLink: true, @@ -175,8 +176,8 @@ export default function PluginsListDataViews( { }, { href: `some-url`, - callback: () => { - console.log( 'Deactivate' ); + callback: ( plugins ) => { + bulkActionDialog( PluginActions.DEACTIVATE, plugins ); }, label: translate( 'Deactivate' ), isExternalLink: true, @@ -186,8 +187,8 @@ export default function PluginsListDataViews( { }, { href: `some-url`, - callback: () => { - console.log( 'Enable Autoupdate' ); + callback: ( plugins ) => { + bulkActionDialog( PluginActions.ENABLE_AUTOUPDATES, plugins ); }, label: translate( 'Enable Autoupdate' ), isExternalLink: true, @@ -196,8 +197,8 @@ export default function PluginsListDataViews( { }, { href: `some-url`, - callback: () => { - console.log( 'Disable Autoupdate' ); + callback: ( plugins ) => { + bulkActionDialog( PluginActions.DISABLE_AUTOUPDATES, plugins ); }, label: translate( 'Disable Autoupdate' ), isExternalLink: true, @@ -206,8 +207,8 @@ export default function PluginsListDataViews( { }, { href: `some-url`, - callback: () => { - console.log( 'Remove' ); + callback: ( plugins ) => { + bulkActionDialog( PluginActions.REMOVE, plugins ); }, label: translate( 'Remove' ), isExternalLink: true, @@ -225,7 +226,6 @@ export default function PluginsListDataViews( { }, [ dataViewsState.search, onSearch ] ); const { data, paginationInfo } = useMemo( () => { - console.log( 'dataViewsState', dataViewsState ); return filterSortAndPaginate( currentPlugins, dataViewsState, fields ); }, [ currentPlugins, dataViewsState, fields ] ); @@ -242,9 +242,6 @@ export default function PluginsListDataViews( { actions: actions, dataViewsState: dataViewsState, setDataViewsState: setDataViewsState, - onSelectionChange: ( items ) => { - console.log( 'items: ', items ); - }, defaultLayouts: { table: {} }, } } /> diff --git a/client/my-sites/plugins/plugins-list/style.scss b/client/my-sites/plugins/plugins-list/style.scss index 238fbdfc254ce9..12096cb0575cda 100644 --- a/client/my-sites/plugins/plugins-list/style.scss +++ b/client/my-sites/plugins/plugins-list/style.scss @@ -66,7 +66,7 @@ body.is-section-plugins .plugin-management-wrapper { border-radius: 2px; .dataviews-view-table__row { - img, .dataviews-view-table__row svg { + img, svg { max-width: 35px; margin-right: 15px; } From b991f5653f4a0a893227ff04d302b78b446ff29d Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Mon, 21 Oct 2024 15:57:56 -0300 Subject: [PATCH 04/15] Remove the unnecessary code and making sure the actions work as expected --- .../plugins/plugin-list-header/index.jsx | 397 ------------------ .../plugins/plugin-list-header/style.scss | 189 --------- .../my-sites/plugins/plugins-list/README.md | 2 +- .../my-sites/plugins/plugins-list/index.jsx | 44 +- 4 files changed, 9 insertions(+), 623 deletions(-) delete mode 100644 client/my-sites/plugins/plugin-list-header/index.jsx delete mode 100644 client/my-sites/plugins/plugin-list-header/style.scss diff --git a/client/my-sites/plugins/plugin-list-header/index.jsx b/client/my-sites/plugins/plugin-list-header/index.jsx deleted file mode 100644 index b05f070f308db5..00000000000000 --- a/client/my-sites/plugins/plugin-list-header/index.jsx +++ /dev/null @@ -1,397 +0,0 @@ -import { WPCOM_FEATURES_MANAGE_PLUGINS } from '@automattic/calypso-products'; -import { Button, Gridicon, SelectDropdown } from '@automattic/components'; -import clsx from 'clsx'; -import { localize } from 'i18n-calypso'; -import { debounce } from 'lodash'; -import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; -import { findDOMNode } from 'react-dom'; -import { connect } from 'react-redux'; -import BulkSelect from 'calypso/components/bulk-select'; -import ButtonGroup from 'calypso/components/button-group'; -import SectionHeader from 'calypso/components/section-header'; -import { gaRecordEvent } from 'calypso/lib/analytics/ga'; -import getSites from 'calypso/state/selectors/get-sites'; -import isSiteWpcomAtomic from 'calypso/state/selectors/is-site-wpcom-atomic'; -import siteHasFeature from 'calypso/state/selectors/site-has-feature'; -import { getSelectedSiteId } from 'calypso/state/ui/selectors'; -import UpdatePlugins from '../plugin-management-v2/update-plugins'; - -import './style.scss'; - -// Constants help determine if the action bar should be a dropdown -const MAX_ACTIONBAR_HEIGHT = 57; -const MIN_ACTIONBAR_WIDTH = 600; - -export class PluginsListHeader extends PureComponent { - state = { - actionBarVisible: true, - }; - - static defaultProps = { - disabled: false, - }; - - static propTypes = { - label: PropTypes.string, - hasManagePluginsFeature: PropTypes.bool, - isBulkManagementActive: PropTypes.bool, - isWpComAtomic: PropTypes.bool, - toggleBulkManagement: PropTypes.func.isRequired, - updateSelected: PropTypes.func.isRequired, - deactiveAndDisconnectSelected: PropTypes.func.isRequired, - setAutoupdateSelected: PropTypes.func.isRequired, - setSelectionState: PropTypes.func.isRequired, - unsetAutoupdateSelected: PropTypes.func.isRequired, - removePluginNotice: PropTypes.func.isRequired, - activatePluginNotice: PropTypes.func.isRequired, - deactivatePluginNotice: PropTypes.func.isRequired, - autoupdateEnablePluginNotice: PropTypes.func.isRequired, - autoupdateDisablePluginNotice: PropTypes.func.isRequired, - updatePluginNotice: PropTypes.func.isRequired, - plugins: PropTypes.array.isRequired, - selected: PropTypes.array.isRequired, - isJetpackCloud: PropTypes.bool, - }; - - componentDidMount() { - this.debouncedAfterResize = debounce( this.afterResize, 100 ); - window.addEventListener( 'resize', this.debouncedAfterResize ); - } - - componentWillUnmount() { - window.removeEventListener( 'resize', this.debouncedAfterResize ); - } - - maybeMakeActionBarVisible() { - const actionBarDomElement = findDOMNode( this ); - if ( actionBarDomElement.offsetWidth < MIN_ACTIONBAR_WIDTH ) { - return; - } - setTimeout( () => { - const actionBarVisible = actionBarDomElement.offsetHeight <= MAX_ACTIONBAR_HEIGHT; - this.setState( { actionBarVisible } ); - }, 1 ); - } - - toggleBulkManagement = () => { - this.props.toggleBulkManagement(); - - this.maybeMakeActionBarVisible(); - }; - - afterResize = () => { - if ( this.props.isBulkManagementActive ) { - this.maybeMakeActionBarVisible(); - } - }; - - unselectOrSelectAll = () => { - const { plugins, selected } = this.props; - const someSelected = selected.length > 0; - this.props.setSelectionState( plugins, ! someSelected ); - gaRecordEvent( - 'Plugins', - someSelected ? 'Clicked to Uncheck All Plugins' : 'Clicked to Check All Plugins' - ); - }; - - isJetpackSelected() { - return this.props.selected.some( ( plugin ) => 'jetpack' === plugin.slug ); - } - - hasSelectedPlugins() { - return this.props.selected.length > 0; - } - - renderCurrentActionButtons() { - const { - hasManagePluginsFeature, - isWpComAtomic, - translate, - siteId, - isJetpackCloud, - isBulkManagementActive, - plugins, - } = this.props; - const buttons = []; - - if ( siteId && isWpComAtomic && ! hasManagePluginsFeature ) { - return buttons; - } - - const isJetpackSelected = this.isJetpackSelected(); - const rightSideButtons = []; - const leftSideButtons = []; - const autoupdateButtons = []; - const activateButtons = []; - if ( ! isBulkManagementActive ) { - if ( isJetpackCloud ) { - const updateButton = ( - - ); - if ( updateButton ) { - rightSideButtons.push( updateButton ); - } - } - rightSideButtons.push( - - - - ); - } else { - const updateButton = ( - - ); - - activateButtons.push( - - ); - - activateButtons.push( - - ); - - if ( ! ( isJetpackSelected && this.props.selected.length === 1 ) ) { - leftSideButtons.push( - - { activateButtons } - - ); - } - - autoupdateButtons.push( - - ); - autoupdateButtons.push( - - ); - - leftSideButtons.push( - - { autoupdateButtons } - - ); - - leftSideButtons.push( - - { updateButton } - - ); - - leftSideButtons.push( - - - - ); - - rightSideButtons.push( - - ); - } - - buttons.push( - - { leftSideButtons } - - ); - - buttons.push( - - { rightSideButtons } - - ); - - return buttons; - } - - renderCurrentActionDropdown() { - const { translate, selected, isBulkManagementActive } = this.props; - if ( ! isBulkManagementActive ) { - return null; - } - - const isJetpackSelected = this.isJetpackSelected(); - - const isJetpackOnlySelected = ! ( isJetpackSelected && selected.length === 1 ); - return ( - - - - - { translate( 'Update Plugins' ) } - - - - { isJetpackOnlySelected && ( - - { translate( 'Activate' ) } - - ) } - { isJetpackOnlySelected && ( - - { translate( 'Deactivate' ) } - - ) } - - - - - { translate( 'Autoupdate' ) } - - - - { translate( 'Disable' ) } - - - - - { translate( 'Remove' ) } - - - ); - } - - render() { - const { label, selected, plugins, isBulkManagementActive, translate } = this.props; - const sectionClasses = clsx( 'plugin-list-header plugin-list-header-new', { - 'is-bulk-editing': isBulkManagementActive, - 'is-action-bar-visible': this.state.actionBarVisible, - } ); - return ( - - { isBulkManagementActive && ( -
- - -
- { translate( '%(number)d {{span}}Selected{{/span}}', { - args: { - number: selected.length, - }, - components: { - span: , - }, - } ) } -
-
- ) } - { this.renderCurrentActionDropdown() } - { this.renderCurrentActionButtons() } -
- ); - } -} - -export default connect( ( state ) => { - const siteId = getSelectedSiteId( state ); - - return { - siteId, - allSites: getSites( state ), - hasManagePluginsFeature: siteHasFeature( state, siteId, WPCOM_FEATURES_MANAGE_PLUGINS ), - isWpComAtomic: isSiteWpcomAtomic( state, siteId ), - }; -} )( localize( PluginsListHeader ) ); diff --git a/client/my-sites/plugins/plugin-list-header/style.scss b/client/my-sites/plugins/plugin-list-header/style.scss deleted file mode 100644 index ab35bc5ad5efa0..00000000000000 --- a/client/my-sites/plugins/plugin-list-header/style.scss +++ /dev/null @@ -1,189 +0,0 @@ -@import "@wordpress/base-styles/breakpoints"; -@import "@wordpress/base-styles/mixins"; - -.plugin-list-header.section-header.card { - .section-header__actions { - flex-grow: 1; - display: flex; - justify-content: space-between; - align-items: center; - } - - .bulk-select { - margin-right: 16px; - } - - .button-group { - margin-left: 8px; - display: inherit; - } - - &.is-placeholder { - .section-header__label span { - @include placeholder( --color-neutral-10 ); - } - } - - &.is-bulk-editing .section-header__label { - display: none; - } - - @include breakpoint-deprecated( ">660px" ) { - padding-right: 16px; - } - @include breakpoint-deprecated( ">960px" ) { - &.is-action-bar-visible { - .plugin-list-header__actions-dropdown { - display: none; - } - .plugin-list-header__action-buttons { - display: flex; - } - } - } -} - -.plugin-list-header__section-actions-close { - color: var(--color-neutral-60); - cursor: pointer; - display: flex; - align-items: center; - - &:focus { - border-color: var(--color-accent); - box-shadow: 0 0 0 2px var(--color-primary-light); - } -} - -.plugin-list-header__actions-dropdown { - display: inline-block; -} - -.plugin-list-header__actions-remove-item { - color: var(--color-error); - - &.is-disabled { - color: var(--color-error-5); - } -} - -.plugin-list-header__mode-buttons { - display: flex; - justify-content: flex-end; - flex-grow: 1; - text-align: right; -} - -.plugin-list-header__action-buttons { - align-items: center; - display: none; - flex-grow: 1; -} - -.theme-jetpack-cloud .plugin-list-header-new .bulk-select .form-checkbox { - &:checked::before { - content: url(/calypso/images/checkbox-icons/checkmark-jetpack.svg); - } -} - -.plugin-list-header-new { - height: 60px; - margin-block-start: 8px; - &.section-header.card { - align-items: center; - margin-inline-start: 0; - margin-inline-end: 0; - padding-inline-start: 16px; - padding-inline-end: 16px; - @include break-wide() { - margin-inline-start: 1px; - margin-inline-end: 1px; - } - &:not(.is-bulk-editing) { - @include break-xlarge() { - display: none; - } - } - &.is-bulk-editing { - margin-block-start: 8px; - margin-block-end: 0; - .section-header__actions { - width: 100%; - flex-wrap: wrap; - } - } - .button-group { - margin-inline-start: 14px; - .button { - &:first-child { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - } - &:last-child { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - } - } - } - .section-header__actions { - margin-inline-start: 0; - flex-grow: 0; - justify-content: end; - .bulk-select__some-checked-icon { - color: var(--color-jetpack); - } - } - } - .bulk-select { - .count { - display: none; - } - } - .plugin-list-header__bulk-select-wrapper { - display: flex; - align-items: center; - } - .plugin-list-header__bulk-select-label { - margin-inline-end: 16px; - font-size: 0.75rem; - font-weight: bold; - - span { - display: none; - @include breakpoint-deprecated( ">960px" ) { - display: inline; - } - } - } - .plugin-list-header__actions-dropdown { - margin-inline-start: auto; - } - - .plugin-list-header__mode-buttons { - flex-grow: 0; - margin-inline-start: 16px; - @include break-medium() { - margin-inline-start: 32px; - } - } - - .plugin-list-header__action-buttons { - justify-content: end; - - button.plugin-list-header__buttons-action-button { - color: var(--studio-gray-80); - } - - button { - &:disabled { - background: var(--studio-gray-5); - color: var(--studio-gray-30); - border: none; - } - - &:not(:first-child):disabled { - border-left: 1px solid var(--studio-gray-10); - } - } - } -} diff --git a/client/my-sites/plugins/plugins-list/README.md b/client/my-sites/plugins/plugins-list/README.md index aa9d689922f61b..f73717f8f4de17 100644 --- a/client/my-sites/plugins/plugins-list/README.md +++ b/client/my-sites/plugins/plugins-list/README.md @@ -1,6 +1,6 @@ # Plugins List -This component is used to represent a list `PluginItem`s, with a `PluginsListHeader` serving as a title for the whole bunch. +This component is used to represent a list `PluginItem`s using the DataViews component. ## How to use diff --git a/client/my-sites/plugins/plugins-list/index.jsx b/client/my-sites/plugins/plugins-list/index.jsx index e3a858c40ac960..21702a53e23f70 100644 --- a/client/my-sites/plugins/plugins-list/index.jsx +++ b/client/my-sites/plugins/plugins-list/index.jsx @@ -1,7 +1,7 @@ import { recordTracksEvent } from '@automattic/calypso-analytics'; import { WPCOM_FEATURES_MANAGE_PLUGINS } from '@automattic/calypso-products'; import { localize } from 'i18n-calypso'; -import { isEqual, reduce } from 'lodash'; +import { isEqual } from 'lodash'; import PropTypes from 'prop-types'; import { Component } from 'react'; import { connect } from 'react-redux'; @@ -145,21 +145,6 @@ export class PluginsList extends Component { return canAutoupdate || canActivate; } - setBulkSelectionState = ( plugins, selectionState ) => { - const slugsToBeUpdated = reduce( - plugins, - ( slugs, plugin ) => { - slugs[ plugin.slug ] = this.canBulkSelect( plugin ) && selectionState; - return slugs; - }, - {} - ); - - this.setState( { - selectedPlugins: Object.assign( {}, this.state.selectedPlugins, slugsToBeUpdated ), - } ); - }; - getSelected() { return this.props.plugins.filter( this.isSelected.bind( this ) ); } @@ -175,34 +160,17 @@ export class PluginsList extends Component { } // Actions - toggleBulkManagement = () => { - const activateBulkManagement = ! this.state.bulkManagementActive; - - if ( activateBulkManagement ) { - this.setBulkSelectionState( this.props.plugins, true ); - this.setState( { bulkManagementActive: true } ); - this.recordEvent( 'Clicked Manage' ); - } else { - this.setState( { bulkManagementActive: false } ); - this.removePluginStatuses(); - this.recordEvent( 'Clicked Manage Done' ); - } - }; - removePluginStatuses() { this.props.removePluginStatuses( 'completed', 'error', 'up-to-date' ); } - doActionOverSelected( actionName, action, selectedPlugins ) { - if ( ! selectedPlugins ) { - selectedPlugins = this.props.plugins.filter( this.isSelected ); - } - + doActionOverSelected( actionName, action ) { const isDeactivatingOrRemovingAndJetpackSelected = ( { slug } ) => [ 'deactivating', 'activating', 'removing' ].includes( actionName ) && 'jetpack' === slug; this.removePluginStatuses(); - const pluginAndSiteObjects = selectedPlugins + + const pluginAndSiteObjects = this.state.selectedPlugins .filter( ( plugin ) => ! isDeactivatingOrRemovingAndJetpackSelected( plugin ) ) // ignore sites that are deactivating, activating or removing jetpack .map( ( p ) => { return Object.keys( p.sites ).map( ( siteId ) => { @@ -233,6 +201,10 @@ export class PluginsList extends Component { } bulkActionDialog = ( actionName, selectedPlugins ) => { + this.setState( { + selectedPlugins: selectedPlugins, + } ); + const { allSites, showPluginActionDialog } = this.props; const isJetpackIncluded = selectedPlugins.some( ( { slug } ) => slug === 'jetpack' ); From d6138b07dc79a2a1b07f10535a834eb0a11926fc Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Mon, 21 Oct 2024 18:04:20 -0300 Subject: [PATCH 05/15] Add a global load state for plugin actions --- .../plugins-list/plugins-list-dataviews.tsx | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 8428b17d907401..689ee5763cb8a5 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -1,4 +1,5 @@ -import { Button } from '@wordpress/components'; +import { FoldableCard, ProgressBar } from '@automattic/components'; +import { Button, Notice } from '@wordpress/components'; import { filterSortAndPaginate } from '@wordpress/dataviews'; import { Icon, link, linkOff, plugins, trash } from '@wordpress/icons'; import { useTranslate } from 'i18n-calypso'; @@ -6,7 +7,9 @@ import { find } from 'lodash'; import { useEffect, useMemo, useState } from 'react'; import ItemsDataViews from 'calypso/a8c-for-agencies/components/items-dashboard/items-dataviews'; import { navigate } from 'calypso/lib/navigate'; +import { useSelector } from 'calypso/state'; import { PluginActions } from '../hooks/types'; +import { getPluginActionStatuses } from '../plugin-management-v2/utils/get-plugin-action-statuses'; import './style.scss'; @@ -35,6 +38,8 @@ export default function PluginsListDataViews( { onSearch, bulkActionDialog, }: Props ) { + const allStatuses = useSelector( ( state ) => getPluginActionStatuses( state ) ); + // Add flags for plugins status: active, inactive, updates // TODO: Check the best way of doind this. We can probably move this to the backend currentPlugins.map( ( plugin ) => { @@ -229,8 +234,47 @@ export default function PluginsListDataViews( { return filterSortAndPaginate( currentPlugins, dataViewsState, fields ); }, [ currentPlugins, dataViewsState, fields ] ); + const ApplyingStatus = () => { + const completed = allStatuses.filter( ( status ) => status.status === 'completed' ); + const errors = allStatuses.filter( ( status ) => status.status === 'error' ); + + if ( + allStatuses.length === 0 || + completed.length === allStatuses.length || + completed.length + errors.length === allStatuses.length + ) { + return null; + } + + const value = ( completed.length * 100 ) / allStatuses.length; + + return ( + <> +

{ translate( 'Applying modifications' ) }

+ + + + { translate( 'An error occurred while applying modifications' ) } + + + { errors.map( ( error ) => ( + <> + + { translate( 'Site: ' ) } { error.siteId } { ' - ' } + { translate( 'Error: ' ) } + { error.error.message } + +
+ + ) ) } +
+ + ); + }; + return (
+ Date: Tue, 22 Oct 2024 09:20:48 -0300 Subject: [PATCH 06/15] Removed unnecessary code --- .../my-sites/plugins/plugins-list/index.jsx | 61 +------------------ 1 file changed, 1 insertion(+), 60 deletions(-) diff --git a/client/my-sites/plugins/plugins-list/index.jsx b/client/my-sites/plugins/plugins-list/index.jsx index 21702a53e23f70..dbd48c8346b5bc 100644 --- a/client/my-sites/plugins/plugins-list/index.jsx +++ b/client/my-sites/plugins/plugins-list/index.jsx @@ -127,32 +127,10 @@ export class PluginsList extends Component { return !! this.state.selectedPlugins[ slug ]; }; - togglePlugin = ( plugin ) => { - const { slug } = plugin; - const { selectedPlugins } = this.state; - const oldValue = selectedPlugins[ slug ]; - const eventAction = - 'Clicked to ' + this.isSelected( plugin ) ? 'Deselect' : 'Select' + 'Single Plugin'; - this.setState( { - selectedPlugins: Object.assign( {}, selectedPlugins, { [ slug ]: ! oldValue } ), - } ); - this.props.recordGoogleEvent( 'Plugins', eventAction, 'Plugin Name', slug ); - }; - - canBulkSelect( plugin ) { - const { autoupdate: canAutoupdate, activation: canActivate } = - this.getAllowedPluginActions( plugin ); - return canAutoupdate || canActivate; - } - - getSelected() { - return this.props.plugins.filter( this.isSelected.bind( this ) ); - } - recordEvent( eventAction, includeSelectedPlugins ) { eventAction += this.props.selectedSite ? '' : ' on Multisite'; if ( includeSelectedPlugins ) { - const pluginSlugs = this.getSelected().map( ( plugin ) => plugin.slug ); + const pluginSlugs = this.state.selectedPlugins.map( ( plugin ) => plugin.slug ); this.props.recordGoogleEvent( 'Plugins', eventAction, 'Plugins', pluginSlugs ); } else { this.props.recordGoogleEvent( 'Plugins', eventAction ); @@ -390,43 +368,6 @@ export class PluginsList extends Component {
); } - - getPlugins() { - const plugins = this.props.plugins.map( ( plugin ) => { - const selectThisPlugin = this.togglePlugin.bind( this, plugin ); - const allowedPluginActions = this.getAllowedPluginActions( plugin ); - const isSelectable = - this.state.bulkManagementActive && - ( allowedPluginActions.autoupdate || allowedPluginActions.activation ); - - return { - ...plugin, - ...{ onClick: selectThisPlugin, isSelected: this.isSelected( plugin ), isSelectable }, - }; - } ); - - // Plugins which require an update sort first, otherwise the original order is kept. - plugins.sort( ( a, b ) => { - const updateA = !! a.update; - const updateB = !! b.update; - return Number( updateB ) - Number( updateA ); - } ); - - return plugins; - } - - getAllowedPluginActions( plugin ) { - const { hasManagePlugins, siteIsAtomic, siteIsJetpack, selectedSite } = this.props; - const autoManagedPlugins = [ 'jetpack', 'vaultpress', 'akismet' ]; - const isManagedPlugin = siteIsAtomic && autoManagedPlugins.includes( plugin.slug ); - const canManagePlugins = - ! selectedSite || ( siteIsJetpack && ! siteIsAtomic ) || ( siteIsAtomic && hasManagePlugins ); - - return { - autoupdate: ! isManagedPlugin && canManagePlugins, - activation: ! isManagedPlugin && canManagePlugins, - }; - } } export default connect( From 4aaa4fcc09965044b196c178333e555c8a3d73f4 Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Tue, 22 Oct 2024 09:53:40 -0300 Subject: [PATCH 07/15] Fixed TS types --- .../plugins-list/plugins-list-dataviews.tsx | 69 +++++++++---------- client/state/plugins/installed/types.ts | 1 + 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 689ee5763cb8a5..765bc21586babb 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -1,26 +1,28 @@ import { FoldableCard, ProgressBar } from '@automattic/components'; import { Button, Notice } from '@wordpress/components'; -import { filterSortAndPaginate } from '@wordpress/dataviews'; +import { filterSortAndPaginate, Operator } from '@wordpress/dataviews'; import { Icon, link, linkOff, plugins, trash } from '@wordpress/icons'; import { useTranslate } from 'i18n-calypso'; import { find } from 'lodash'; import { useEffect, useMemo, useState } from 'react'; +import { initialDataViewsState } from 'calypso/a8c-for-agencies/components/items-dashboard/constants'; import ItemsDataViews from 'calypso/a8c-for-agencies/components/items-dashboard/items-dataviews'; import { navigate } from 'calypso/lib/navigate'; import { useSelector } from 'calypso/state'; +import { Plugin } from 'calypso/state/plugins/installed/types'; import { PluginActions } from '../hooks/types'; import { getPluginActionStatuses } from '../plugin-management-v2/utils/get-plugin-action-statuses'; import './style.scss'; interface Props { - currentPlugins: Array; + currentPlugins: Array< Plugin >; initialSearch?: string; - pluginsWithUpdates: Array; - activePlugins: Array; - inactivePlugins: Array; + pluginsWithUpdates: Array< Plugin >; + activePlugins: Array< Plugin >; + inactivePlugins: Array< Plugin >; onSearch?: ( search: string ) => void; - bulkActionDialog: ( action: string, plugins: Array ) => void; + bulkActionDialog: ( action: string, plugins: Array< Plugin > ) => void; } export const PLUGINS_STATUS = { @@ -41,7 +43,6 @@ export default function PluginsListDataViews( { const allStatuses = useSelector( ( state ) => getPluginActionStatuses( state ) ); // Add flags for plugins status: active, inactive, updates - // TODO: Check the best way of doind this. We can probably move this to the backend currentPlugins.map( ( plugin ) => { plugin.status = []; @@ -67,7 +68,7 @@ export default function PluginsListDataViews( { { id: 'status', label: translate( 'Status' ), - getValue: ( { item }: { item } ) => { + getValue: ( { item }: { item: Plugin } ) => { return item.status; }, render: () => null, @@ -92,7 +93,7 @@ export default function PluginsListDataViews( { }, ], filterBy: { - operators: [ 'isAny' ], + operators: [ 'isAny' as Operator ], isPrimary: true, }, enableHiding: false, @@ -101,9 +102,9 @@ export default function PluginsListDataViews( { { id: 'plugins', label: 'Installed Plugins', - getValue: ( { item }: { item } ) => item.name, + getValue: ( { item }: { item: Plugin } ) => item.name, enableGlobalSearch: true, - render: ( { item } ) => { + render: ( { item }: { item: Plugin } ) => { return ( <> { item.icon && { } @@ -124,7 +125,7 @@ export default function PluginsListDataViews( { id: 'sites', label: 'Sites', enableHiding: false, - render: ( { item } ) => { + render: ( { item }: { item: Plugin } ) => { return { item.sites && Object.keys( item.sites ).length }; }, }, @@ -132,7 +133,7 @@ export default function PluginsListDataViews( { id: 'update', label: 'Update available', enableHiding: false, - render: ( { item } ) => { + render: ( { item }: { item: Plugin } ) => { if ( item.status?.includes( PLUGINS_STATUS.UPDATE ) ) { return ; } @@ -142,26 +143,12 @@ export default function PluginsListDataViews( { [] ); - const pluginsPerPage = 10; - const initialDataViewsState = { - type: 'table', - search: initialSearch || '', - filters: [], - page: 1, - perPage: pluginsPerPage, - sort: { - field: 'date', - direction: 'desc', - }, - fields: [ 'plugins', 'sites', 'update' ], - layout: {}, - }; - const actions = [ { + id: 'manage-plugin', href: `some-url`, - callback: ( data ) => { - data.length && navigate( '/plugins/' + data[ 0 ].slug ); + callback: ( plugins: Array< Plugin > ) => { + plugins.length && navigate( '/plugins/' + plugins[ 0 ].slug ); }, label: translate( 'Manage Plugin' ), isExternalLink: true, @@ -169,8 +156,9 @@ export default function PluginsListDataViews( { supportsBulk: false, }, { + id: 'activate-plugin', href: `some-url`, - callback: ( plugins ) => { + callback: ( plugins: Array< Plugin > ) => { bulkActionDialog( PluginActions.ACTIVATE, plugins ); }, label: translate( 'Activate' ), @@ -180,8 +168,9 @@ export default function PluginsListDataViews( { icon: , }, { + id: 'deactivate-plugin', href: `some-url`, - callback: ( plugins ) => { + callback: ( plugins: Array< Plugin > ) => { bulkActionDialog( PluginActions.DEACTIVATE, plugins ); }, label: translate( 'Deactivate' ), @@ -191,8 +180,9 @@ export default function PluginsListDataViews( { icon: , }, { + id: 'enable-autoupdate', href: `some-url`, - callback: ( plugins ) => { + callback: ( plugins: Array< Plugin > ) => { bulkActionDialog( PluginActions.ENABLE_AUTOUPDATES, plugins ); }, label: translate( 'Enable Autoupdate' ), @@ -201,8 +191,9 @@ export default function PluginsListDataViews( { supportsBulk: true, }, { + id: 'disable-autoupdate', href: `some-url`, - callback: ( plugins ) => { + callback: ( plugins: Array< Plugin > ) => { bulkActionDialog( PluginActions.DISABLE_AUTOUPDATES, plugins ); }, label: translate( 'Disable Autoupdate' ), @@ -211,8 +202,9 @@ export default function PluginsListDataViews( { supportsBulk: true, }, { + id: 'remove-plugin', href: `some-url`, - callback: ( plugins ) => { + callback: ( plugins: Array< Plugin > ) => { bulkActionDialog( PluginActions.REMOVE, plugins ); }, label: translate( 'Remove' ), @@ -223,11 +215,16 @@ export default function PluginsListDataViews( { }, ]; + // Set initial state for the data views + const pluginsPerPage = 10; + initialDataViewsState.perPage = pluginsPerPage; + initialDataViewsState.search = initialSearch || ''; + initialDataViewsState.fields = [ 'plugins', 'sites', 'update' ]; const [ dataViewsState, setDataViewsState ] = useState( initialDataViewsState ); // When search changes, notify the parent component useEffect( () => { - onSearch && onSearch( dataViewsState.search ); + onSearch && onSearch( dataViewsState.search || '' ); }, [ dataViewsState.search, onSearch ] ); const { data, paginationInfo } = useMemo( () => { diff --git a/client/state/plugins/installed/types.ts b/client/state/plugins/installed/types.ts index 5907d57798ca69..074afa26375feb 100644 --- a/client/state/plugins/installed/types.ts +++ b/client/state/plugins/installed/types.ts @@ -30,6 +30,7 @@ export type Plugin = { statusRecentlyChanged?: boolean; update?: PluginUpdate; wporg?: boolean; + status?: Array< number >; }; export type PluginSite = { From 0c0e71487f76fa18d9aecf3739df54c7f5d952ed Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Tue, 22 Oct 2024 10:24:57 -0300 Subject: [PATCH 08/15] Design feedback on status filter and loading state --- client/my-sites/plugins/plugins-list/index.jsx | 1 + .../plugins-list/plugins-list-dataviews.tsx | 15 ++++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/client/my-sites/plugins/plugins-list/index.jsx b/client/my-sites/plugins/plugins-list/index.jsx index dbd48c8346b5bc..6456700a1fea4e 100644 --- a/client/my-sites/plugins/plugins-list/index.jsx +++ b/client/my-sites/plugins/plugins-list/index.jsx @@ -364,6 +364,7 @@ export class PluginsList extends Component { activePlugins={ this.props.activePlugins } inactivePlugins={ this.props.inactivePlugins } bulkActionDialog={ this.bulkActionDialog } + isLoading={ this.props.isLoading } /> ); diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 765bc21586babb..76454ae52261f2 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -21,6 +21,7 @@ interface Props { pluginsWithUpdates: Array< Plugin >; activePlugins: Array< Plugin >; inactivePlugins: Array< Plugin >; + isLoading: boolean; onSearch?: ( search: string ) => void; bulkActionDialog: ( action: string, plugins: Array< Plugin > ) => void; } @@ -37,6 +38,7 @@ export default function PluginsListDataViews( { pluginsWithUpdates, activePlugins, inactivePlugins, + isLoading, onSearch, bulkActionDialog, }: Props ) { @@ -75,21 +77,15 @@ export default function PluginsListDataViews( { elements: [ { value: PLUGINS_STATUS.ACTIVE, - label: - translate( 'Active' ) + - ( activePlugins?.length > 0 ? ' - ' + activePlugins?.length : '' ), + label: translate( 'Active' ), }, { value: PLUGINS_STATUS.INACTIVE, - label: - translate( 'Inactive' ) + - ( inactivePlugins?.length > 0 ? ' - ' + inactivePlugins?.length : '' ), + label: translate( 'Inactive' ), }, { value: PLUGINS_STATUS.UPDATE, - label: - translate( 'Needs update' ) + - ( pluginsWithUpdates?.length > 0 ? ' - ' + pluginsWithUpdates?.length : '' ), + label: translate( 'Needs update' ), }, ], filterBy: { @@ -285,6 +281,7 @@ export default function PluginsListDataViews( { setDataViewsState: setDataViewsState, defaultLayouts: { table: {} }, } } + isLoading={ isLoading } /> ); From 73d0954a491689607f1c93f2e3238684e395a011 Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Tue, 22 Oct 2024 10:36:43 -0300 Subject: [PATCH 09/15] Add translation strings --- .../plugins/plugins-list/plugins-list-dataviews.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 76454ae52261f2..42f8953e48df81 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -97,7 +97,7 @@ export default function PluginsListDataViews( { }, { id: 'plugins', - label: 'Installed Plugins', + label: translate( 'Installed Plugins' ), getValue: ( { item }: { item: Plugin } ) => item.name, enableGlobalSearch: true, render: ( { item }: { item: Plugin } ) => { @@ -119,7 +119,7 @@ export default function PluginsListDataViews( { }, { id: 'sites', - label: 'Sites', + label: translate( 'Sites' ), enableHiding: false, render: ( { item }: { item: Plugin } ) => { return { item.sites && Object.keys( item.sites ).length }; @@ -127,7 +127,7 @@ export default function PluginsListDataViews( { }, { id: 'update', - label: 'Update available', + label: translate( 'Update available' ), enableHiding: false, render: ( { item }: { item: Plugin } ) => { if ( item.status?.includes( PLUGINS_STATUS.UPDATE ) ) { @@ -214,7 +214,7 @@ export default function PluginsListDataViews( { // Set initial state for the data views const pluginsPerPage = 10; initialDataViewsState.perPage = pluginsPerPage; - initialDataViewsState.search = initialSearch || ''; + initialDataViewsState.search = initialSearch; initialDataViewsState.fields = [ 'plugins', 'sites', 'update' ]; const [ dataViewsState, setDataViewsState ] = useState( initialDataViewsState ); From 37527cc065628805747c370f4fceb1d02cbe9bb2 Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Tue, 22 Oct 2024 15:15:15 -0300 Subject: [PATCH 10/15] Reusing css styles --- .../sites/features/jetpack/style.scss | 2 +- .../sites/components/dotcom-style.scss | 3 +- .../plugins-list/plugins-list-dataviews.tsx | 2 + .../my-sites/plugins/plugins-list/style.scss | 75 +++---------------- client/my-sites/plugins/style.scss | 11 --- 5 files changed, 14 insertions(+), 79 deletions(-) diff --git a/client/a8c-for-agencies/sections/sites/features/jetpack/style.scss b/client/a8c-for-agencies/sections/sites/features/jetpack/style.scss index fc287713218c02..43ea1f902cfa3e 100644 --- a/client/a8c-for-agencies/sections/sites/features/jetpack/style.scss +++ b/client/a8c-for-agencies/sections/sites/features/jetpack/style.scss @@ -1,4 +1,4 @@ -.sites-dashboard { +.sites-dashboard, .plugin-management-wrapper { .activity-log-v2 .button.toolbar__button { display: none !important; } diff --git a/client/hosting/sites/components/dotcom-style.scss b/client/hosting/sites/components/dotcom-style.scss index ef27adef91b9a4..79b1a030ae0305 100644 --- a/client/hosting/sites/components/dotcom-style.scss +++ b/client/hosting/sites/components/dotcom-style.scss @@ -61,7 +61,8 @@ } } -.wpcom-site .main.a4a-layout.sites-dashboard.sites-dashboard__layout .sites-overview { +.wpcom-site .main.a4a-layout.sites-dashboard.sites-dashboard__layout .sites-overview, +.wpcom-site .plugin-management-wrapper { background: var(--studio-white); .a4a-layout__top-wrapper { diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 42f8953e48df81..4ce8e467d872ff 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -13,6 +13,8 @@ import { Plugin } from 'calypso/state/plugins/installed/types'; import { PluginActions } from '../hooks/types'; import { getPluginActionStatuses } from '../plugin-management-v2/utils/get-plugin-action-statuses'; +import 'calypso/a8c-for-agencies/sections/sites/features/jetpack/style.scss'; +import 'calypso/a8c-for-agencies/style.scss'; import './style.scss'; interface Props { diff --git a/client/my-sites/plugins/plugins-list/style.scss b/client/my-sites/plugins/plugins-list/style.scss index 12096cb0575cda..5756ecdc4336a6 100644 --- a/client/my-sites/plugins/plugins-list/style.scss +++ b/client/my-sites/plugins/plugins-list/style.scss @@ -1,83 +1,26 @@ -.plugins-list { - margin-bottom: 16px; -} - -.plugins-list .plugin-item { - @include breakpoint-deprecated( "<1040px" ) { - width: 100%; - - &:nth-last-child(n + 2) { - border-bottom-width: 1px; - } - } - - @include breakpoint-deprecated( ">1040px" ) { - flex-direction: column; - width: 33.33%; - border-right-width: 1px; - - &:nth-last-child(n + 4) { - border-bottom-width: 1px; - } - - // Provider proper bottom borders in the second-last row when the number - // of items is not multiple of 3. - &:nth-child(3n) { - border-right-width: 0; - &:nth-last-child(3), - &:nth-last-child(2) { - border-bottom-width: 1px; - } - } - - &:nth-child(3n - 1):nth-last-child(3) { - border-bottom-width: 1px; - } - - .plugin-item__count, - .plugin-item__actions { - align-self: flex-end; - flex-direction: column; - margin-top: -6px; - padding-top: 0; - text-align: right; - } +body.is-section-plugins .plugin-management-wrapper { - .plugin-item__count { - flex-direction: row; - } + .navigation-header { + border-block-end: 1px solid var(--color-border-secondary); + padding-inline: 48px; } -} - -.plugins-list__elements { - display: flex; - flex-flow: row wrap; - padding: 0; -} - - - - -body.is-section-plugins .plugin-management-wrapper { .dataviews-wrapper { .dataviews-view-table { - border: 1px solid var(--color-neutral-5); - border-radius: 2px; + table-layout: auto; .dataviews-view-table__row { img, svg { max-width: 35px; - margin-right: 15px; + margin-right: 16px; } .dataviews-view-table-selection-checkbox{ padding-left: 0; } - } - - .dataviews-view-table__checkbox-column { - padding-left: 18px; + .dataviews-view-table__checkbox-column { + padding-left: 47px; + } } } } diff --git a/client/my-sites/plugins/style.scss b/client/my-sites/plugins/style.scss index 3802790ffe0de0..2fff706b19b88b 100644 --- a/client/my-sites/plugins/style.scss +++ b/client/my-sites/plugins/style.scss @@ -514,17 +514,6 @@ body.is-section-plugins #primary { } } -body.is-section-plugins .plugin-management-wrapper { - @include break-small { - padding-left: 1rem; - padding-right: 1rem; - } - @include break-medium { - padding-left: 2rem; - padding-right: 2rem; - } -} - .plugins__page-title { color: var(--studio-gray-80); font-weight: 400; From 357dffe9addede33f8aee39a31ad5d05b10f82bd Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Wed, 23 Oct 2024 14:26:54 -0300 Subject: [PATCH 11/15] Simplified CSS --- .../sections/sites/features/jetpack/style.scss | 2 +- client/hosting/sites/components/dotcom-style.scss | 3 +-- .../plugins/plugins-list/plugins-list-dataviews.tsx | 2 -- client/my-sites/plugins/plugins-list/style.scss | 8 ++++---- client/my-sites/plugins/style.scss | 12 ------------ 5 files changed, 6 insertions(+), 21 deletions(-) diff --git a/client/a8c-for-agencies/sections/sites/features/jetpack/style.scss b/client/a8c-for-agencies/sections/sites/features/jetpack/style.scss index 43ea1f902cfa3e..fc287713218c02 100644 --- a/client/a8c-for-agencies/sections/sites/features/jetpack/style.scss +++ b/client/a8c-for-agencies/sections/sites/features/jetpack/style.scss @@ -1,4 +1,4 @@ -.sites-dashboard, .plugin-management-wrapper { +.sites-dashboard { .activity-log-v2 .button.toolbar__button { display: none !important; } diff --git a/client/hosting/sites/components/dotcom-style.scss b/client/hosting/sites/components/dotcom-style.scss index 79b1a030ae0305..ef27adef91b9a4 100644 --- a/client/hosting/sites/components/dotcom-style.scss +++ b/client/hosting/sites/components/dotcom-style.scss @@ -61,8 +61,7 @@ } } -.wpcom-site .main.a4a-layout.sites-dashboard.sites-dashboard__layout .sites-overview, -.wpcom-site .plugin-management-wrapper { +.wpcom-site .main.a4a-layout.sites-dashboard.sites-dashboard__layout .sites-overview { background: var(--studio-white); .a4a-layout__top-wrapper { diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 4ce8e467d872ff..42f8953e48df81 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -13,8 +13,6 @@ import { Plugin } from 'calypso/state/plugins/installed/types'; import { PluginActions } from '../hooks/types'; import { getPluginActionStatuses } from '../plugin-management-v2/utils/get-plugin-action-statuses'; -import 'calypso/a8c-for-agencies/sections/sites/features/jetpack/style.scss'; -import 'calypso/a8c-for-agencies/style.scss'; import './style.scss'; interface Props { diff --git a/client/my-sites/plugins/plugins-list/style.scss b/client/my-sites/plugins/plugins-list/style.scss index 5756ecdc4336a6..af95e376dba7b0 100644 --- a/client/my-sites/plugins/plugins-list/style.scss +++ b/client/my-sites/plugins/plugins-list/style.scss @@ -4,10 +4,13 @@ body.is-section-plugins .plugin-management-wrapper { border-block-end: 1px solid var(--color-border-secondary); padding-inline: 48px; } +} + +body.is-section-plugins .plugin-management-wrapper, +.is-section-jetpack-cloud-plugin-management { .dataviews-wrapper { .dataviews-view-table { - table-layout: auto; .dataviews-view-table__row { img, svg { @@ -18,9 +21,6 @@ body.is-section-plugins .plugin-management-wrapper { .dataviews-view-table-selection-checkbox{ padding-left: 0; } - .dataviews-view-table__checkbox-column { - padding-left: 47px; - } } } } diff --git a/client/my-sites/plugins/style.scss b/client/my-sites/plugins/style.scss index 2fff706b19b88b..76c1051d79fb5d 100644 --- a/client/my-sites/plugins/style.scss +++ b/client/my-sites/plugins/style.scss @@ -617,18 +617,6 @@ body.is-section-plugins #primary { } } -.plugins__main-content-jc { - // We need these negative margin values because we want to make the container full-width, - // but our element is inside a limited-width parent. - margin: 0 -32px; - padding: 0 48px; - - @include breakpoint-deprecated( ">660px" ) { - padding: 16px 48px; - margin-bottom: -32px; - } -} - .plugins__search { height: 52px; box-shadow: 0 0 0 1px var(--color-neutral-5); From b789214de1e80ee60abcb2f13aa89dc1d300cb4d Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Wed, 23 Oct 2024 14:55:41 -0300 Subject: [PATCH 12/15] Fixed selection color and action margins --- .../plugins-list/plugins-list-dataviews.tsx | 12 +++-------- .../my-sites/plugins/plugins-list/style.scss | 21 ++++++++----------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 42f8953e48df81..421c9b18c5830a 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -103,14 +103,8 @@ export default function PluginsListDataViews( { render: ( { item }: { item: Plugin } ) => { return ( <> - { item.icon && { } - { ! item.icon && ( - - ) } + { item.icon && { } + { ! item.icon && } { item.name } ); @@ -212,7 +206,7 @@ export default function PluginsListDataViews( { ]; // Set initial state for the data views - const pluginsPerPage = 10; + const pluginsPerPage = 15; initialDataViewsState.perPage = pluginsPerPage; initialDataViewsState.search = initialSearch; initialDataViewsState.fields = [ 'plugins', 'sites', 'update' ]; diff --git a/client/my-sites/plugins/plugins-list/style.scss b/client/my-sites/plugins/plugins-list/style.scss index af95e376dba7b0..fb0cda9aec6cda 100644 --- a/client/my-sites/plugins/plugins-list/style.scss +++ b/client/my-sites/plugins/plugins-list/style.scss @@ -8,21 +8,18 @@ body.is-section-plugins .plugin-management-wrapper { body.is-section-plugins .plugin-management-wrapper, .is-section-jetpack-cloud-plugin-management { + --wp-components-color-accent: var(--studio-automattic-blue-50); - .dataviews-wrapper { - .dataviews-view-table { - - .dataviews-view-table__row { - img, svg { - max-width: 35px; - margin-right: 16px; - } + .dataviews-wrapper .dataviews-view-table { + .dataviews-view-table__row { + .plugin-icon { + max-width: 35px; + max-height: 35px; + } - .dataviews-view-table-selection-checkbox{ - padding-left: 0; - } + .dataviews-view-table-selection-checkbox{ + padding-left: 0; } } } - } From 800ad50c6a2e1fa4d542bfc27454d3c33aaec3f1 Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Wed, 23 Oct 2024 15:53:36 -0300 Subject: [PATCH 13/15] Added proper support to update CTA --- .../plugins/plugins-list/plugins-list-dataviews.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 421c9b18c5830a..4e7f472561e45c 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -125,7 +125,18 @@ export default function PluginsListDataViews( { enableHiding: false, render: ( { item }: { item: Plugin } ) => { if ( item.status?.includes( PLUGINS_STATUS.UPDATE ) ) { - return ; + return ( + + ); } }, }, From 3757cd9b9ffdaa10b3e086252471608bebb2c021 Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Thu, 24 Oct 2024 18:38:17 -0300 Subject: [PATCH 14/15] Reimplemented default PluginActionStatus feedback --- .../plugin-action-status/style.scss | 2 +- .../plugins-list/plugins-list-dataviews.tsx | 69 ++++++++----------- client/state/plugins/installed/types.ts | 2 + 3 files changed, 30 insertions(+), 43 deletions(-) diff --git a/client/my-sites/plugins/plugin-management-v2/plugin-action-status/style.scss b/client/my-sites/plugins/plugin-management-v2/plugin-action-status/style.scss index fd266cadf3e7f0..a5f05e386e6457 100644 --- a/client/my-sites/plugins/plugin-management-v2/plugin-action-status/style.scss +++ b/client/my-sites/plugins/plugin-management-v2/plugin-action-status/style.scss @@ -2,7 +2,7 @@ @import "@wordpress/base-styles/mixins"; .plugin-action-status-container { - margin-top: -8px; + margin-left: 20px; white-space: pre; } diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 4e7f472561e45c..8e0cdaaef4822b 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -1,5 +1,4 @@ -import { FoldableCard, ProgressBar } from '@automattic/components'; -import { Button, Notice } from '@wordpress/components'; +import { Button } from '@wordpress/components'; import { filterSortAndPaginate, Operator } from '@wordpress/dataviews'; import { Icon, link, linkOff, plugins, trash } from '@wordpress/icons'; import { useTranslate } from 'i18n-calypso'; @@ -11,6 +10,7 @@ import { navigate } from 'calypso/lib/navigate'; import { useSelector } from 'calypso/state'; import { Plugin } from 'calypso/state/plugins/installed/types'; import { PluginActions } from '../hooks/types'; +import PluginActionStatus from '../plugin-management-v2/plugin-action-status'; import { getPluginActionStatuses } from '../plugin-management-v2/utils/get-plugin-action-statuses'; import './style.scss'; @@ -42,7 +42,9 @@ export default function PluginsListDataViews( { onSearch, bulkActionDialog, }: Props ) { - const allStatuses = useSelector( ( state ) => getPluginActionStatuses( state ) ); + const allStatuses = useSelector( ( state ) => { + return getPluginActionStatuses( state ); + } ); // Add flags for plugins status: active, inactive, updates currentPlugins.map( ( plugin ) => { @@ -101,11 +103,23 @@ export default function PluginsListDataViews( { getValue: ( { item }: { item: Plugin } ) => item.name, enableGlobalSearch: true, render: ( { item }: { item: Plugin } ) => { + let pluginActionStatus = null; + + if ( item.allStatuses?.length ) { + pluginActionStatus = ( + + ); + } + return ( <> { item.icon && { } { ! item.icon && } { item.name } + { pluginActionStatus } ); }, @@ -229,50 +243,21 @@ export default function PluginsListDataViews( { }, [ dataViewsState.search, onSearch ] ); const { data, paginationInfo } = useMemo( () => { - return filterSortAndPaginate( currentPlugins, dataViewsState, fields ); - }, [ currentPlugins, dataViewsState, fields ] ); + const result = filterSortAndPaginate( currentPlugins, dataViewsState, fields ); - const ApplyingStatus = () => { - const completed = allStatuses.filter( ( status ) => status.status === 'completed' ); - const errors = allStatuses.filter( ( status ) => status.status === 'error' ); + // Add all statuses to the plugin object so we can display them in the DataViews + result.data.forEach( ( plugin ) => { + plugin.allStatuses = allStatuses.filter( ( status ) => status.pluginId === plugin.id ); + } ); - if ( - allStatuses.length === 0 || - completed.length === allStatuses.length || - completed.length + errors.length === allStatuses.length - ) { - return null; - } - - const value = ( completed.length * 100 ) / allStatuses.length; - - return ( - <> -

{ translate( 'Applying modifications' ) }

- - - - { translate( 'An error occurred while applying modifications' ) } - - - { errors.map( ( error ) => ( - <> - - { translate( 'Site: ' ) } { error.siteId } { ' - ' } - { translate( 'Error: ' ) } - { error.error.message } - -
- - ) ) } -
- - ); - }; + return { + data: result.data, + paginationInfo: result.paginationInfo, + }; + }, [ currentPlugins, dataViewsState, fields, allStatuses ] ); return (
- ; + allStatuses?: Array< CurrentSiteStatus >; }; export type PluginSite = { From 7ce60e30c674de09b619d1c8cb97157578f0748b Mon Sep 17 00:00:00 2001 From: Paulo Trentin Date: Thu, 24 Oct 2024 20:59:37 -0300 Subject: [PATCH 15/15] Fixed search and sorting issues --- client/my-sites/plugins/main.jsx | 37 +++---------------- .../plugins-list/plugins-list-dataviews.tsx | 10 ++++- .../my-sites/plugins/plugins-list/style.scss | 2 +- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/client/my-sites/plugins/main.jsx b/client/my-sites/plugins/main.jsx index 54460c972025c6..27537a13bbffb8 100644 --- a/client/my-sites/plugins/main.jsx +++ b/client/my-sites/plugins/main.jsx @@ -16,7 +16,6 @@ import DocumentHead from 'calypso/components/data/document-head'; import QueryJetpackSitesFeatures from 'calypso/components/data/query-jetpack-sites-features'; import QueryPlugins from 'calypso/components/data/query-plugins'; import QuerySiteFeatures from 'calypso/components/data/query-site-features'; -import EmptyContent from 'calypso/components/empty-content'; import NavigationHeader from 'calypso/components/navigation-header'; import MissingPaymentNotification from 'calypso/jetpack-cloud/components/missing-payment-notification'; import PageViewTracker from 'calypso/lib/analytics/page-view-tracker'; @@ -152,17 +151,13 @@ export class PluginsMain extends Component { } getCurrentPlugins() { - const { currentPlugins, currentPluginsOnVisibleSites, search, selectedSiteSlug } = this.props; - let plugins = selectedSiteSlug ? currentPlugins : currentPluginsOnVisibleSites; + const { currentPlugins, currentPluginsOnVisibleSites, selectedSiteSlug } = this.props; + const plugins = selectedSiteSlug ? currentPlugins : currentPluginsOnVisibleSites; if ( ! plugins ) { return plugins; } - if ( search ) { - plugins = plugins.filter( this.matchSearchTerms.bind( this, search ) ); - } - return this.addWporgDataToPlugins( plugins ); } @@ -310,34 +305,14 @@ export class PluginsMain extends Component { } renderPluginsContent() { - const { search, isJetpackCloud } = this.props; - - const currentPlugins = this.getCurrentPlugins(); - const showInstalledPluginList = - isJetpackCloud || ! isEmpty( currentPlugins ) || this.isFetchingPlugins(); - - if ( ! showInstalledPluginList && ! search && ! this.props.requestPluginsError ) { - const emptyContentData = this.getEmptyContentData(); - if ( emptyContentData ) { - return ( - - ); - } - } - - const installedPluginsList = showInstalledPluginList && ( + return ( ); - - return
{ installedPluginsList }
; } handleAddPluginButtonClick = () => { diff --git a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx index 8e0cdaaef4822b..d98f13b0c1ce2c 100644 --- a/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx +++ b/client/my-sites/plugins/plugins-list/plugins-list-dataviews.tsx @@ -123,12 +123,16 @@ export default function PluginsListDataViews( { ); }, - enableSorting: false, + enableSorting: true, }, { id: 'sites', label: translate( 'Sites' ), enableHiding: false, + getValue: ( { item }: { item: Plugin } ) => { + // Used exclusively for sorting + return item.sites && Object.keys( item.sites ).length; + }, render: ( { item }: { item: Plugin } ) => { return { item.sites && Object.keys( item.sites ).length }; }, @@ -136,6 +140,10 @@ export default function PluginsListDataViews( { { id: 'update', label: translate( 'Update available' ), + getValue: ( { item }: { item: Plugin } ) => { + // Used exclusively for sorting + return item.status?.includes( PLUGINS_STATUS.UPDATE ) ? 'a' : 'b'; + }, enableHiding: false, render: ( { item }: { item: Plugin } ) => { if ( item.status?.includes( PLUGINS_STATUS.UPDATE ) ) { diff --git a/client/my-sites/plugins/plugins-list/style.scss b/client/my-sites/plugins/plugins-list/style.scss index fb0cda9aec6cda..cbcc3f8800fb9e 100644 --- a/client/my-sites/plugins/plugins-list/style.scss +++ b/client/my-sites/plugins/plugins-list/style.scss @@ -1,4 +1,5 @@ body.is-section-plugins .plugin-management-wrapper { + --wp-components-color-accent: var(--studio-automattic-blue-50); .navigation-header { border-block-end: 1px solid var(--color-border-secondary); @@ -8,7 +9,6 @@ body.is-section-plugins .plugin-management-wrapper { body.is-section-plugins .plugin-management-wrapper, .is-section-jetpack-cloud-plugin-management { - --wp-components-color-accent: var(--studio-automattic-blue-50); .dataviews-wrapper .dataviews-view-table { .dataviews-view-table__row {