@strapi/admin 4.2.0-alpha.7 → 4.2.0-alpha.8

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 (42) hide show
  1. package/admin/src/assets/images/icon_made-by-strapi.svg +5 -0
  2. package/admin/src/components/PrivateRoute/index.js +23 -17
  3. package/admin/src/hooks/index.js +0 -1
  4. package/admin/src/hooks/useFetchInstalledPlugins/index.js +23 -0
  5. package/admin/src/{pages/InstalledPluginsPage → hooks/useFetchInstalledPlugins}/utils/api.js +2 -4
  6. package/admin/src/hooks/useFetchMarketplacePlugins/index.js +23 -0
  7. package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +17 -0
  8. package/admin/src/pages/AuthPage/index.js +22 -5
  9. package/admin/src/pages/InstalledPluginsPage/Plugins.js +6 -15
  10. package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/EmptyPluginGrid.js +27 -0
  11. package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/index.js +30 -0
  12. package/admin/src/pages/MarketplacePage/components/PluginCard/index.js +186 -0
  13. package/admin/src/pages/MarketplacePage/index.js +199 -107
  14. package/admin/src/pages/MarketplacePage/utils/api.js +9 -0
  15. package/admin/src/translations/en.json +16 -13
  16. package/build/4362.91a4253f.chunk.js +1 -0
  17. package/build/90f49a385afb000fb1d4.svg +5 -0
  18. package/build/{Admin-authenticatedApp.0b6b5c7e.chunk.js → Admin-authenticatedApp.187bd266.chunk.js} +1 -1
  19. package/build/Admin_marketplace.89a0a014.chunk.js +1 -0
  20. package/build/Admin_pluginsPage.97a514db.chunk.js +1 -0
  21. package/build/admin-users.2740c223.chunk.js +1 -0
  22. package/build/en-json.73a610d6.chunk.js +1 -0
  23. package/build/index.html +1 -1
  24. package/build/{main.1f025df1.js → main.c12537d5.js} +2 -2
  25. package/build/{main.1f025df1.js.LICENSE.txt → main.c12537d5.js.LICENSE.txt} +0 -0
  26. package/build/{runtime~main.53294538.js → runtime~main.e5240b25.js} +1 -1
  27. package/package.json +5 -5
  28. package/server/controllers/admin.js +12 -1
  29. package/.env +0 -0
  30. package/admin/src/hooks/useFetchPluginsFromMarketPlace/index.js +0 -49
  31. package/admin/src/pages/MarketplacePage/MarketplaceBanner/Wrapper.js +0 -28
  32. package/admin/src/pages/MarketplacePage/MarketplaceBanner/index.js +0 -37
  33. package/admin/src/pages/MarketplacePage/PluginCard/Wrapper.js +0 -148
  34. package/admin/src/pages/MarketplacePage/PluginCard/index.js +0 -185
  35. package/admin/src/pages/MarketplacePage/Wrapper.js +0 -5
  36. package/admin/src/pages/MarketplacePage/assets/marketplace-coming-soon.png +0 -0
  37. package/build/01a600d9e6e0dea21e33.png +0 -0
  38. package/build/4362.ce36d91a.chunk.js +0 -1
  39. package/build/Admin_marketplace.419010d8.chunk.js +0 -1
  40. package/build/Admin_pluginsPage.7d1bd7ce.chunk.js +0 -1
  41. package/build/admin-users.1fda1f27.chunk.js +0 -1
  42. package/build/en-json.98c7c4be.chunk.js +0 -1
@@ -1,127 +1,219 @@
1
- import React, { useEffect } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
2
  import { useIntl } from 'react-intl';
3
- import styled from 'styled-components';
4
3
  import { Helmet } from 'react-helmet';
5
- import { pxToRem, CheckPagePermissions, useTracking } from '@strapi/helper-plugin';
4
+ import { useQuery } from 'react-query';
5
+ import matchSorter from 'match-sorter';
6
+ import {
7
+ AnErrorOccurred,
8
+ CheckPagePermissions,
9
+ useFocusWhenNavigate,
10
+ useTracking,
11
+ LoadingIndicatorPage,
12
+ useNotification,
13
+ } from '@strapi/helper-plugin';
14
+ import { Grid, GridItem } from '@strapi/design-system/Grid';
6
15
  import { Layout, HeaderLayout, ContentLayout } from '@strapi/design-system/Layout';
