@strapi/admin 4.2.0-beta.4 → 4.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/admin/src/app.js +4 -7
  2. package/admin/src/components/OverlayBlocker/index.js +4 -0
  3. package/admin/src/content-manager/components/Wysiwyg/EditorStylesContainer.js +1 -1
  4. package/admin/src/hooks/{useFetchInstalledPlugins → useFetchEnabledPlugins}/index.js +4 -4
  5. package/admin/src/hooks/{useFetchInstalledPlugins → useFetchEnabledPlugins}/utils/api.js +2 -2
  6. package/admin/src/hooks/useFetchMarketplaceProviders/index.js +23 -0
  7. package/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +11 -0
  8. package/admin/src/pages/Admin/index.js +5 -15
  9. package/admin/src/pages/App/index.js +3 -17
  10. package/admin/src/pages/InstalledPluginsPage/Plugins.js +2 -2
  11. package/admin/src/pages/MarketplacePage/components/{EmptyPluginSearch/EmptyPluginGrid.js → EmptyNpmPackageSearch/EmptyNpmPackageGrid.js} +1 -1
  12. package/admin/src/pages/MarketplacePage/components/{EmptyPluginSearch → EmptyNpmPackageSearch}/index.js +6 -4
  13. package/admin/src/pages/MarketplacePage/components/{PluginCard → NpmPackageCard}/InstallPluginButton.js +0 -0
  14. package/admin/src/pages/MarketplacePage/components/{PluginCard → NpmPackageCard}/index.js +22 -11
  15. package/admin/src/pages/MarketplacePage/components/NpmPackagesGrid/index.js +48 -0
  16. package/admin/src/pages/MarketplacePage/components/PageHeader/index.js +12 -5
  17. package/admin/src/pages/MarketplacePage/index.js +91 -59
  18. package/admin/src/reducers.js +2 -4
  19. package/admin/src/translations/en.json +7 -3
  20. package/admin/src/translations/hi.json +699 -0
  21. package/admin/src/translations/languageNativeNames.js +1 -0
  22. package/admin/src/translations/pl.json +335 -78
  23. package/admin/src/translations/vi.json +17 -17
  24. package/admin/src/translations/zh-Hans.json +28 -1
  25. package/build/1856.6a94980b.chunk.js +172 -0
  26. package/build/2077.5456ccd1.chunk.js +194 -0
  27. package/build/2758.9475712b.chunk.js +162 -0
  28. package/build/2912.dd031292.chunk.js +253 -0
  29. package/build/4715.a6e62860.chunk.js +385 -0
  30. package/build/4982.c57c5675.chunk.js +308 -0
  31. package/build/7197.74d81c4c.chunk.js +113 -0
  32. package/build/{6229.a5cca9f2.chunk.js → 7589.77ef4fbf.chunk.js} +2 -2
  33. package/build/{472.0350a5bd.chunk.js → 7757.f6eb5e92.chunk.js} +58 -58
  34. package/build/7841.9e9cf739.chunk.js +253 -0
  35. package/build/8681.2fd4020a.chunk.js +163 -0
  36. package/build/9066.2847fdff.chunk.js +101 -0
  37. package/build/{4073.e144a91a.chunk.js → 9115.623dc4f7.chunk.js} +1 -1
  38. package/build/9158.c5f772d6.chunk.js +503 -0
  39. package/build/{9298.aff28744.chunk.js → 9298.cb3b6bc1.chunk.js} +93 -93
  40. package/build/9420.ba035f29.chunk.js +508 -0
  41. package/build/Admin-authenticatedApp.2a22d6f4.chunk.js +80 -0
  42. package/build/{Admin_homePage.0ac648e8.chunk.js → Admin_homePage.447df176.chunk.js} +1 -1
  43. package/build/Admin_marketplace.0724f650.chunk.js +11 -0
  44. package/build/Admin_pluginsPage.6f1187fe.chunk.js +1 -0
  45. package/build/{Admin_profilePage.27191ed2.chunk.js → Admin_profilePage.249cbfc9.chunk.js} +2 -2
  46. package/build/Admin_settingsPage.0d138832.chunk.js +180 -0
  47. package/build/{admin-edit-roles-page.fb374555.chunk.js → admin-edit-roles-page.7c2c9752.chunk.js} +1 -1
  48. package/build/admin-edit-users.b835bc48.chunk.js +11 -0
  49. package/build/admin-users.19900b75.chunk.js +12 -0
  50. package/build/{api-tokens-create-page.698f132d.chunk.js → api-tokens-create-page.8d299dde.chunk.js} +1 -1
  51. package/build/{api-tokens-edit-page.afece2fe.chunk.js → api-tokens-edit-page.3e453fc1.chunk.js} +1 -1
  52. package/build/{api-tokens-list-page.46d96dee.chunk.js → api-tokens-list-page.872c3800.chunk.js} +1 -1
  53. package/build/{codemirror-css.b467b1de.chunk.js → codemirror-css.98490df3.chunk.js} +2 -2
  54. package/build/{codemirror-javacript.41bdefda.chunk.js → codemirror-javacript.cafbda9c.chunk.js} +1 -1
  55. package/build/codemirror-theme.b3c64617.chunk.js +34 -0
  56. package/build/{content-manager.7cd28f84.chunk.js → content-manager.18834aa8.chunk.js} +10 -10
  57. package/build/content-type-builder-translation-pl-json.4a42349b.chunk.js +1 -0
  58. package/build/content-type-builder.55dd9554.chunk.js +142 -0
  59. package/build/{cropper-css.ecc0d670.chunk.js → cropper-css.0055cd53.chunk.js} +2 -2
  60. package/build/email-settings-page.1f235173.chunk.js +103 -0
  61. package/build/email-translation-pl-json.a03bcf98.chunk.js +1 -0
  62. package/build/en-json.0a5ba154.chunk.js +1 -0
  63. package/build/{fontawesome-css-all.04f33619.chunk.js → fontawesome-css-all.b88d464e.chunk.js} +3 -3
  64. package/build/{fontawesome-css.477ba714.chunk.js → fontawesome-css.a92a7b6c.chunk.js} +2 -2
  65. package/build/hi-json.b4ae16d1.chunk.js +1 -0
  66. package/build/highlight.js.9d8ef460.chunk.js +86 -0
  67. package/build/i18n-settings-page.06e88cf2.chunk.js +101 -0
  68. package/build/i18n-translation-pl-json.cea5bf23.chunk.js +1 -0
  69. package/build/index.html +1 -1
  70. package/build/main.fcb539e3.js +8406 -0
  71. package/build/pl-json.4d11f53d.chunk.js +1 -0
  72. package/build/runtime~main.ade14a85.js +2 -0
  73. package/build/sso-settings-page.a7c2e854.chunk.js +1 -0
  74. package/build/upload-settings.4ee2f135.chunk.js +101 -0
  75. package/build/upload-translation-pl-json.bb2aa937.chunk.js +1 -0
  76. package/build/upload.0d4153e8.chunk.js +105 -0
  77. package/build/users-advanced-settings-page.583c5dda.chunk.js +101 -0
  78. package/build/users-email-settings-page.8b9a266d.chunk.js +1 -0
  79. package/build/users-permissions-translation-en-json.765abf48.chunk.js +1 -0
  80. package/build/users-permissions-translation-pl-json.1dbdd4a1.chunk.js +1 -0
  81. package/build/users-providers-settings-page.fc9d8f9d.chunk.js +1 -0
  82. package/build/{users-roles-settings-page.988ebc3b.chunk.js → users-roles-settings-page.1bf4ffc5.chunk.js} +2 -2
  83. package/build/vi-json.bf3424be.chunk.js +1 -0
  84. package/build/{webhook-edit-page.a7ae6e3b.chunk.js → webhook-edit-page.142b23ac.chunk.js} +2 -2
  85. package/build/webhook-list-page.671582a0.chunk.js +133 -0
  86. package/build/zh-Hans-json.562f3b6f.chunk.js +1 -0
  87. package/index.js +239 -53
  88. package/package.json +9 -11
  89. package/scripts/build.js +3 -17
  90. package/server/controllers/admin.js +2 -15
  91. package/server/policies/index.js +0 -1
  92. package/server/routes/admin.js +0 -9
  93. package/server/routes/serve-admin-panel.js +1 -1
  94. package/webpack.alias.js +30 -19
  95. package/webpack.config.js +9 -29
  96. package/admin/src/pages/App/constants.js +0 -1
  97. package/admin/src/pages/App/reducer.js +0 -22
  98. package/admin/src/pages/MarketplacePage/utils/api.js +0 -9
  99. package/admin/src/tsconfig.json +0 -10
  100. package/build/1541.6c1c96f9.chunk.js +0 -307
  101. package/build/1856.521a99fd.chunk.js +0 -172
  102. package/build/2077.51485bfb.chunk.js +0 -194
  103. package/build/2912.79c2b3c8.chunk.js +0 -253
  104. package/build/3214.9196aeff.chunk.js +0 -235
  105. package/build/3865.21cec9de.chunk.js +0 -310
  106. package/build/4715.77e04177.chunk.js +0 -385
  107. package/build/4982.f53b78a4.chunk.js +0 -308
  108. package/build/7351.b95e65ae.chunk.js +0 -428
  109. package/build/7418.6db737ce.chunk.js +0 -112
  110. package/build/7841.f0e7d629.chunk.js +0 -253
  111. package/build/8826.58e236d4.chunk.js +0 -1057
  112. package/build/9066.118ecccd.chunk.js +0 -101
  113. package/build/9420.cb0b75e8.chunk.js +0 -508
  114. package/build/9988.f84412d9.chunk.js +0 -162
  115. package/build/Admin-authenticatedApp.162a5805.chunk.js +0 -80
  116. package/build/Admin_marketplace.0bb91ec8.chunk.js +0 -11
  117. package/build/Admin_pluginsPage.788fb2f6.chunk.js +0 -1
  118. package/build/Admin_settingsPage.23e873f0.chunk.js +0 -178
  119. package/build/admin-edit-users.a360deaf.chunk.js +0 -10
  120. package/build/admin-users.47d06d24.chunk.js +0 -11
  121. package/build/codemirror-theme.cf9f9eb6.chunk.js +0 -34
  122. package/build/content-type-builder-translation-pl-json.a866acda.chunk.js +0 -1
  123. package/build/content-type-builder.7456cabe.chunk.js +0 -141
  124. package/build/email-settings-page.f67d13b2.chunk.js +0 -103
  125. package/build/email-translation-pl-json.6da50d0f.chunk.js +0 -1
  126. package/build/en-json.40ee00aa.chunk.js +0 -1
  127. package/build/highlight.js.3381ffc3.chunk.js +0 -86
  128. package/build/i18n-settings-page.6b67cb75.chunk.js +0 -101
  129. package/build/main.b632a0d6.js +0 -11625
  130. package/build/pl-json.94f05d2c.chunk.js +0 -1
  131. package/build/runtime~main.38d418e9.js +0 -2
  132. package/build/sso-settings-page.dfb0b917.chunk.js +0 -1
  133. package/build/upload-settings.3db55de0.chunk.js +0 -101
  134. package/build/upload-translation-pl-json.6071e38c.chunk.js +0 -1
  135. package/build/upload.070c189b.chunk.js +0 -105
  136. package/build/users-advanced-settings-page.a23cda17.chunk.js +0 -101
  137. package/build/users-email-settings-page.0a096388.chunk.js +0 -1
  138. package/build/users-permissions-translation-en-json.3fe86528.chunk.js +0 -1
  139. package/build/users-permissions-translation-pl-json.3c4fe81c.chunk.js +0 -1
  140. package/build/users-providers-settings-page.bfe7755a.chunk.js +0 -1
  141. package/build/vi-json.3d14e91e.chunk.js +0 -1
  142. package/build/webhook-list-page.83297d98.chunk.js +0 -133
  143. package/build/zh-Hans-json.c84ce330.chunk.js +0 -1
  144. package/server/policies/isTelemetryEnabled.js +0 -16
  145. package/utils/create-cache-dir.js +0 -161
  146. package/utils/get-custom-app-config-file.js +0 -23
  147. package/utils/get-custom-webpack-config.js +0 -38
  148. package/utils/get-plugins-path.js +0 -26
  149. package/utils/index.js +0 -13
  150. package/utils/should-build-admin.js +0 -52
  151. package/utils/watch-admin-files.js +0 -59
