@strapi/admin 4.2.0-alpha.O → 4.2.0-beta.0

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 (80) hide show
  1. package/admin/src/app.js +7 -4
  2. package/admin/src/assets/images/icon_made-by-strapi.svg +5 -0
  3. package/admin/src/components/AuthenticatedApp/index.js +9 -2
  4. package/admin/src/components/AuthenticatedApp/utils/api.js +20 -1
  5. package/admin/src/components/GuidedTour/Homepage/index.js +13 -3
  6. package/admin/src/components/GuidedTour/Modal/index.js +4 -1
  7. package/admin/src/components/GuidedTour/layout.js +9 -0
  8. package/admin/src/components/PrivateRoute/index.js +23 -17
  9. package/admin/src/content-manager/components/DynamicZone/components/ComponentPicker/Category/index.js +4 -1
  10. package/admin/src/content-manager/components/Inputs/index.js +3 -4
  11. package/admin/src/content-manager/components/SelectWrapper/utils/getSelectStyles.js +2 -1
  12. package/admin/src/content-manager/pages/EditView/index.js +0 -188
  13. package/admin/src/hooks/index.js +0 -1
  14. package/admin/src/hooks/useFetchInstalledPlugins/index.js +23 -0
  15. package/admin/src/{pages/InstalledPluginsPage → hooks/useFetchInstalledPlugins}/utils/api.js +2 -4
  16. package/admin/src/hooks/useFetchMarketplacePlugins/index.js +23 -0
  17. package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +17 -0
  18. package/admin/src/pages/Admin/index.js +1 -3
  19. package/admin/src/pages/AuthPage/index.js +28 -5
  20. package/admin/src/pages/InstalledPluginsPage/Plugins.js +6 -15
  21. package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/EmptyPluginGrid.js +27 -0
  22. package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/index.js +30 -0
  23. package/admin/src/pages/MarketplacePage/components/PluginCard/index.js +186 -0
  24. package/admin/src/pages/MarketplacePage/index.js +199 -107
  25. package/admin/src/pages/MarketplacePage/utils/api.js +9 -0
  26. package/admin/src/translations/en.json +18 -15
  27. package/admin/src/translations/ja.json +2 -2
  28. package/admin/src/translations/ko.json +2 -2
  29. package/admin/src/translations/vi.json +30 -4
  30. package/build/4362.b3d67035.chunk.js +1 -0
  31. package/build/90f49a385afb000fb1d4.svg +5 -0
  32. package/build/9260.4233fae2.chunk.js +2 -0
  33. package/build/{9260.fa40c7bd.chunk.js.LICENSE.txt → 9260.4233fae2.chunk.js.LICENSE.txt} +0 -0
  34. package/build/Admin-authenticatedApp.16bed71f.chunk.js +1 -0
  35. package/build/Admin_homePage.fd1fc572.chunk.js +1 -0
  36. package/build/Admin_marketplace.89a0a014.chunk.js +1 -0
  37. package/build/Admin_pluginsPage.97a514db.chunk.js +1 -0
  38. package/build/admin-users.2740c223.chunk.js +1 -0
  39. package/build/content-manager.f1c46a88.chunk.js +1 -0
  40. package/build/en-json.73a610d6.chunk.js +1 -0
  41. package/build/index.html +1 -1
  42. package/build/ja-json.e13f04e8.chunk.js +1 -0
  43. package/build/ko-json.2200c9c9.chunk.js +1 -0
  44. package/build/main.12d62562.js +2 -0
  45. package/build/{main.3e719c82.js.LICENSE.txt → main.12d62562.js.LICENSE.txt} +0 -0
  46. package/build/{runtime~main.66becdbd.js → runtime~main.21bf3a67.js} +1 -1
  47. package/build/{upload-translation-en-json.c3373c8d.chunk.js → upload-translation-en-json.c334dd82.chunk.js} +1 -1
  48. package/build/vi-json.1e850069.chunk.js +1 -0
  49. package/index.js +53 -244
  50. package/package.json +9 -7
  51. package/server/controllers/admin.js +12 -1
  52. package/server/routes/serve-admin-panel.js +1 -1
  53. package/utils/create-cache-dir.js +119 -0
  54. package/utils/get-custom-webpack-config.js +38 -0
  55. package/utils/index.js +13 -0
  56. package/utils/should-build-admin.js +51 -0
  57. package/utils/watch-admin-files.js +56 -0
  58. package/webpack.config.js +36 -3
  59. package/.env +0 -0
  60. package/admin/src/hooks/useFetchPluginsFromMarketPlace/index.js +0 -49
  61. package/admin/src/pages/MarketplacePage/MarketplaceBanner/Wrapper.js +0 -28
  62. package/admin/src/pages/MarketplacePage/MarketplaceBanner/index.js +0 -37
  63. package/admin/src/pages/MarketplacePage/PluginCard/Wrapper.js +0 -148
  64. package/admin/src/pages/MarketplacePage/PluginCard/index.js +0 -185
  65. package/admin/src/pages/MarketplacePage/Wrapper.js +0 -5
  66. package/admin/src/pages/MarketplacePage/assets/marketplace-coming-soon.png +0 -0
  67. package/build/01a600d9e6e0dea21e33.png +0 -0
  68. package/build/4362.86a4e939.chunk.js +0 -1
  69. package/build/9260.fa40c7bd.chunk.js +0 -2
  70. package/build/Admin-authenticatedApp.a5d2c5fa.chunk.js +0 -1
  71. package/build/Admin_homePage.d6754c66.chunk.js +0 -1
  72. package/build/Admin_marketplace.419010d8.chunk.js +0 -1
  73. package/build/Admin_pluginsPage.7d1bd7ce.chunk.js +0 -1
  74. package/build/admin-users.1fda1f27.chunk.js +0 -1
  75. package/build/content-manager.8412e024.chunk.js +0 -1
  76. package/build/en-json.b35c285f.chunk.js +0 -1
  77. package/build/ja-json.46e29f04.chunk.js +0 -1
  78. package/build/ko-json.dd36fdc0.chunk.js +0 -1
  79. package/build/main.3e719c82.js +0 -2
  80. package/build/vi-json.55a11ac0.chunk.js +0 -1