7
- import { Flex } from '@strapi/design-system/Flex';
16
+ import { Main } from '@strapi/design-system/Main';
17
+ import { Searchbar } from '@strapi/design-system/Searchbar';
8
18
  import { Box } from '@strapi/design-system/Box';
9
- import { Stack } from '@strapi/design-system/Stack';
10
19
  import { LinkButton } from '@strapi/design-system/LinkButton';
11
- import { Main } from '@strapi/design-system/Main';
12
- import { Typography } from '@strapi/design-system/Typography';
13
- import ExternalLink from '@strapi/icons/ExternalLink';
14
- import adminPermissions from '../../permissions';
15
- import MarketplacePicture from './assets/marketplace-coming-soon.png';
16
-
17
- const CenterTypography = styled(Typography)`
18
- text-align: center;
19
- `;
20
+ import { useNotifyAT } from '@strapi/design-system/LiveRegions';
21
+ import Upload from '@strapi/icons/Upload';
20
22
 
21
- const Img = styled.img`
22
- width: ${190 / 16}rem;
23
- `;
23
+ import PluginCard from './components/PluginCard';
24
+ import { EmptyPluginSearch } from './components/EmptyPluginSearch';
25
+ import { fetchAppInformation } from './utils/api';
26
+ import useFetchInstalledPlugins from '../../hooks/useFetchInstalledPlugins';
27
+ import useFetchMarketplacePlugins from '../../hooks/useFetchMarketplacePlugins';
28
+ import adminPermissions from '../../permissions';
24
29
 
25
- const StackCentered = styled(Stack)`
26
- align-items: center;
27
- `;
30
+ const matchSearch = (plugins, search) => {
31
+ return matchSorter(plugins, search, {
32
+ keys: [
33
+ {
34
+ threshold: matchSorter.rankings.WORD_STARTS_WITH,
35
+ key: 'attributes.name',
36
+ },
37
+ { threshold: matchSorter.rankings.WORD_STARTS_WITH, key: 'attributes.description' },
38
+ ],
39
+ });
40
+ };
28
41
 
29
42
  const MarketPlacePage = () => {
30
43
  const { formatMessage } = useIntl();
31
44
  const { trackUsage } = useTracking();
45
+ const { notifyStatus } = useNotifyAT();
46
+ const trackUsageRef = useRef(trackUsage);
47
+ const toggleNotification = useNotification();
48
+ const [searchQuery, setSearchQuery] = useState('');
49
+
50
+ useFocusWhenNavigate();
51
+
52
+ const marketplaceTitle = formatMessage({
53
+ id: 'admin.pages.MarketPlacePage.title',
54
+ defaultMessage: 'Marketplace',
55
+ });
56
+
57
+ const notifyMarketplaceLoad = () => {
58
+ notifyStatus(
59
+ formatMessage(
60
+ {
61
+ id: 'app.utils.notify.data-loaded',
62
+ defaultMessage: 'The {target} has loaded',
63
+ },
64
+ { target: marketplaceTitle }
65
+ )
66
+ );
67
+ };
68
+
69
+ const {
70
+ status: marketplacePluginsStatus,
71
+ data: marketplacePluginsResponse,
72
+ } = useFetchMarketplacePlugins(notifyMarketplaceLoad);
73
+
74
+ const {
75
+ status: installedPluginsStatus,
76
+ data: installedPluginsResponse,
77
+ } = useFetchInstalledPlugins();
78
+
79
+ const { data: appInfoResponse, status: appInfoStatus } = useQuery(
80
+ 'app-information',
81
+ fetchAppInformation,
82
+ {
83
+ onError: () => {
84
+ toggleNotification({
85
+ type: 'warning',
86
+ message: { id: 'notification.error', defaultMessage: 'An error occured' },
87
+ });
88
+ },
89
+ }
90
+ );
91
+
92
+ const isLoading = [marketplacePluginsStatus, installedPluginsStatus, appInfoStatus].includes(
93
+ 'loading'
94
+ );
95
+
96
+ const hasFailed = [marketplacePluginsStatus, installedPluginsStatus, appInfoStatus].includes(
97
+ 'error'
98
+ );
32
99
 
33
100
  useEffect(() => {
34
- trackUsage('didGoToMarketplace');
35
- }, [trackUsage]);
101
+ trackUsageRef.current('didGoToMarketplace');
102
+ }, []);
36
103
 
