Skip to content

Commit

Permalink
Merge pull request #13462 from strapi/providers/add-tabs
Browse files Browse the repository at this point in the history
[marketplace] add providers tabs
  • Loading branch information
markkaylor committed Jun 13, 2022
2 parents 164ca83 + 9d40d0c commit 1b93931
Show file tree
Hide file tree
Showing 9 changed files with 1,348 additions and 746 deletions.
@@ -0,0 +1,23 @@
import { useQuery } from 'react-query';
import { useNotification } from '@strapi/helper-plugin';
import { fetchMarketplacePlugins } from './utils/api';

const useFetchMarketplaceProviders = (notifyLoad) => {
const toggleNotification = useNotification();

return useQuery('list-marketplace-providers', () => fetchMarketplacePlugins(), {
onSuccess: () => {
if (notifyLoad) {
notifyLoad();
}
},
onError: () => {
toggleNotification({
type: 'warning',
message: { id: 'notification.error', defaultMessage: 'An error occured' },
});
},
});
};

export default useFetchMarketplaceProviders;
@@ -0,0 +1,11 @@
import axios from 'axios';

const MARKETPLACE_API_URL = 'https://market-api.strapi.io';

const fetchMarketplacePlugins = async () => {
const { data } = await axios.get(`${MARKETPLACE_API_URL}/providers`);

return data;
};

export { fetchMarketplacePlugins };
Expand Up @@ -25,12 +25,18 @@ const EllipsisText = styled(Typography)`
overflow: hidden;
`;