package/admin/src/app.js CHANGED
@@ -1,9 +1,6 @@
1
- const config = {
2
- locales: ['fr'],
3
- };
4
- const bootstrap = () => {};
5
-
6
1
  export default {
7
- config,
8
- bootstrap,
2
+ config: {
3
+ locales: ['fr'],
4
+ },
5
+ bootstrap() {},
9
6
  };
@@ -37,6 +37,10 @@ const Portal = ({ isOpen }) => {
37
37
  return null;
38
38
  };
39
39
 
40
+ Portal.propTypes = {
41
+ isOpen: PropTypes.bool.isRequired,
42
+ };
43
+
40
44
  const OverlayBlockerProvider = ({ children }) => {
41
45
  const [isOpen, setIsOpen] = useState(false);
42
46
 
@@ -16,7 +16,7 @@ export const EditorStylesContainer = styled.div`
16
16
  height: ${({ isExpandMode }) => (isExpandMode ? '100%' : '290px')};
17
17
  color: ${({ theme }) => theme.colors.neutral800};
18
18
  direction: ltr;
19
- font-family: --apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
19
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
20
20
  'Open Sans', 'Helvetica Neue', sans-serif;
21
21
  }
22
22
 
@@ -1,11 +1,11 @@
1
1
  import { useQuery } from 'react-query';
2
2
  import { useNotification } from '@strapi/helper-plugin';
3
- import { fetchInstalledPlugins } from './utils/api';
3
+ import { fetchEnabledPlugins } from './utils/api';
4
4
 
5
- const useFetchInstalledPlugins = notifyLoad => {
5
+ const useFetchEnabledPlugins = notifyLoad => {
6
6
  const toggleNotification = useNotification();
7
7
 
8
- return useQuery('list-installed-plugins', () => fetchInstalledPlugins(), {
8
+ return useQuery('list-enabled-plugins', () => fetchEnabledPlugins(), {
9
9
  onSuccess: () => {
10
10
  if (notifyLoad) {
11
11
  notifyLoad();
@@ -20,4 +20,4 @@ const useFetchInstalledPlugins = notifyLoad => {
20
20
  });
21
21
  };
22
22
 
23
- export default useFetchInstalledPlugins;
23
+ export default useFetchEnabledPlugins;
@@ -1,9 +1,9 @@
1
1
  import { axiosInstance } from '../../../core/utils';
2
2
 
3
- const fetchInstalledPlugins = async () => {
3
+ const fetchEnabledPlugins = async () => {
4
4
  const { data } = await axiosInstance.get('/admin/plugins');
5
5
 
6
6
  return data;
7
7
  };
8
8
 
9
- export { fetchInstalledPlugins };
9
+ export { fetchEnabledPlugins };
@@ -0,0 +1,23 @@
1
+ import { useQuery } from 'react-query';
2
+ import { useNotification } from '@strapi/helper-plugin';
3
+ import { fetchMarketplacePlugins } from './utils/api';
4
+
5
+ const useFetchMarketplaceProviders = (notifyLoad) => {
6
+ const toggleNotification = useNotification();
7
+
8
+ return useQuery('list-marketplace-providers', () => fetchMarketplacePlugins(), {
9
+ onSuccess: () => {
10
+ if (notifyLoad) {
11
+ notifyLoad();
12
+ }
13
+ },
14
+ onError: () => {
15
+ toggleNotification({
16
+ type: 'warning',
17
+ message: { id: 'notification.error', defaultMessage: 'An error occured' },
18
+ });
19
+ },
20
+ });
21
+ };
22
+
23
+ export default useFetchMarketplaceProviders;
@@ -0,0 +1,11 @@
1
+ import axios from 'axios';
2
+
3
+ const MARKETPLACE_API_URL = 'https://market-api.strapi.io';
4
+
5
+ const fetchMarketplacePlugins = async () => {
6
+ const { data } = await axios.get(`${MARKETPLACE_API_URL}/providers`);
7
+
8
+ return data;
9
+ };
10
+
11
+ export { fetchMarketplacePlugins };
@@ -6,17 +6,16 @@
6
6
 
7
7
  import React, { Suspense, useEffect, useMemo, lazy } from 'react';
8
8
  import { Switch, Route } from 'react-router-dom';
9
+ // Components from @strapi/helper-plugin
9
10
  import { useTracking, LoadingIndicatorPage, useStrapiApp } from '@strapi/helper-plugin';
10
- import { useDispatch, useSelector } from 'react-redux';
11
11
  import { DndProvider } from 'react-dnd';
12
12
  import { HTML5Backend } from 'react-dnd-html5-backend';
13
- import GuidedTourModal from '../../components/GuidedTour/Modal';
14
13
  import LeftMenu from '../../components/LeftMenu';
15
14
  import AppLayout from '../../layouts/AppLayout';
16
15
  import { useMenu } from '../../hooks';
17
- import { createRoute } from '../../utils';
18
- import { SET_APP_RUNTIME_STATUS } from '../App/constants';
19
16
  import Onboarding from './Onboarding';
17
+ import { createRoute } from '../../utils';
18
+ import GuidedTourModal from '../../components/GuidedTour/Modal';
20
19
 
21
20
  const CM = lazy(() =>
22
21
  import(/* webpackChunkName: "content-manager" */ '../../content-manager/pages/App')
@@ -41,20 +40,11 @@ const SettingsPage = lazy(() =>
41
40
  // Simple hook easier for testing
42
41
  const useTrackUsage = () => {
43
42
  const { trackUsage } = useTracking();
44
- const dispatch = useDispatch();
45
- const appStatus = useSelector(state => state.admin_app.status);
46
43
 
47
44
  useEffect(() => {
48
- // Make sure the event is only send once after accessing the admin panel
49
- // and not at runtime for example when regenerating the permissions with the ctb
50
- // or with i18n
51
- if (appStatus === 'init') {
52
- trackUsage('didAccessAuthenticatedAdministration');
53
-
54
- dispatch({ type: SET_APP_RUNTIME_STATUS });
55
- }
45
+ trackUsage('didAccessAuthenticatedAdministration');
56
46
  // eslint-disable-next-line react-hooks/exhaustive-deps
57
- }, [appStatus]);
47
+ }, []);
58
48
  };
59
49
 
60
50
  const Admin = () => {
@@ -14,7 +14,6 @@ import {
14
14
  TrackingContext,
15
15
  prefixFileUrlWithBackendUrl,
16
16
  } from '@strapi/helper-plugin';
17
- import axios from 'axios';
18
17
  import { SkipToContent } from '@strapi/design-system/Main';
19
18
  import { useIntl } from 'react-intl';
20
19
  import PrivateRoute from '../../components/PrivateRoute';
@@ -42,8 +41,6 @@ function App() {
42
41
  );
43
42
  }, []);
44
43
 
45
- const [telemetryProperties, setTelemetryProperties] = useState(null);
46
-
47
44
  useEffect(() => {
48
45
  const currentToken = auth.getToken();
49
46
 
@@ -72,20 +69,12 @@ function App() {
72
69
  const getData = async () => {
73
70
  try {
74
71
  const {
75
- data: {
76
- data: { hasAdmin, uuid, menuLogo },
77
- },
78
- } = await axios.get(`${strapi.backendURL}/admin/init`);
72
+ data: { hasAdmin, uuid, menuLogo },
73
+ } = await request('/admin/init', { method: 'GET' });
79
74
 
80
75
  updateProjectSettings({ menuLogo: prefixFileUrlWithBackendUrl(menuLogo) });
81
76
 
82
77
  if (uuid) {
83
- const {
84
- data: { data: properties },
85
- } = await axios.get(`${strapi.backendURL}/admin/telemetry-properties`);
86
-
87
- setTelemetryProperties(properties);
88
-
89
78
  try {
90
79
  const deviceId = await getUID();
91
80
 
@@ -95,9 +84,6 @@ function App() {
95
84
  event: 'didInitializeAdministration',
96
85
  uuid,
97
86
  deviceId,
98
- properties: {
99
- ...properties,
100
- },
101
87
  }),
102
88
  headers: {
103
89
  'Content-Type': 'application/json',
@@ -129,7 +115,7 @@ function App() {
129
115
  return (
130
116
  <Suspense fallback={<LoadingIndicatorPage />}>
131
117
  <SkipToContent>{formatMessage({ id: 'skipToContent' })}</SkipToContent>
132
- <TrackingContext.Provider value={{ uuid, telemetryProperties }}>
118
+ <TrackingContext.Provider value={uuid}>
133
119
  <Switch>
134
120
  {authRoutes}
135
121
  <Route
@@ -6,7 +6,7 @@ import { Layout, HeaderLayout, ContentLayout } from '@strapi/design-system/Layou
6
6
  import { Main } from '@strapi/design-system/Main';
7
7
  import { Typography } from '@strapi/design-system/Typography';
8
8
  import { Table, Thead, Tbody, Tr, Td, Th } from '@strapi/design-system/Table';
9
- import useFetchInstalledPlugins from '../../hooks/useFetchInstalledPlugins';
9
+ import useFetchEnabledPlugins from '../../hooks/useFetchEnabledPlugins';
10
10
 
11
11
  const Plugins = () => {
12
12
  const { formatMessage } = useIntl();
@@ -30,7 +30,7 @@ const Plugins = () => {
30
30
  );
31
31
  };
32
32
 
33
- const { status, data } = useFetchInstalledPlugins(notifyPluginPageLoad);
33
+ const { status, data } = useFetchEnabledPlugins(notifyPluginPageLoad);
34
34
 
35
35
  const isLoading = status !== 'success' && status !== 'error';
36
36
 
@@ -9,7 +9,7 @@ const EmptyPluginCard = styled(Box)`
9
9
  opacity: 0.33;
10
10
  `;
11
11
 
12
- export const EmptyPluginGrid = () => {
12
+ export const EmptyNpmPackageGrid = () => {
13
13
  return (
14
14
  <GridLayout>
15
15
  {Array(12)
@@ -5,12 +5,12 @@ import { Box } from '@strapi/design-system/Box';
5
5
  import { Flex } from '@strapi/design-system/Flex';
6
6
  import { Icon } from '@strapi/design-system/Icon';
7
7
  import EmptyStateDocument from '@strapi/icons/EmptyDocuments';
8
- import { EmptyPluginGrid } from './EmptyPluginGrid';
8
+ import { EmptyNpmPackageGrid } from './EmptyNpmPackageGrid';
9
9
 
10
- export const EmptyPluginSearch = ({ content }) => {
10
+ const EmptyNpmPackageSearch = ({ content }) => {
11
11
  return (
12
12
  <Box position="relative">
13
- <EmptyPluginGrid />
13
+ <EmptyNpmPackageGrid />
14
14
  <Box position="absolute" top={11} width="100%">
15
15
  <Flex alignItems="center" justifyContent="center" direction="column">
16
16
  <Icon as={EmptyStateDocument} color="" width="160px" height="88px" />
@@ -25,6 +25,8 @@ export const EmptyPluginSearch = ({ content }) => {
25
25
  );
26
26
  };
27
27
 
28
- EmptyPluginSearch.propTypes = {
28
+ EmptyNpmPackageSearch.propTypes = {
29
29
  content: PropTypes.string.isRequired,
30
30
  };
31
+
32
+ export default EmptyNpmPackageSearch;
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { useIntl } from 'react-intl';
4
4
  import styled from 'styled-components';
5
+ import pluralize from 'pluralize';
5
6
  import { Box } from '@strapi/design-system/Box';
6
7
  import { Stack } from '@strapi/design-system/Stack';
7
8
  import { Typography } from '@strapi/design-system/Typography';
@@ -25,13 +26,17 @@ const EllipsisText = styled(Typography)`
25
26
  overflow: hidden;
26
27
  `;
27
28
 
28
- const PluginCard = ({ plugin, installedPluginNames, useYarn, isInDevelopmentMode }) => {
29
- const { attributes } = plugin;
29
+ const NpmPackageCard = ({
30
+ npmPackage,
31
+ isInstalled,
32
+ useYarn,
33
+ isInDevelopmentMode,
34
+ npmPackageType,
35
+ }) => {
36
+ const { attributes } = npmPackage;
30
37
  const { formatMessage } = useIntl();
31
38
  const { trackUsage } = useTracking();
32
39
 
33
- const isInstalled = installedPluginNames.includes(attributes.npmPackageName);
34
-
35
40
  const commandToCopy = useYarn
36
41
  ? `yarn add ${attributes.npmPackageName}`
37
42
  : `npm install ${attributes.npmPackageName}`;
@@ -41,6 +46,10 @@ const PluginCard = ({ plugin, installedPluginNames, useYarn, isInDevelopmentMode
41
46
  defaultMessage: 'Made by Strapi',
42
47
  });
43
48
 
49
+ const npmPackageHref = `https://market.strapi.io/${pluralize.plural(npmPackageType)}/${
50
+ attributes.slug
51
+ }`;
52
+
44
53
  return (
45
54
  <Flex
46
55
  direction="column"
@@ -54,6 +63,7 @@ const PluginCard = ({ plugin, installedPluginNames, useYarn, isInDevelopmentMode
54
63
  shadow="tableShadow"
55
64
  height="100%"
56
65
  alignItems="normal"
66
+ data-testid="npm-package-card"
57
67
  >
58
68
  <Box>
59
69
  <Box
@@ -107,7 +117,7 @@ const PluginCard = ({ plugin, installedPluginNames, useYarn, isInDevelopmentMode
107
117
  <Stack horizontal spacing={2} style={{ alignSelf: 'flex-end' }} paddingTop={6}>
108
118
  <LinkButton
109
119
  size="S"
110
- href={`https://market.strapi.io/plugins/${attributes.slug}`}
120
+ href={npmPackageHref}
111
121
  isExternal