37
- return (
38
- <CheckPagePermissions permissions={adminPermissions.marketplace.main}>
104
+ if (hasFailed) {
105
+ return (
39
106
  <Layout>
40
- <Main>
41
- <Helmet
42
- title={formatMessage({
43
- id: 'admin.pages.MarketPlacePage.helmet',
44
- defaultMessage: 'Marketplace - Plugins',
45
- })}
46
- />
47
- <HeaderLayout
48
- title={formatMessage({
49
- id: 'admin.pages.MarketPlacePage.title',
50
- defaultMessage: 'Marketplace',
51
- })}
52
- subtitle={formatMessage({
53
- id: 'admin.pages.MarketPlacePage.subtitle',
54
- defaultMessage: 'Get more out of Strapi',
55
- })}
56
- />
57
- <ContentLayout>
58
- <StackCentered
59
- spacing={0}
60
- hasRadius
61
- background="neutral0"
62
- shadow="tableShadow"
63
- paddingTop={10}
64
- paddingBottom={10}
65
- >
66
- <Box paddingBottom={7}>
67
- <Img
68
- alt={formatMessage({
69
- id: 'admin.pages.MarketPlacePage.illustration',
70
- defaultMessage: 'marketplace illustration',
71
- })}
72
- src={MarketplacePicture}
73
- />
74
- </Box>
75
- <Typography variant="alpha">
76
- {formatMessage({
77
- id: 'admin.pages.MarketPlacePage.coming-soon.1',
78
- defaultMessage: 'A new way to make Strapi awesome.',
79
- })}
80
- </Typography>
81
- <Typography variant="alpha" textColor="primary700">
82
- {formatMessage({
83
- id: 'admin.pages.MarketPlacePage.published',
84
- defaultMessage: 'Finally here.',
85
- })}
86
- </Typography>
87
- <Flex maxWidth={pxToRem(620)} paddingTop={3}>
88
- <CenterTypography variant="epsilon" textColor="neutral600">
89
- {formatMessage({
90
- id: 'admin.pages.MarketPlacePage.content.subtitle.published',
91
- defaultMessage:
92
- 'The web marketplace helps you get the most of Strapi. In addition, we are working hard to offer the best experience to discover and install plugins, directly from the app.',
93
- })}
94
- </CenterTypography>
95
- </Flex>
96
- <Stack paddingTop={6} horizontal spacing={2}>
97
- <LinkButton
98
- href="https://market.strapi.io"
99
- size="L"
100
- variant="primary"
101
- endIcon={<ExternalLink />}
102
- >
103
- {formatMessage({
104
- id: 'admin.pages.MarketPlacePage.submit.market.link',
105
- defaultMessage: 'Visit the web marketplace',
106
- })}
107
- </LinkButton>
108
- <LinkButton
109
- href="https://market.strapi.io/submit-plugin"
110
- size="L"
111
- variant="secondary"
112
- >
113
- {formatMessage({
114
- id: 'admin.pages.MarketPlacePage.submit.plugin.link',
115
- defaultMessage: 'Submit your plugin',
116
- })}
117
- </LinkButton>
118
- </Stack>
119
- </StackCentered>
120
- </ContentLayout>
107
+ <ContentLayout>
108
+ <Box paddingTop={8}>
109
+ <AnErrorOccurred />
110
+ </Box>
111
+ </ContentLayout>
112
+ </Layout>
113
+ );
114
+ }
115
+
116
+ if (isLoading) {
117
+ return (
118
+ <Layout>
119
+ <Main aria-busy>
120
+ <LoadingIndicatorPage />
121
121
  </Main>
122
122
  </Layout>
123
- </CheckPagePermissions>
123
+ );
124
+ }
125
+
126
+ const searchResults = matchSearch(marketplacePluginsResponse.data, searchQuery);
127
+ const installedPluginNames = installedPluginsResponse.plugins.map(plugin => plugin.packageName);
128
+
129
+ return (
130
+ <Layout>
131
+ <Main>
132
+ <Helmet
133
+ title={formatMessage({
134
+ id: 'admin.pages.MarketPlacePage.helmet',
135
+ defaultMessage: 'Marketplace - Plugins',
136
+ })}
137
+ />
138
+ <HeaderLayout
139
+ title={formatMessage({
140
+ id: 'admin.pages.MarketPlacePage.title',
141
+ defaultMessage: 'Marketplace',
142
+ })}
143
+ subtitle={formatMessage({
144
+ id: 'admin.pages.MarketPlacePage.subtitle',
145
+ defaultMessage: 'Get more out of Strapi',
146
+ })}
147
+ primaryAction={
148
+ <LinkButton
149
+ startIcon={<Upload />}
150
+ variant="tertiary"
151
+ href="https://market.strapi.io/submit-plugin"
152
+ onClick={() => trackUsage('didSubmitPlugin')}
153
+ >
154
+ {formatMessage({
155
+ id: 'admin.pages.MarketPlacePage.submit.plugin.link',
156
+ defaultMessage: 'Submit your plugin',
157
+ })}
158
+ </LinkButton>
159
+ }
160
+ />
161
+ <ContentLayout>
162
+ <Box width="25%" paddingBottom={4}>
163
+ <Searchbar
164
+ name="searchbar"
165
+ onClear={() => setSearchQuery('')}
166
+ value={searchQuery}
167
+ onChange={e => setSearchQuery(e.target.value)}
168
+ clearLabel={formatMessage({
169
+ id: 'admin.pages.MarketPlacePage.search.clear',
170
+ defaultMessage: 'Clear the plugin search',
171
+ })}
172
+ placeholder={formatMessage({
173
+ id: 'admin.pages.MarketPlacePage.search.placeholder',
174
+ defaultMessage: 'Search for a plugin',
175
+ })}
176
+ >
177
+ {formatMessage({
178
+ id: 'admin.pages.MarketPlacePage.search.placeholder',
179
+ defaultMessage: 'Search for a plugin',
180
+ })}
181
+ </Searchbar>
182
+ </Box>
183
+ {searchQuery.length > 0 && !searchResults.length ? (
184
+ <EmptyPluginSearch
185
+ content={formatMessage(
186
+ {
187
+ id: 'admin.pages.MarketPlacePage.search.empty',
188
+ defaultMessage: 'No result for "{target}"',
189
+ },
190
+ { target: searchQuery }
191
+ )}
192
+ />
193
+ ) : (
194
+ <Grid gap={4}>
195
+ {searchResults.map(plugin => (
196
+ <GridItem col={4} s={6} xs={12} style={{ height: '100%' }} key={plugin.id}>
197
+ <PluginCard
198
+ plugin={plugin}
199
+ installedPluginNames={installedPluginNames}
200
+ useYarn={appInfoResponse.data.useYarn}
201
+ />
202
+ </GridItem>
203
+ ))}
204
+ </Grid>
205
+ )}
206
+ </ContentLayout>
207
+ </Main>
208
+ </Layout>
124
209
  );
125
210
  };
