From 576c3faad464f5c6a57844ca1fd7b37a56b644cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20de=20Juvigny?= Date: Wed, 5 Oct 2022 15:58:49 +0200 Subject: [PATCH 01/10] Rename fetch market providers function --- .../admin/src/hooks/useFetchMarketplaceProviders/index.js | 4 ++-- .../admin/src/hooks/useFetchMarketplaceProviders/utils/api.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/admin/admin/src/hooks/useFetchMarketplaceProviders/index.js b/packages/core/admin/admin/src/hooks/useFetchMarketplaceProviders/index.js index 9970a335c5..ddb7d26f4e 100644 --- a/packages/core/admin/admin/src/hooks/useFetchMarketplaceProviders/index.js +++ b/packages/core/admin/admin/src/hooks/useFetchMarketplaceProviders/index.js @@ -1,11 +1,11 @@ import { useQuery } from 'react-query'; import { useNotification } from '@strapi/helper-plugin'; -import { fetchMarketplacePlugins } from './utils/api'; +import { fetchMarketplaceProviders } from './utils/api'; const useFetchMarketplaceProviders = (notifyLoad) => { const toggleNotification = useNotification(); - return useQuery('list-marketplace-providers', () => fetchMarketplacePlugins(), { + return useQuery('list-marketplace-providers', () => fetchMarketplaceProviders(), { onSuccess() { if (notifyLoad) { notifyLoad(); diff --git a/packages/core/admin/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js b/packages/core/admin/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js index c1776b1bfd..2c01ea2c94 100644 --- a/packages/core/admin/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +++ b/packages/core/admin/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js @@ -2,10 +2,10 @@ import axios from 'axios'; const MARKETPLACE_API_URL = 'https://market-api.strapi.io'; -const fetchMarketplacePlugins = async () => { +const fetchMarketplaceProviders = async () => { const { data } = await axios.get(`${MARKETPLACE_API_URL}/providers`); return data; }; -export { fetchMarketplacePlugins }; +export { fetchMarketplaceProviders }; From 45af88102b266bf7fffa213ce37ef16cd8a70ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20de=20Juvigny?= Date: Thu, 6 Oct 2022 14:44:54 +0200 Subject: [PATCH 02/10] Add marketplace category selector --- .../NpmPackagesFilters/FiltersPopover.js | 84 +++++++++++++++++++ .../components/NpmPackagesFilters/index.js | 43 ++++++++++ .../admin/src/pages/MarketplacePage/index.js | 4 + .../core/admin/admin/src/translations/en.json | 12 +-- 4 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js create mode 100644 packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/index.js diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js new file mode 100644 index 0000000000..a0da017ac4 --- /dev/null +++ b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js @@ -0,0 +1,84 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Box } from '@strapi/design-system/Box'; +import { Popover } from '@strapi/design-system/Popover'; +import { Stack } from '@strapi/design-system/Stack'; +import { FocusTrap } from '@strapi/design-system/FocusTrap'; +import { Select, Option } from '@strapi/design-system/Select'; +import { useIntl } from 'react-intl'; + +const filters = { + categories: { + 'Custom fields': 20, + Deployment: 4, + }, +}; + +const FiltersPopover = ({ source, onToggle, query, setQuery }) => { + const { formatMessage } = useIntl(); + + const handleSubmit = (e) => { + e.preventDefault(); + }; + + const categoriesMessage = formatMessage({ + id: 'admin.pages.MarketPlacePage.filters.collections', + defaultMessage: 'Collections', + }); + + return ( + {}}> + +
+ + + + + +
+
+
+ ); +}; + +FiltersPopover.defaultProps = { + query: {}, +}; + +FiltersPopover.propTypes = { + onToggle: PropTypes.func.isRequired, + source: PropTypes.shape({ current: PropTypes.instanceOf(Element) }).isRequired, + query: PropTypes.shape({ + collections: PropTypes.arrayOf(PropTypes.string), + categories: PropTypes.arrayOf(PropTypes.string), + }), + setQuery: PropTypes.func.isRequired, +}; + +export default FiltersPopover; diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/index.js b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/index.js new file mode 100644 index 0000000000..cb106ba5e7 --- /dev/null +++ b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/index.js @@ -0,0 +1,43 @@ +import React, { useState, useRef } from 'react'; +import { useIntl } from 'react-intl'; +import { useQueryParams } from '@strapi/helper-plugin'; +import { Box } from '@strapi/design-system/Box'; +import { Button } from '@strapi/design-system/Button'; +import Filter from '@strapi/icons/Filter'; +import FiltersPopover from './FiltersPopover'; + +const NpmPackagesFilters = () => { + const [isVisible, setIsVisible] = useState(false); + const buttonRef = useRef(); + const { formatMessage } = useIntl(); + const [{ query }, setQuery] = useQueryParams(); + + const handleToggle = () => setIsVisible((prev) => !prev); + + return ( + <> + + + {isVisible && ( + + )} + + {/* */} + + ); +}; + +export default NpmPackagesFilters; diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/index.js b/packages/core/admin/admin/src/pages/MarketplacePage/index.js index 1d5552fda4..596893fa61 100644 --- a/packages/core/admin/admin/src/pages/MarketplacePage/index.js +++ b/packages/core/admin/admin/src/pages/MarketplacePage/index.js @@ -29,6 +29,7 @@ import offlineCloud from '../../assets/images/icon_offline-cloud.svg'; import useNavigatorOnLine from '../../hooks/useNavigatorOnLine'; import MissingPluginBanner from './components/MissingPluginBanner'; import NpmPackagesGrid from './components/NpmPackagesGrid'; +import NpmPackagesFilters from './components/NpmPackagesFilters'; const matchSearch = (npmPackages, search) => { return matchSorter(npmPackages, search, { @@ -235,6 +236,9 @@ const MarketPlacePage = () => { + + + {/* Plugins panel */} diff --git a/packages/core/admin/admin/src/translations/en.json b/packages/core/admin/admin/src/translations/en.json index 52320dfbe3..164f84a741 100644 --- a/packages/core/admin/admin/src/translations/en.json +++ b/packages/core/admin/admin/src/translations/en.json @@ -100,11 +100,11 @@ "Settings.apiTokens.duration.30-days": "30 days", "Settings.apiTokens.duration.90-days": "90 days", "Settings.apiTokens.duration.unlimited": "Unlimited", - "Settings.apiTokens.form.duration":"Token duration", - "Settings.apiTokens.form.type":"Token type", - "Settings.apiTokens.duration.expiration-date":"Expiration date", - "Settings.apiTokens.createPage.permissions.title":"Permissions", - "Settings.apiTokens.createPage.permissions.description":"Only actions bound by a route are listed below.", + "Settings.apiTokens.form.duration": "Token duration", + "Settings.apiTokens.form.type": "Token type", + "Settings.apiTokens.duration.expiration-date": "Expiration date", + "Settings.apiTokens.createPage.permissions.title": "Permissions", + "Settings.apiTokens.createPage.permissions.description": "Only actions bound by a route are listed below.", "Settings.apiTokens.RegenerateDialog.title": "Regenerate token", "Settings.apiTokens.popUpWarning.message": "Are you sure you want to regenerate this token?", "Settings.apiTokens.Button.cancel": "Cancel", @@ -280,6 +280,8 @@ "admin.pages.MarketPlacePage.tab-group.label": "Plugins and Providers for Strapi", "admin.pages.MarketPlacePage.missingPlugin.title": "Missing a plugin?", "admin.pages.MarketPlacePage.missingPlugin.description": "Tell us what plugin you are looking for and we'll let our community plugin developers know in case they are in search for inspiration!", + "admin.pages.MarketPlacePage.filters.collections": "Collections", + "admin.pages.MarketPlacePage.filters.collectionsSelected": "{count, plural, =0 {No collections} one {# collection} other {# collections}} selected", "anErrorOccurred": "Woops! Something went wrong. Please, try again.", "app.component.CopyToClipboard.label": "Copy to clipboard", "app.component.search.label": "Search for {target}", From 75ae5977e0a67f918d678ad5151fda7b7103ccb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20de=20Juvigny?= Date: Thu, 6 Oct 2022 15:41:58 +0200 Subject: [PATCH 03/10] Add abstraction for marketplace filters --- .../NpmPackagesFilters/FilterSelect.js | 47 ++++++++++++++ .../NpmPackagesFilters/FiltersPopover.js | 64 +++++++++++-------- .../core/admin/admin/src/translations/en.json | 2 + 3 files changed, 88 insertions(+), 25 deletions(-) create mode 100644 packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FilterSelect.js diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FilterSelect.js b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FilterSelect.js new file mode 100644 index 0000000000..107d13a475 --- /dev/null +++ b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FilterSelect.js @@ -0,0 +1,47 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Select, Option } from '@strapi/design-system/Select'; + +const FilterSelect = ({ + message, + value, + onChange, + name, + possibleFilters, + onClear, + customizeContent, +}) => { + return ( + + ); +}; + +FilterSelect.propTypes = { + message: PropTypes.string.isRequired, + value: PropTypes.array.isRequired, + onChange: PropTypes.func.isRequired, + name: PropTypes.string.isRequired, + possibleFilters: PropTypes.object.isRequired, + onClear: PropTypes.func.isRequired, + customizeContent: PropTypes.func.isRequired, +}; + +export default FilterSelect; diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js index a0da017ac4..a68657682d 100644 --- a/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js +++ b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js @@ -4,10 +4,14 @@ import { Box } from '@strapi/design-system/Box'; import { Popover } from '@strapi/design-system/Popover'; import { Stack } from '@strapi/design-system/Stack'; import { FocusTrap } from '@strapi/design-system/FocusTrap'; -import { Select, Option } from '@strapi/design-system/Select'; import { useIntl } from 'react-intl'; +import FilterSelect from './FilterSelect'; -const filters = { +const possibleFilters = { + collections: { + 'Made by Strapi': 20, + Verified: 4, + }, categories: { 'Custom fields': 20, Deployment: 4, @@ -21,44 +25,54 @@ const FiltersPopover = ({ source, onToggle, query, setQuery }) => { e.preventDefault(); }; - const categoriesMessage = formatMessage({ - id: 'admin.pages.MarketPlacePage.filters.collections', - defaultMessage: 'Collections', - }); - return ( {}}>
- - {Object.entries(possibleFilters).map(([name, count]) => { + {Object.entries(possibleFilters).map(([filterName, count]) => { return ( - ); })} @@ -38,7 +29,6 @@ FilterSelect.propTypes = { message: PropTypes.string.isRequired, value: PropTypes.array.isRequired, onChange: PropTypes.func.isRequired, - name: PropTypes.string.isRequired, possibleFilters: PropTypes.object.isRequired, onClear: PropTypes.func.isRequired, customizeContent: PropTypes.func.isRequired, diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js index a9e97f47ce..f247bcefb6 100644 --- a/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js +++ b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js @@ -26,7 +26,7 @@ const FiltersPopover = ({ {}}> - + )} diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/tests/index.test.js b/packages/core/admin/admin/src/pages/MarketplacePage/tests/index.test.js index 8ada3d878b..8e2bba5753 100644 --- a/packages/core/admin/admin/src/pages/MarketplacePage/tests/index.test.js +++ b/packages/core/admin/admin/src/pages/MarketplacePage/tests/index.test.js @@ -178,6 +178,25 @@ describe('Marketplace page', () => { expect(noResult).toBeVisible(); }); + it('shows filters popover on plugins and providers', () => { + render(App); + + // Show collections and categories filters on plugins + const pluginsTab = screen.getByRole('tab', { name: /plugins/i }); + fireEvent.click(pluginsTab); + const filtersButton = screen.getByRole('button', { name: /filters/i }); + fireEvent.click(filtersButton); + screen.getByLabelText(/no collections selected/i); + screen.getByLabelText(/no categories selected/i); + fireEvent.click(filtersButton); + + // Only show collections filters on providers + const providersTab = screen.getByRole('tab', { name: /providers/i }); + fireEvent.click(providersTab); + fireEvent.click(filtersButton); + screen.getByLabelText(/no collections selected/i); + }); + it('handles production environment', () => { // Simulate production environment useAppInfos.mockImplementationOnce(() => ({ From 4d2f9eeb3d84cbb66f8e51f09b9d684d8b6e7d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20de=20Juvigny?= Date: Tue, 11 Oct 2022 14:46:09 +0200 Subject: [PATCH 10/10] Apply feedback --- .../NpmPackagesFilters/FiltersPopover.js | 76 +++++++++---------- .../admin/src/pages/MarketplacePage/index.js | 11 +-- 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js index f247bcefb6..71220e843c 100644 --- a/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js +++ b/packages/core/admin/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js @@ -18,64 +18,58 @@ const FiltersPopover = ({ }) => { const { formatMessage } = useIntl(); - const handleSubmit = (e) => { - e.preventDefault(); - }; - return ( {}}> - - + + + setQuery({ collections: newCollections })} + onClear={() => setQuery({ collections: [] }, 'remove')} + possibleFilters={possibleCollections} + customizeContent={(values) => + formatMessage( + { + id: 'admin.pages.MarketPlacePage.filters.collectionsSelected', + defaultMessage: + '{count, plural, =0 {No collections} one {# collection} other {# collections}} selected', + }, + { count: values.length } + ) + } + /> + + {npmPackageType === 'plugin' && ( setQuery({ collections: newCollections })} - onClear={() => setQuery({ collections: [] }, 'remove')} - possibleFilters={possibleCollections} + value={query?.categories || []} + onChange={(newCategories) => setQuery({ categories: newCategories })} + onClear={() => setQuery({ categories: [] }, 'remove')} + possibleFilters={possibleCategories} customizeContent={(values) => formatMessage( { - id: 'admin.pages.MarketPlacePage.filters.collectionsSelected', + id: 'admin.pages.MarketPlacePage.filters.categoriesSelected', defaultMessage: - '{count, plural, =0 {No collections} one {# collection} other {# collections}} selected', + '{count, plural, =0 {No categories} one {# category} other {# categories}} selected', }, { count: values.length } ) } + name="categories" /> - {npmPackageType === 'plugin' && ( - - setQuery({ categories: newCategories })} - onClear={() => setQuery({ categories: [] }, 'remove')} - possibleFilters={possibleCategories} - customizeContent={(values) => - formatMessage( - { - id: 'admin.pages.MarketPlacePage.filters.categoriesSelected', - defaultMessage: - '{count, plural, =0 {No categories} one {# category} other {# categories}} selected', - }, - { count: values.length } - ) - } - name="categories" - /> - - )} - - + )} + ); diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/index.js b/packages/core/admin/admin/src/pages/MarketplacePage/index.js index 89da83616c..89ab68053d 100644 --- a/packages/core/admin/admin/src/pages/MarketplacePage/index.js +++ b/packages/core/admin/admin/src/pages/MarketplacePage/index.js @@ -185,6 +185,11 @@ const MarketPlacePage = () => { // Check if plugins and providers are installed already const installedPackageNames = Object.keys(dependencies); + const possibleCollections = + npmPackageType === 'plugin' + ? marketplacePluginsResponse.meta.collections + : marketplaceProvidersResponse.meta.collections; + return (
@@ -248,11 +253,7 @@ const MarketPlacePage = () => {