112
122
  endIcon={<ExternalLink />}
113
123
  aria-label={formatMessage(
@@ -135,12 +145,12 @@ const PluginCard = ({ plugin, installedPluginNames, useYarn, isInDevelopmentMode
135
145
  );
136
146
  };
137
147
 
138
- PluginCard.defaultProps = {
148
+ NpmPackageCard.defaultProps = {
139
149
  isInDevelopmentMode: false,
140
150
  };
141
151
 
142
- PluginCard.propTypes = {
143
- plugin: PropTypes.shape({
152
+ NpmPackageCard.propTypes = {
153
+ npmPackage: PropTypes.shape({
144
154
  id: PropTypes.string.isRequired,
145
155
  attributes: PropTypes.shape({
146
156
  name: PropTypes.string.isRequired,
@@ -153,12 +163,13 @@ PluginCard.propTypes = {
153
163
  developerName: PropTypes.string.isRequired,
154
164
  validated: PropTypes.bool.isRequired,
155
165
  madeByStrapi: PropTypes.bool.isRequired,
156
- strapiCompatibility: PropTypes.oneOf(['v3', 'v4']).isRequired,
166
+ strapiCompatibility: PropTypes.oneOf(['v3', 'v4']),
157
167
  }).isRequired,
158
168
  }).isRequired,
159
- installedPluginNames: PropTypes.arrayOf(PropTypes.string).isRequired,
169
+ isInstalled: PropTypes.bool.isRequired,
160
170
  useYarn: PropTypes.bool.isRequired,
161
171
  isInDevelopmentMode: PropTypes.bool,
172
+ npmPackageType: PropTypes.string.isRequired,
162
173
  };
163
174
 
164
- export default PluginCard;
175
+ export default NpmPackageCard;
@@ -0,0 +1,48 @@
1
+ import React, { useCallback } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Grid, GridItem } from '@strapi/design-system/Grid';
4
+ import NpmPackageCard from '../NpmPackageCard';
5
+
6
+ const NpmPackagesGrid = ({
7
+ npmPackages,
8
+ installedPackageNames,
9
+ useYarn,
10
+ isInDevelopmentMode,
11
+ npmPackageType,
12
+ }) => {
13
+ // Check if an individual package is in the dependencies
14
+ const isAlreadyInstalled = useCallback(
15
+ npmPackageName => installedPackageNames.includes(npmPackageName),
16
+ [installedPackageNames]
17
+ );
18
+
19
+ return (
20
+ <Grid gap={4}>
21
+ {npmPackages.map(npmPackage => (
22
+ <GridItem col={4} s={6} xs={12} style={{ height: '100%' }} key={npmPackage.id}>
23
+ <NpmPackageCard
24
+ npmPackage={npmPackage}
25
+ isInstalled={isAlreadyInstalled(npmPackage.attributes.npmPackageName)}
26
+ useYarn={useYarn}
27
+ isInDevelopmentMode={isInDevelopmentMode}
28
+ npmPackageType={npmPackageType}
29
+ />
30
+ </GridItem>
31
+ ))}
32
+ </Grid>
33
+ );
34
+ };
35
+
36
+ NpmPackagesGrid.defaultProps = {
37
+ installedPackageNames: [],
38
+ };
39
+
40
+ NpmPackagesGrid.propTypes = {
41
+ npmPackages: PropTypes.array.isRequired,
42
+ installedPackageNames: PropTypes.arrayOf(PropTypes.string),
43
+ useYarn: PropTypes.bool.isRequired,
44
+ isInDevelopmentMode: PropTypes.bool.isRequired,
45
+ npmPackageType: PropTypes.string.isRequired,
46
+ };
47
+
48
+ export default NpmPackagesGrid;
@@ -6,10 +6,12 @@ import { LinkButton } from '@strapi/design-system/v2/LinkButton';
6
6
  import Upload from '@strapi/icons/Upload';
7
7
  import { useTracking } from '@strapi/helper-plugin';
8
8
 
9
- const PageHeader = ({ isOnline }) => {
9
+ const PageHeader = ({ isOnline, npmPackageType }) => {
10
10
  const { formatMessage } = useIntl();
11
11
  const { trackUsage } = useTracking();
12
12
 
13
+ const tracking = npmPackageType === 'provider' ? 'didSubmitProvider' : 'didSubmitPlugin';
14
+
13
15
  return (
14
16
  <HeaderLayout
15
17
  title={formatMessage({
@@ -25,13 +27,13 @@ const PageHeader = ({ isOnline }) => {
25
27
  <LinkButton
26
28
  startIcon={<Upload />}
27
29
  variant="tertiary"
28
- href="https://market.strapi.io/submit-plugin"
29
- onClick={() => trackUsage('didSubmitPlugin')}
30
+ href={`https://market.strapi.io/submit-${npmPackageType}`}
31
+ onClick={() => trackUsage(tracking)}
30
32
  isExternal
31
33
  >
32
34
  {formatMessage({
33
- id: 'admin.pages.MarketPlacePage.submit.plugin.link',
34
- defaultMessage: 'Submit your plugin',
35
+ id: `admin.pages.MarketPlacePage.submit.${npmPackageType}.link`,
36
+ defaultMessage: `Submit ${npmPackageType}`,
35
37
  })}
36
38
  </LinkButton>
37
39
  )
@@ -42,6 +44,11 @@ const PageHeader = ({ isOnline }) => {
42
44
 
43
45
  export default PageHeader;
44
46
 
47
+ PageHeader.defaultProps = {
48
+ npmPackageType: 'plugin',
49
+ };
50
+
45
51
  PageHeader.propTypes = {
46
52
  isOnline: PropTypes.bool.isRequired,
53
+ npmPackageType: PropTypes.string,
47
54
  };