126
211
 
127
- export default MarketPlacePage;
212
+ const ProtectedMarketPlace = () => (
213
+ <CheckPagePermissions permissions={adminPermissions.marketplace.main}>
214
+ <MarketPlacePage />
215
+ </CheckPagePermissions>
216
+ );
217
+
218
+ export { MarketPlacePage };
219
+ export default ProtectedMarketPlace;
@@ -0,0 +1,9 @@
1
+ import { axiosInstance } from '../../../core/utils';
2
+
3
+ const fetchAppInformation = async () => {
4
+ const { data } = await axiosInstance.get('/admin/information');
5
+
6
+ return data;
7
+ };
8
+
9
+ export { fetchAppInformation };
@@ -58,6 +58,21 @@
58
58
  "Auth.privacy-policy-agreement.policy": "privacy policy",
59
59
  "Auth.privacy-policy-agreement.terms": "terms",
60
60
  "Auth.reset-password.title": "Reset password",
61
+ "admin.pages.MarketPlacePage.helmet": "Marketplace - Plugins",
62
+ "admin.pages.MarketPlacePage.title": "Marketplace",
63
+ "admin.pages.MarketPlacePage.subtitle": "Get more out of Strapi",
64
+ "admin.pages.MarketPlacePage.plugin.info.text": "Learn more",
65
+ "admin.pages.MarketPlacePage.plugin.info.label": "Learn more about {pluginName}",
66
+ "admin.pages.MarketPlacePage.plugin.copy": "Copy install command",
67
+ "admin.pages.MarketPlacePage.plugin.copy.success": "Install command ready to be pasted in your terminal",
68
+ "admin.pages.MarketPlacePage.plugin.installed": "Installed",
69
+ "admin.pages.MarketPlacePage.plugin.info": "Learn more",
70
+ "admin.pages.MarketPlacePage.submit.plugin.link": "Submit your plugin",
71
+ "admin.pages.MarketPlacePage.plugin.tooltip.verified": "Plugin verified by Strapi",
72
+ "admin.pages.MarketPlacePage.search.placeholder": "Search for a plugin",
73
+ "admin.pages.MarketPlacePage.search.clear": "Clear the plugin search",
74
+ "admin.pages.MarketPlacePage.search.empty": "No result for \"{target}\"",
75
+ "admin.pages.MarketPlacePage.plugin.tooltip.madeByStrapi": "Made by Strapi",
61
76
  "Content Manager": "Content Manager",