@@ -14,7 +14,10 @@ import init from './init';
14
14
  import { initialState, reducer } from './reducer';
15
15
 
16
16
  const AuthPage = ({ hasAdmin, setHasAdmin }) => {
17
- const { push } = useHistory();
17
+ const {
18
+ push,
19
+ location: { search },
20
+ } = useHistory();
18
21
  const { changeLocale } = useLocalesProvider();
19
22
  const { setSkipped } = useGuidedTour();
20
23
  const { trackUsage } = useTracking();
@@ -119,7 +122,7 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
119
122
  auth.setToken(token, body.rememberMe);
120
123
  auth.setUserInfo(user, body.rememberMe);
121
124
 
122
- push('/');
125
+ redirectToPreviousLocation();
123
126
  } catch (err) {
124
127
  if (err.response) {
125
128
  const errorMessage = get(
@@ -174,6 +177,7 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
174
177
  if (isUserSuperAdmin) {
175
178
  persistStateToLocaleStorage.setSkipped(false);
176
179
  setSkipped(false);
180
+ trackUsage('didLaunchGuidedtour');
177
181
  }
178
182
  }
179
183
 
@@ -189,8 +193,7 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
189
193
  return;
190
194
  }
191
195
 
192
- // Redirect to the homePage
193
- push('/');
196
+ redirectToPreviousLocation();
194
197
  } catch (err) {
195
198
  trackUsage('didNotCreateFirstAdmin');
196
199
 
@@ -238,6 +241,17 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
238
241
  }
239
242
  };
240
243
 
244
+ const redirectToPreviousLocation = () => {
245
+ if (authType === 'login') {
246
+ const redirectTo = query.get('redirectTo');
247
+ const redirectUrl = redirectTo ? decodeURIComponent(redirectTo) : '/';
248
+
249
+ push(redirectUrl);
250
+ } else {
251
+ push('/');
252
+ }
253
+ };
254
+
241
255
  // Redirect the user to the login page if
242
256
  // the endpoint does not exist or
243
257
  // there is already an admin user oo
@@ -248,7 +262,16 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
248
262
 
249
263
  // Redirect the user to the register-admin if it is the first user