const PluginCard = ({ plugin, installedPluginNames, useYarn, isInDevelopmentMode }) => {
const { attributes } = plugin;
const NpmPackageCard = ({
npmPackage,
installedPackageNames,
useYarn,
isInDevelopmentMode,
npmPackageType,
}) => {
const { attributes } = npmPackage;
const { formatMessage } = useIntl();
const { trackUsage } = useTracking();

const isInstalled = installedPluginNames.includes(attributes.npmPackageName);
const isInstalled = installedPackageNames.includes(attributes.npmPackageName);

const commandToCopy = useYarn
? `yarn add ${attributes.npmPackageName}`
Expand All @@ -41,6 +47,11 @@ const PluginCard = ({ plugin, installedPluginNames, useYarn, isInDevelopmentMode
defaultMessage: 'Made by Strapi',
});

const npmPackageHref =
npmPackageType === 'provider'
? attributes.npmPackageUrl
: `https://market.strapi.io/plugins/${attributes.slug}`;

return (
<Flex
direction="column"
Expand Down Expand Up @@ -107,7 +118,7 @@ const PluginCard = ({ plugin, installedPluginNames, useYarn, isInDevelopmentMode
<Stack horizontal spacing={2} style={{ alignSelf: 'flex-end' }} paddingTop={6}>
<LinkButton
size="S"
href={`https://market.strapi.io/plugins/${attributes.slug}`}
href={npmPackageHref}
isExternal
endIcon={<ExternalLink />}
aria-label={formatMessage(
Expand Down Expand Up @@ -135,12 +146,12 @@ const PluginCard = ({ plugin, installedPluginNames, useYarn, isInDevelopmentMode
);
};

PluginCard.defaultProps = {
NpmPackageCard.defaultProps = {
isInDevelopmentMode: false,
};

PluginCard.propTypes = {
plugin: PropTypes.shape({
NpmPackageCard.propTypes = {
npmPackage: PropTypes.shape({
id: PropTypes.string.isRequired,
attributes: PropTypes.shape({
name: PropTypes.string.isRequired,
Expand All @@ -153,12 +164,13 @@ PluginCard.propTypes = {
developerName: PropTypes.string.isRequired,
validated: PropTypes.bool.isRequired,
madeByStrapi: PropTypes.bool.isRequired,
strapiCompatibility: PropTypes.oneOf(['v3', 'v4']).isRequired,
strapiCompatibility: PropTypes.oneOf(['v3', 'v4']),
}).isRequired,
}).isRequired,
installedPluginNames: PropTypes.arrayOf(PropTypes.string).isRequired,
installedPackageNames: PropTypes.arrayOf(PropTypes.string).isRequired,
useYarn: PropTypes.bool.isRequired,
isInDevelopmentMode: PropTypes.bool,
npmPackageType: PropTypes.string.isRequired,
};

export default PluginCard;
export default NpmPackageCard;
@@ -0,0 +1,42 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Grid, GridItem } from '@strapi/design-system/Grid';
import NpmPackageCard from '../NpmPackageCard';

const NpmPackagesGrid = ({
npmPackages,
installedPackageNames,
useYarn,
isInDevelopmentMode,
npmPackageType,
}) => {
return (
<Grid gap={4}>
{npmPackages.map((npmPackage) => (
<GridItem col={4} s={6} xs={12} style={{ height: '100%' }} key={npmPackage.id}>
<NpmPackageCard
npmPackage={npmPackage}
installedPackageNames={installedPackageNames}
useYarn={useYarn}
isInDevelopmentMode={isInDevelopmentMode}
npmPackageType={npmPackageType}
/>
</GridItem>
))}
</Grid>
);
};

NpmPackagesGrid.defaultProps = {
installedPackageNames: [],
};

NpmPackagesGrid.propTypes = {
npmPackages: PropTypes.array.isRequired,
installedPackageNames: PropTypes.arrayOf(PropTypes.string),
useYarn: PropTypes.bool.isRequired,
isInDevelopmentMode: PropTypes.bool.isRequired,
npmPackageType: PropTypes.string.isRequired,
};

export default NpmPackagesGrid;
94 changes: 67 additions & 27 deletions packages/core/admin/admin/src/pages/MarketplacePage/index.js
Expand Up @@ -12,25 +12,26 @@ import {
useNotification,
useAppInfos,
} from '@strapi/helper-plugin';
import { Grid, GridItem } from '@strapi/design-system/Grid';
import { Layout, ContentLayout } from '@strapi/design-system/Layout';
import { Main } from '@strapi/design-system/Main';
import { Searchbar } from '@strapi/design-system/Searchbar';
import { Box } from '@strapi/design-system/Box';
import { useNotifyAT } from '@strapi/design-system/LiveRegions';
import { Typography } from '@strapi/design-system/Typography';
import { Flex } from '@strapi/design-system/Flex';
import { Tabs, Tab, TabGroup, TabPanels, TabPanel } from '@strapi/design-system/Tabs';

import PluginCard from './components/PluginCard';
import { EmptyPluginSearch } from './components/EmptyPluginSearch';
import PageHeader from './components/PageHeader';
import { fetchAppInformation } from './utils/api';
import useFetchInstalledPlugins from '../../hooks/useFetchInstalledPlugins';
import useFetchMarketplaceProviders from '../../hooks/useFetchMarketplaceProviders';
import useFetchMarketplacePlugins from '../../hooks/useFetchMarketplacePlugins';
import adminPermissions from '../../permissions';
import offlineCloud from '../../assets/images/icon_offline-cloud.svg';
import useNavigatorOnLine from '../../hooks/useNavigatorOnLine';
import MissingPluginBanner from './components/MissingPluginBanner';
import NpmPackagesGrid from './components/NpmPackagesGrid';

const matchSearch = (plugins, search) => {
return matchSorter(plugins, search, {
Expand Down Expand Up @@ -73,15 +74,14 @@ const MarketPlacePage = () => {
);
};

const {
status: marketplacePluginsStatus,
data: marketplacePluginsResponse,
} = useFetchMarketplacePlugins(notifyMarketplaceLoad);
const { status: marketplacePluginsStatus, data: marketplacePluginsResponse } =
useFetchMarketplacePlugins(notifyMarketplaceLoad);

const {
status: installedPluginsStatus,
data: installedPluginsResponse,
} = useFetchInstalledPlugins();
const { status: marketplaceProvidersStatus, data: marketplaceProvidersResponse } =
useFetchMarketplaceProviders(notifyMarketplaceLoad);

const { status: installedPluginsStatus, data: installedPluginsResponse } =
useFetchInstalledPlugins();

const { data: appInfoResponse, status: appInfoStatus } = useQuery(
'app-information',
Expand All @@ -96,13 +96,19 @@ const MarketPlacePage = () => {
}
);

const isLoading = [marketplacePluginsStatus, installedPluginsStatus, appInfoStatus].includes(
'loading'
);
const isLoading = [
marketplacePluginsStatus,
marketplaceProvidersStatus,
installedPluginsStatus,
appInfoStatus,
].includes('loading');

const hasFailed = [marketplacePluginsStatus, installedPluginsStatus, appInfoStatus].includes(
'error'
);
const hasFailed = [
marketplacePluginsStatus,
marketplaceProvidersStatus,
installedPluginsStatus,
appInfoStatus,
].includes('error');

useEffect(() => {
trackUsageRef.current('didGoToMarketplace');
Expand Down Expand Up @@ -180,7 +186,7 @@ const MarketPlacePage = () => {
}

const searchResults = matchSearch(marketplacePluginsResponse.data, searchQuery);
const installedPluginNames = installedPluginsResponse.plugins.map(plugin => plugin.packageName);
const installedPluginNames = installedPluginsResponse.plugins.map((plugin) => plugin.packageName);

return (
<Layout>
Expand All @@ -198,7 +204,7 @@ const MarketPlacePage = () => {
name="searchbar"
onClear={() => setSearchQuery('')}
value={searchQuery}
onChange={e => setSearchQuery(e.target.value)}
onChange={(e) => setSearchQuery(e.target.value)}
clearLabel={formatMessage({
id: 'admin.pages.MarketPlacePage.search.clear',
defaultMessage: 'Clear the plugin search',
Expand All @@ -225,18 +231,52 @@ const MarketPlacePage = () => {
)}
/>
) : (
<Grid gap={4}>
{searchResults.map(plugin => (
<GridItem col={4} s={6} xs={12} style={{ height: '100%' }} key={plugin.id}>
<PluginCard
plugin={plugin}
installedPluginNames={installedPluginNames}
<TabGroup
label={formatMessage({
id: 'admin.pages.MarketPlacePage.tab-group.label',
defaultMessage: 'Plugins and Providers for Strapi',
})}
id="tabs"
variant="simple"
>
<Box paddingBottom={4}>
<Tabs>
<Tab>
{formatMessage({
id: 'admin.pages.MarketPlacePage.plugins',
defaultMessage: 'Plugins',
})}{' '}
({searchResults.length})
</Tab>
<Tab>
{formatMessage({
id: 'admin.pages.MarketPlacePage.providers',
defaultMessage: 'Providers',
})}{' '}
({marketplaceProvidersResponse.data.length})
</Tab>
</Tabs>
</Box>
<TabPanels>
<TabPanel>
<NpmPackagesGrid
npmPackages={searchResults}
installedPackageNames={installedPluginNames}
useYarn={appInfoResponse.data.useYarn}
isInDevelopmentMode={isInDevelopmentMode}
npmPackageType="plugin"
/>
</TabPanel>
<TabPanel>
<NpmPackagesGrid
npmPackages={marketplaceProvidersResponse.data}
useYarn={appInfoResponse.data.useYarn}
isInDevelopmentMode={isInDevelopmentMode}
npmPackageType="provider"
/>
</GridItem>
))}
</Grid>
</TabPanel>
</TabPanels>
</TabGroup>
)}
<Box paddingTop={7}>
<MissingPluginBanner />
Expand Down

0 comments on commit 1b93931

Please sign in to comment.