62
77
  "Content Type Builder": "Content-Types Builder",
63
78
  "Documentation": "Documentation",
@@ -230,18 +245,6 @@
230
245
  "Users.components.List.empty": "There is no users...",
231
246
  "Users.components.List.empty.withFilters": "There is no users with the applied filters...",
232
247
  "Users.components.List.empty.withSearch": "There is no users corresponding to the search ({search})...",
233
- "admin.pages.MarketPlacePage.blog.link": "Read our blog post",
234
- "admin.pages.MarketPlacePage.coming-soon.1": "A new way to make Strapi awesome.",
235
- "admin.pages.MarketPlacePage.coming-soon.2": "Coming soon.",
236
- "admin.pages.MarketPlacePage.content.subtitle": "The new marketplace will help you get more out of Strapi. We are working hard to offer the best experience to discover and install plugins.",
237
- "admin.pages.MarketPlacePage.content.subtitle.published": "The web marketplace helps you get the most of Strapi. In addition, we are working hard to offer the best experience to discover and install plugins, directly from the app.",
238
- "admin.pages.MarketPlacePage.helmet": "Marketplace - Plugins",
239
- "admin.pages.MarketPlacePage.illustration": "marketplace illustration",
240
- "admin.pages.MarketPlacePage.market.link": "Visit the web marketplace",
241
- "admin.pages.MarketPlacePage.published": "Finally here.",
242
- "admin.pages.MarketPlacePage.submit.plugin.link": "Submit your plugin",
243
- "admin.pages.MarketPlacePage.subtitle": "Get more out of Strapi",
244
- "admin.pages.MarketPlacePage.title": "Marketplace",
245
248
  "anErrorOccurred": "Woops! Something went wrong. Please, try again.",
246
249
  "app.components.GuidedTour.skip": "Skip the tour",
247
250
  "app.components.GuidedTour.title": "3 steps to get started",
@@ -704,4 +707,4 @@
704
707
  "request.error.model.unknown": "This model doesn't exist",
705
708
  "skipToContent": "Skip to content",
706
709
  "submit": "Submit"
707
- }
710
+ }