250
264
  if (!hasAdmin && authType !== 'register-admin') {
251
- return <Redirect to="/auth/register-admin" />;
265
+ return (
266
+ <Redirect
267
+ to={{
268
+ pathname: '/auth/register-admin',
269
+ // Forward the `?redirectTo` from /auth/login
270
+ // /abc => /auth/login?redirectTo=%2Fabc => /auth/register-admin?redirectTo=%2Fabc
271
+ search,
272
+ }}
273
+ />
274
+ );
252
275
  }
253
276
 
254
277
  return (
@@ -1,26 +1,24 @@
1
1
  import React from 'react';
2
- import { useQuery } from 'react-query';
3
2
  import { useIntl } from 'react-intl';
4
- import { LoadingIndicatorPage, useNotification, useFocusWhenNavigate } from '@strapi/helper-plugin';
3
+ import { LoadingIndicatorPage, useFocusWhenNavigate } from '@strapi/helper-plugin';
4
+ import { useNotifyAT } from '@strapi/design-system/LiveRegions';
5
5
  import { Layout, HeaderLayout, ContentLayout } from '@strapi/design-system/Layout';
6
6
  import { Main } from '@strapi/design-system/Main';
7
- import { useNotifyAT } from '@strapi/design-system/LiveRegions';
8
7
  import { Typography } from '@strapi/design-system/Typography';
9
8
  import { Table, Thead, Tbody, Tr, Td, Th } from '@strapi/design-system/Table';
10
- import { fetchPlugins } from './utils/api';
9
+ import useFetchInstalledPlugins from '../../hooks/useFetchInstalledPlugins';
11
10
 
12
11
  const Plugins = () => {
13
12
  const { formatMessage } = useIntl();
14
- useFocusWhenNavigate();
15
13
  const { notifyStatus } = useNotifyAT();
16
- const toggleNotification = useNotification();
14
+ useFocusWhenNavigate();
17
15
 
18
16
  const title = formatMessage({
19
17
  id: 'app.components.ListPluginsPage.title',
20
18
  defaultMessage: 'Plugins',
21
19
  });
22
20
 
23
- const notifyLoad = () => {
21
+ const notifyPluginPageLoad = () => {
24
22
  notifyStatus(
25
23
  formatMessage(
26
24
  {
@@ -32,14 +30,7 @@ const Plugins = () => {
32
30
  );
33
31
  };
34
32
 
35
- const { status, data } = useQuery('list-plugins', () => fetchPlugins(notifyLoad), {
36
- onError: () => {
37
- toggleNotification({
38
- type: 'warning',
39
- message: { id: 'notification.error', defaultMessage: 'An error occured' },
40
- });
41
- },
42
- });
33
+ const { status, data } = useFetchInstalledPlugins(notifyPluginPageLoad);
43
34
 
44
35
  const isLoading = status !== 'success' && status !== 'error';
45
36
 
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { Box } from '@strapi/design-system/Box';
4
+ import { GridLayout } from '@strapi/design-system/Layout';
5
+
6
+ const EmptyPluginCard = styled(Box)`
7
+ background: ${({ theme }) =>
8
+ `linear-gradient(180deg, rgba(234, 234, 239, 0) 0%, ${theme.colors.neutral150} 100%)`};
9
+ opacity: 0.33;
10
+ `;
11
+
12
+ export const EmptyPluginGrid = () => {
13
+ return (
14
+ <GridLayout>
15
+ {Array(12)
16
+ .fill(null)
17
+ .map((_, idx) => (
18
+ <EmptyPluginCard
19
+ // eslint-disable-next-line react/no-array-index-key
20
+ key={`empty-plugin-card-${idx}`}
21
+ height="234px"
22
+ hasRadius
23
+ />
24
+ ))}
25
+ </GridLayout>
26
+ );
27
+ };
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Typography } from '@strapi/design-system/Typography';
4
+ import { Box } from '@strapi/design-system/Box';
5
+ import { Flex } from '@strapi/design-system/Flex';
6
+ import { Icon } from '@strapi/design-system/Icon';
7
+ import EmptyStateDocument from '@strapi/icons/EmptyDocuments';
8
+ import { EmptyPluginGrid } from './EmptyPluginGrid';
9
+
10
+ export const EmptyPluginSearch = ({ content }) => {
11
+ return (
12
+ <Box position="relative">
13
+ <EmptyPluginGrid />
14
+ <Box position="absolute" top={11} width="100%">
15
+ <Flex alignItems="center" justifyContent="center" direction="column">
16
+ <Icon as={EmptyStateDocument} color="" width="160px" height="88px" />
17
+ <Box paddingTop={6}>
18
+ <Typography variant="delta" as="p" textColor="neutral600">
19
+ {content}
20
+ </Typography>
21
+ </Box>
22
+ </Flex>
23
+ </Box>
24
+ </Box>
25
+ );
26
+ };
27
+
28
+ EmptyPluginSearch.propTypes = {
29
+ content: PropTypes.string.isRequired,
30
+ };
@@ -0,0 +1,186 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useIntl } from 'react-intl';
4
+ import styled from 'styled-components';
5
+ import { Box } from '@strapi/design-system/Box';
6
+ import { Stack } from '@strapi/design-system/Stack';
7
+ import { Typography } from '@strapi/design-system/Typography';
8
+ import { Button } from '@strapi/design-system/Button';
9
+ import { LinkButton } from '@strapi/design-system/LinkButton';
10
+ import { Flex } from '@strapi/design-system/Flex';
11
+ import { Icon } from '@strapi/design-system/Icon';
12
+ import { Tooltip } from '@strapi/design-system/Tooltip';
13
+ import ExternalLink from '@strapi/icons/ExternalLink';
14
+ import Duplicate from '@strapi/icons/Duplicate';
15
+ import Check from '@strapi/icons/Check';
16
+ import CheckCircle from '@strapi/icons/CheckCircle';
17
+ import { useNotification, useTracking } from '@strapi/helper-plugin';
18
+ import { CopyToClipboard } from 'react-copy-to-clipboard';
19
+ import madeByStrapiIcon from '../../../../assets/images/icon_made-by-strapi.svg';
20
+
21
+ // Custom component to have an ellipsis after the 2nd line
22
+ const EllipsisText = styled(Typography)`
23
+ /* stylelint-disable value-no-vendor-prefix, property-no-vendor-prefix */
24
+ display: -webkit-box;
25
+ -webkit-box-orient: vertical;
26
+ -webkit-line-clamp: 2;
27
+ /* stylelint-enable value-no-vendor-prefix, property-no-vendor-prefix */
28
+ overflow: hidden;
29
+ `;
30
+
31
+ const PluginCard = ({ plugin, installedPluginNames, useYarn }) => {
32
+ const { attributes } = plugin;
33
+ const { formatMessage } = useIntl();
34
+ const toggleNotification = useNotification();
35
+ const { trackUsage } = useTracking();
36
+
37
+ const isInstalled = installedPluginNames.includes(attributes.npmPackageName);
38
+
39
+ const commandToCopy = useYarn
40
+ ? `yarn add ${attributes.npmPackageName}`
41
+ : `npm install ${attributes.npmPackageName}`;
42
+
43
+ const madeByStrapiMessage = formatMessage({
44
+ id: 'admin.pages.MarketPlacePage.plugin.tooltip.madeByStrapi',
45
+ defaultMessage: 'Made by Strapi',
46
+ });
47
+
48
+ return (
49
+ <Flex
50
+ direction="column"
51
+ justifyContent="space-between"
52
+ paddingTop={4}
53
+ paddingRight={6}
54
+ paddingBottom={4}
55
+ paddingLeft={6}
56
+ hasRadius
57
+ background="neutral0"
58
+ shadow="tableShadow"
59
+ height="100%"
60
+ alignItems="normal"
61
+ >
62
+ <Box>
63
+ <Box
64
+ as="img"
65
+ src={attributes.logo.url}
66
+ alt={`${attributes.name} logo`}
67
+ hasRadius
68
+ width={11}
69
+ height={11}
70
+ />
71
+ <Box paddingTop={4}>
72
+ <Typography as="h3" variant="delta">
73
+ <Flex alignItems="center">
74
+ {attributes.name}
75
+ {attributes.validated && !attributes.madeByStrapi && (
76
+ <Tooltip
77
+ description={formatMessage({
78
+ id: 'admin.pages.MarketPlacePage.plugin.tooltip.verified',
79
+ defaultMessage: 'Plugin verified by Strapi',
80
+ })}
81
+ >
82
+ <Flex>
83
+ <Icon as={CheckCircle} marginLeft={2} color="success600" />
84
+ </Flex>
85
+ </Tooltip>
86
+ )}
87
+ {attributes.madeByStrapi && (
88
+ <Tooltip description={madeByStrapiMessage}>
89
+ <Flex>
90
+ <Box
91
+ as="img"
92
+ src={madeByStrapiIcon}
93
+ alt={madeByStrapiMessage}
94
+ marginLeft={1}
95
+ width={6}
96
+ height="auto"
97
+ />
98
+ </Flex>
99
+ </Tooltip>
100
+ )}
101
+ </Flex>
102
+ </Typography>
103
+ </Box>
104
+ <Box paddingTop={2}>
105
+ <EllipsisText as="p" variant="omega" textColor="neutral600">
106
+ {attributes.description}
107
+ </EllipsisText>
108
+ </Box>
109
+ </Box>
110
+
111
+ <Stack horizontal spacing={2} style={{ alignSelf: 'flex-end' }} paddingTop={6}>
112
+ <LinkButton
113
+ size="S"
114
+ href={`https://market.strapi.io/plugins/${attributes.slug}`}
115
+ endIcon={<ExternalLink />}
116
+ aria-label={formatMessage(
117
+ {
118
+ id: 'admin.pages.MarketPlacePage.plugin.info.label',
119
+ defaultMessage: 'Learn more about {pluginName}',
120
+ },
121
+ { pluginName: attributes.name }
122
+ )}
123
+ variant="tertiary"
124
+ onClick={() => trackUsage('didPluginLearnMore')}
125
+ >
126
+ {formatMessage({
127
+ id: 'admin.pages.MarketPlacePage.plugin.info.text',
128
+ defaultMessage: 'Learn more',
129
+ })}
130
+ </LinkButton>
131
+ {isInstalled ? (
132
+ <Box paddingLeft={4}>
133
+ <Icon as={Check} marginRight={2} width={12} height={12} color="success600" />
134
+ <Typography variant="omega" textColor="success600" fontWeight="bold">
135
+ {formatMessage({
136
+ id: 'admin.pages.MarketPlacePage.plugin.installed',
137
+ defaultMessage: 'Installed',
138
+ })}
139
+ </Typography>
140
+ </Box>
141
+ ) : (
142
+ <CopyToClipboard
143
+ onCopy={() => {
144
+ trackUsage('willInstallPlugin');
145
+ toggleNotification({
146
+ type: 'success',
147
+ message: { id: 'admin.pages.MarketPlacePage.plugin.copy.success' },
148
+ });
149
+ }}
150
+ text={commandToCopy}
151
+ >
152
+ <Button size="S" startIcon={<Duplicate />} variant="secondary">
153
+ {formatMessage({
154
+ id: 'admin.pages.MarketPlacePage.plugin.copy',
155
+ defaultMessage: 'Copy install command',
156
+ })}
157
+ </Button>
158
+ </CopyToClipboard>
159
+ )}
160
+ </Stack>
161
+ </Flex>
162
+ );
163
+ };
164
+
165
+ PluginCard.propTypes = {
166
+ plugin: PropTypes.shape({
167
+ id: PropTypes.string.isRequired,
168
+ attributes: PropTypes.shape({
169
+ name: PropTypes.string.isRequired,
170
+ description: PropTypes.string.isRequired,
171
+ slug: PropTypes.string.isRequired,
172
+ npmPackageName: PropTypes.string.isRequired,
173
+ npmPackageUrl: PropTypes.string.isRequired,
174
+ repositoryUrl: PropTypes.string.isRequired,
175
+ logo: PropTypes.object.isRequired,
176
+ developerName: PropTypes.string.isRequired,
177
+ validated: PropTypes.bool.isRequired,
178
+ madeByStrapi: PropTypes.bool.isRequired,
179
+ strapiCompatibility: PropTypes.oneOf(['v3', 'v4']).isRequired,
180
+ }).isRequired,
181
+ }).isRequired,
182
+ installedPluginNames: PropTypes.arrayOf(PropTypes.string).isRequired,
183
+ useYarn: PropTypes.bool.isRequired,
184
+ };
185
+
186
+ export default PluginCard;