@strapi/admin 4.1.4-alpha.0 → 4.2.0-alpha.1

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 (69) hide show
  1. package/.env +0 -0
  2. package/admin/src/StrapiApp.js +40 -42
  3. package/admin/src/components/GuidedTour/Modal/components/Modal.js +1 -1
  4. package/admin/src/components/Providers/index.js +65 -32
  5. package/admin/src/components/Theme/index.js +11 -12
  6. package/admin/src/components/ThemeToggleProvider/index.js +66 -0
  7. package/admin/src/content-manager/components/SelectWrapper/utils/getSelectStyles.js +3 -1
  8. package/admin/src/content-manager/components/Wysiwyg/EditorStylesContainer.js +4 -2
  9. package/admin/src/contexts/ThemeToggle/index.js +5 -0
  10. package/admin/src/contexts/index.js +1 -0
  11. package/admin/src/hooks/index.js +2 -0
  12. package/admin/src/hooks/useFetchPluginsFromMarketPlace/index.js +49 -0
  13. package/admin/src/hooks/useThemeToggle/index.js +10 -0
  14. package/admin/src/pages/Admin/Onboarding/index.js +1 -1
  15. package/admin/src/pages/HomePage/SocialLinks.js +0 -3
  16. package/admin/src/pages/InstalledPluginsPage/Plugins.js +15 -6
  17. package/admin/src/{hooks/useFetchInstalledPlugins → pages/InstalledPluginsPage}/utils/api.js +4 -2
  18. package/admin/src/pages/MarketplacePage/MarketplaceBanner/Wrapper.js +28 -0
  19. package/admin/src/pages/MarketplacePage/MarketplaceBanner/index.js +37 -0
  20. package/admin/src/pages/MarketplacePage/PluginCard/Wrapper.js +148 -0
  21. package/admin/src/pages/MarketplacePage/PluginCard/index.js +185 -0
  22. package/admin/src/pages/MarketplacePage/Wrapper.js +5 -0
  23. package/admin/src/pages/MarketplacePage/assets/marketplace-coming-soon.png +0 -0
  24. package/admin/src/pages/MarketplacePage/index.js +109 -198
  25. package/admin/src/pages/ProfilePage/index.js +74 -10
  26. package/admin/src/pages/ProfilePage/utils/api.js +4 -2
  27. package/admin/src/translations/en.json +18 -18
  28. package/build/01a600d9e6e0dea21e33.png +0 -0
  29. package/build/4362.86a4e939.chunk.js +1 -0
  30. package/build/{6250.836851ca.chunk.js → 6404.3c2d0a81.chunk.js} +1 -1
  31. package/build/{Admin-authenticatedApp.27fba46d.chunk.js → Admin-authenticatedApp.2d44e117.chunk.js} +1 -1
  32. package/build/{Admin_homePage.964ff5d7.chunk.js → Admin_homePage.d6754c66.chunk.js} +1 -1
  33. package/build/Admin_marketplace.419010d8.chunk.js +1 -0
  34. package/build/Admin_pluginsPage.7d1bd7ce.chunk.js +1 -0
  35. package/build/Admin_profilePage.d7192d06.chunk.js +1 -0
  36. package/build/{Admin_settingsPage.55ec1f30.chunk.js → Admin_settingsPage.a8c7ded5.chunk.js} +1 -1
  37. package/build/admin-users.1fda1f27.chunk.js +1 -0
  38. package/build/content-manager.de808f2c.chunk.js +1 -0
  39. package/build/{content-type-builder.de5d18ad.chunk.js → content-type-builder.cda4ba3c.chunk.js} +1 -1
  40. package/build/{email-settings-page.27ee4a98.chunk.js → email-settings-page.40ee2bda.chunk.js} +1 -1
  41. package/build/en-json.b35c285f.chunk.js +1 -0
  42. package/build/index.html +1 -1
  43. package/build/{main.22e9a5c5.js → main.34ee547b.js} +2 -2
  44. package/build/{main.22e9a5c5.js.LICENSE.txt → main.34ee547b.js.LICENSE.txt} +0 -0
  45. package/build/{runtime~main.e6326927.js → runtime~main.3ef9943c.js} +1 -1
  46. package/build/users-email-settings-page.5abb9575.chunk.js +1 -0
  47. package/package.json +5 -5
  48. package/server/controllers/admin.js +1 -12
  49. package/admin/src/assets/images/icon_made-by-strapi.svg +0 -5
  50. package/admin/src/hooks/useFetchInstalledPlugins/index.js +0 -23
  51. package/admin/src/hooks/useFetchMarketplacePlugins/index.js +0 -23
  52. package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +0 -17
  53. package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/EmptyPluginGrid.js +0 -27
  54. package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/index.js +0 -30
  55. package/admin/src/pages/MarketplacePage/components/PluginCard/index.js +0 -186
  56. package/admin/src/pages/MarketplacePage/utils/api.js +0 -9
  57. package/admin/src/themes/colors.js +0 -51
  58. package/admin/src/themes/fontWeights.js +0 -8
  59. package/admin/src/themes/index.js +0 -13
  60. package/admin/src/themes/sizes.js +0 -31
  61. package/build/4362.5c92d240.chunk.js +0 -1
  62. package/build/90f49a385afb000fb1d4.svg +0 -5
  63. package/build/Admin_marketplace.e83567ff.chunk.js +0 -1
  64. package/build/Admin_pluginsPage.97a514db.chunk.js +0 -1
  65. package/build/Admin_profilePage.c497b39d.chunk.js +0 -1
  66. package/build/admin-users.2740c223.chunk.js +0 -1
  67. package/build/content-manager.e1189026.chunk.js +0 -1
  68. package/build/en-json.086acf41.chunk.js +0 -1
  69. package/build/users-email-settings-page.862eb51e.chunk.js +0 -1
@@ -0,0 +1,148 @@
1
+ import styled from 'styled-components';
2
+
3
+ const Wrapper = styled.div`
4
+ .wrapper {
5
+ position: relative;
6
+ min-height: 216px;
7
+ margin-bottom: 3.6rem;
8
+ padding: 1.2rem 1.5rem;
9
+ padding-bottom: 0;
10
+ background-color: #fff;
11
+ box-shadow: 0 2px 4px #e3e9f3;
12
+ -webkit-font-smoothing: antialiased;
13
+ }
14
+
15
+ .cardTitle {
16
+ display: flex;
17
+ font-size: 13px;
18
+ font-weight: 600;
19
+ text-transform: uppercase;
20
+ letter-spacing: 0.5px;
21
+
22
+ > div:first-child {
23
+ margin-right: 14px;
24
+ }
25
+
26
+ > div:last-child {
27
+ height: 36px;
28
+ line-height: 36px;
29
+ }
30
+
31
+ i,
32
+ svg {
33
+ margin-left: 7px;
34
+ color: #b3b5b9;
35
+ font-size: 1rem;
36
+ vertical-align: baseline;
37
+ cursor: pointer;
38
+ }
39
+ }
40
+
41
+ .cardDescription {
42
+ height: 54px;
43
+ margin-top: 27px;
44
+ margin-bottom: 9px;
45
+ font-size: 13px;
46
+ font-weight: 400;
47
+
48
+ > span:last-child {
49
+ color: #1c5de7;
50
+ }
51
+ -webkit-font-smoothing: antialiased;
52
+ }
53
+
54
+ .cardFooter {
55
+ position: absolute;
56
+ bottom: 0;
57
+ left: 0;
58
+ display: flex;
59
+ width: 100%;
60
+ height: 45px;
61
+ padding: 0.9rem 1.5rem 1rem;
62
+ background-color: #fafafb;
63
+ justify-content: space-between;
64
+ flex-direction: row-reverse;
65
+ cursor: initial;
66
+ }
67
+
68
+ .compatible {
69
+ margin-top: 3px;
70
+ color: #5a9e06;
71
+ font-size: 1.3rem;
72
+ font-style: italic;
73
+
74
+ > i,
75
+ > svg {
76
+ margin-right: 7px;
77
+ font-size: 12px;
78
+ }
79
+ }
80
+
81
+ .settings {
82
+ margin-top: 3px;
83
+ color: #323740;
84
+ font-size: 1.3rem;
85
+ font-weight: 500;
86
+ cursor: pointer;
87
+
88
+ > i,
89
+ > svg {
90
+ margin-right: 7px;
91
+ font-size: 11px;
92
+ vertical-align: inherit;
93
+ }
94
+ }
95
+
96
+ .button {
97
+ height: 26px;
98
+ min-width: 89px !important;
99
+ padding: 0 15px;
100
+ margin: 0;
101
+ border-radius: 2px !important;
102
+ line-height: 23px;
103
+ font-size: 13px;
104
+ cursor: pointer;
105
+ span {
106
+ display: inline-block;
107
+ width: 100%;
108
+ height: 100%;
109
+ }
110
+ }
111
+
112
+ .frame {
113
+ width: 70px;
114
+ height: 36px;
115
+ margin: auto 0;
116
+ text-align: center;
117
+ border: 1px solid #f3f3f7;
118
+ border-radius: 3px;
119
+ white-space: nowrap;
120
+ > img {
121
+ max-height: 36px;
122
+ vertical-align: middle;
123
+ }
124
+ }
125
+
126
+ .helper {
127
+ display: inline-block;
128
+ height: 100%;
129
+ vertical-align: middle;
130
+ }
131
+ .primary {
132
+ background: linear-gradient(315deg, #0097f6 0%, #005eea 100%);
133
+ color: white;
134
+ font-weight: 500;
135
+ -webkit-font-smoothing: antialiased;
136
+
137
+ &:active {
138
+ box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.15);
139
+ }
140
+ }
141
+
142
+ .secondary {
143
+ border: 1px solid #dfe0e1;
144
+ font-weight: 600;
145
+ }
146
+ `;
147
+
148
+ export default Wrapper;
@@ -0,0 +1,185 @@
1
+ /**
2
+ *
3
+ * PluginCard
4
+ *
5
+ */
6
+ /* eslint-disable */
7
+ import React from 'react';
8
+ import PropTypes from 'prop-types';
9
+ import { FormattedMessage } from 'react-intl';
10
+ import { Button, PopUpWarning, CheckPermissions } from '@strapi/helper-plugin';
11
+ import adminPermissions from '../../../permissions';
12
+ import Wrapper from './Wrapper';
13
+
14
+ /* eslint-disable react/no-unused-state */
15
+ class PluginCard extends React.Component {
16
+ state = {
17
+ boostrapCol: 'col-lg-4',
18
+ showModalAutoReload: false,
19
+ showModalEnv: false,
20
+ };
21
+
22
+ componentDidMount() {
23
+ // Listen window resize.
24
+ window.addEventListener('resize', this.setBoostrapCol);
25
+ this.setBoostrapCol();
26
+ }
27
+
28
+ componentWillUnmount() {
29
+ window.removeEventListener('resize', this.setBoostrapCol);
30
+ }
31
+
32
+ setBoostrapCol = () => {
33
+ let boostrapCol = 'col-lg-4';
34
+
35
+ if (window.innerWidth > 1680) {
36
+ boostrapCol = 'col-lg-3';
37
+ }
38
+
39
+ if (window.innerWidth > 2300) {
40
+ boostrapCol = 'col-lg-2';
41
+ }
42
+
43
+ this.setState({ boostrapCol });
44
+ };
45
+
46
+ handleDownloadPlugin = e => {
47
+ const {
48
+ autoReload,
49
+ currentEnvironment,
50
+ downloadPlugin,
51
+ history: { push },
52
+ isAlreadyInstalled,
53
+ plugin: { id },
54
+ } = this.props;
55
+
56
+ if (!autoReload) {
57
+ this.setState({ showModalAutoReload: true });
58
+ } else if (currentEnvironment !== 'development') {
59
+ this.setState({ showModalEnv: true });
60
+ } else if (!isAlreadyInstalled) {
61
+ downloadPlugin(id);
62
+ } else {
63
+ push('/list-plugins');
64
+ }
65
+ };
66
+
67
+ render() {
68
+ const buttonClass = !this.props.isAlreadyInstalled ? 'primary' : 'secondary';
69
+ const buttonLabel = this.props.isAlreadyInstalled
70
+ ? 'app.components.PluginCard.Button.label.install'
71
+ : 'app.components.PluginCard.Button.label.download';
72
+
73
+ const settingsComponent = null;
74
+
75
+ const descriptions = {
76
+ short:
77
+ this.props.plugin.id === 'support-us' ? (
78
+ <FormattedMessage id={this.props.plugin.description.short} />
79
+ ) : (
80
+ this.props.plugin.description.short
81
+ ),
82
+ long:
83
+ this.props.plugin.id === 'support-us' ? (
84
+ <FormattedMessage
85
+ id={this.props.plugin.description.long || this.props.plugin.description.short}
86
+ />
87
+ ) : (
88
+ this.props.plugin.description.long || this.props.plugin.description.short
89
+ ),
90
+ };
91
+
92
+ return (
93
+ <Wrapper className={this.state.boostrapCol}>
94
+ <div className="wrapper">
95
+ <div className="cardTitle">
96
+ <div className="frame">
97
+ <span className="helper" />
98
+ <img src={this.props.plugin.logo} alt="icon" />
99
+ </div>
100
+ <div
101
+ onClick={e => {
102
+ // FIXME: dead link as we are changing the naming. Would be better to use a url comming from the api call directly
103
+ window.open(
104
+ `https://github.com/strapi/strapi/tree/master/packages/strapi-plugin-${this.props.plugin.id}`,
105
+ '_blank'
106
+ );
107
+ }}
108
+ >
109
+ {this.props.plugin.name} <i className="fa fa-external-link-alt" />
110
+ </div>
111
+ </div>
112
+ <div className="cardDescription">{descriptions.long}</div>
113
+ <div className="cardFooter" onClick={e => e.stopPropagation()}>
114
+ <div className="cardFooterButton">
115
+ <CheckPermissions permissions={adminPermissions.marketplace.install}>
116
+ <Button
117
+ className={`${buttonClass} button`}
118
+ label={buttonLabel}
119
+ type="button"
120
+ onClick={this.handleDownloadPlugin}
121
+ />
122
+ </CheckPermissions>
123
+ </div>
124
+ {this.props.isAlreadyInstalled ? (
125
+ settingsComponent
126
+ ) : (
127
+ <div className="compatible">
128
+ <i className={`fa fa-${this.props.plugin.isCompatible ? 'check' : 'times'}`} />
129
+ <FormattedMessage
130
+ id={`app.components.PluginCard.compatible${
131
+ this.props.plugin.id === 'support-us' ? 'Community' : ''
132
+ }`}
133
+ />
134
+ </div>
135
+ )}
136
+ </div>
137
+ </div>
138
+
139
+ <PopUpWarning
140
+ content={{
141
+ message: 'app.components.PluginCard.PopUpWarning.install.impossible.autoReload.needed',
142
+ title: 'app.components.PluginCard.PopUpWarning.install.impossible.title',
143
+ confirm: 'app.components.PluginCard.PopUpWarning.install.impossible.confirm',
144
+ }}
145
+ isOpen={this.state.showModalAutoReload}
146
+ onlyConfirmButton
147
+ onConfirm={() => this.setState({ showModalAutoReload: false })}
148
+ popUpWarningType="warning"
149
+ />
150
+ <PopUpWarning
151
+ content={{
152
+ message: 'app.components.PluginCard.PopUpWarning.install.impossible.environment',
153
+ title: 'app.components.PluginCard.PopUpWarning.install.impossible.title',
154
+ confirm: 'app.components.PluginCard.PopUpWarning.install.impossible.confirm',
155
+ }}
156
+ isOpen={this.state.showModalEnv}
157
+ onlyConfirmButton
158
+ onConfirm={() => this.setState({ showModalEnv: false })}
159
+ popUpWarningType="warning"
160
+ />
161
+ </Wrapper>
162
+ );
163
+ }
164
+ }
165
+
166
+ PluginCard.defaultProps = {
167
+ isAlreadyInstalled: false,
168
+ plugin: {
169
+ description: '',
170
+ id: '',
171
+ name: '',
172
+ price: 0,
173
+ ratings: 5,
174
+ },
175
+ };
176
+
177
+ PluginCard.propTypes = {
178
+ currentEnvironment: PropTypes.string.isRequired,
179
+ downloadPlugin: PropTypes.func.isRequired,
180
+ history: PropTypes.object.isRequired,
181
+ isAlreadyInstalled: PropTypes.bool,
182
+ plugin: PropTypes.object,
183
+ };
184
+
185
+ export default PluginCard;
@@ -0,0 +1,5 @@
1
+ import styled from 'styled-components';
2
+
3
+ const Wrapper = styled.div``;
4
+
5
+ export default Wrapper;
@@ -1,216 +1,127 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { useEffect } from 'react';
2
2
  import { useIntl } from 'react-intl';
3
+ import styled from 'styled-components';
3
4
  import { Helmet } from 'react-helmet';
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';
15
- import { Layout, HeaderLayout, ContentLayout, ActionLayout } from '@strapi/design-system/Layout';
16
- import { Main } from '@strapi/design-system/Main';
17
- import { Searchbar } from '@strapi/design-system/Searchbar';
5
+ import { pxToRem, CheckPagePermissions, useTracking } from '@strapi/helper-plugin';
6
+ import { Layout, HeaderLayout, ContentLayout } from '@strapi/design-system/Layout';
7
+ import { Flex } from '@strapi/design-system/Flex';
8
+ import { Box } from '@strapi/design-system/Box';
9
+ import { Stack } from '@strapi/design-system/Stack';
18
10
  import { LinkButton } from '@strapi/design-system/LinkButton';
19
- import { useNotifyAT } from '@strapi/design-system/LiveRegions';
20
- import Plus from '@strapi/icons/Plus';
21
-
22
- import PluginCard from './components/PluginCard';
23
- import { EmptyPluginSearch } from './components/EmptyPluginSearch';
24
- import { fetchAppInformation } from './utils/api';
25
- import useFetchInstalledPlugins from '../../hooks/useFetchInstalledPlugins';
26
- import useFetchMarketplacePlugins from '../../hooks/useFetchMarketplacePlugins';
11
+ import { Main } from '@strapi/design-system/Main';
12
+ import { Typography } from '@strapi/design-system/Typography';
13
+ import ExternalLink from '@strapi/icons/ExternalLink';
27
14
  import adminPermissions from '../../permissions';
15
+ import MarketplacePicture from './assets/marketplace-coming-soon.png';
28
16
 
29
- const matchSearch = (plugins, search) => {
30
- return matchSorter(plugins, search, {
31
- keys: [
32
- {
33
- threshold: matchSorter.rankings.WORD_STARTS_WITH,
34
- key: 'attributes.name',
35
- },
36
- { threshold: matchSorter.rankings.WORD_STARTS_WITH, key: 'attributes.description' },
37
- ],
38
- });
39
- };
17
+ const CenterTypography = styled(Typography)`
18
+ text-align: center;
19
+ `;
20
+
21
+ const Img = styled.img`
22
+ width: ${190 / 16}rem;
23
+ `;
24
+
25
+ const StackCentered = styled(Stack)`
26
+ align-items: center;
27
+ `;
40
28
 
41
29
  const MarketPlacePage = () => {
42
30
  const { formatMessage } = useIntl();
43
31
  const { trackUsage } = useTracking();
44
- const { notifyStatus } = useNotifyAT();
45
- const trackUsageRef = useRef(trackUsage);
46
- const toggleNotification = useNotification();
47
- const [searchQuery, setSearchQuery] = useState('');
48
-
49
- useFocusWhenNavigate();
50
-
51
- const marketplaceTitle = formatMessage({
52
- id: 'admin.pages.MarketPlacePage.title',
53
- defaultMessage: 'Marketplace',
54
- });
55
-
56
- const notifyMarketplaceLoad = () => {
57
- notifyStatus(
58
- formatMessage(
59
- {
60
- id: 'app.utils.notify.data-loaded',
61
- defaultMessage: 'The {target} has loaded',
62
- },
63
- { target: marketplaceTitle }
64
- )
65
- );
66
- };
67
-
68
- const {
69
- status: marketplacePluginsStatus,
70
- data: marketplacePluginsResponse,
71
- } = useFetchMarketplacePlugins(notifyMarketplaceLoad);
72
-
73
- const {
74
- status: installedPluginsStatus,
75
- data: installedPluginsResponse,
76
- } = useFetchInstalledPlugins();
77
-
78
- const { data: appInfoResponse, status: appInfoStatus } = useQuery(
79
- 'app-information',
80
- fetchAppInformation,
81
- {
82
- onError: () => {
83
- toggleNotification({
84
- type: 'warning',
85
- message: { id: 'notification.error', defaultMessage: 'An error occured' },
86
- });
87
- },
88
- }
89
- );
90
-
91
- const isLoading = [marketplacePluginsStatus, installedPluginsStatus, appInfoStatus].includes(
92
- 'loading'
93
- );
94
-
95
- const hasFailed = [marketplacePluginsStatus, installedPluginsStatus, appInfoStatus].includes(
96
- 'error'
97
- );
98
32
 
99
33
  useEffect(() => {
100
- trackUsageRef.current('didGoToMarketplace');
101
- }, []);
34
+ trackUsage('didGoToMarketplace');
35
+ }, [trackUsage]);
102
36
 
103
- if (hasFailed) {
104
- return (
105
- <Layout>
106
- <AnErrorOccurred />
107
- </Layout>
108
- );
109
- }
110
-
111
- if (isLoading) {
112
- return (
37
+ return (
38
+ <CheckPagePermissions permissions={adminPermissions.marketplace.main}>
113
39
  <Layout>
114
- <Main aria-busy>
115
- <LoadingIndicatorPage />
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>
116
121
  </Main>
117
122
  </Layout>
118
- );
119
- }
120
-
121
- const searchResults = matchSearch(marketplacePluginsResponse.data, searchQuery);
122
- const installedPluginNames = installedPluginsResponse.plugins.map(plugin => plugin.packageName);
123
-
124
- return (
125
- <Layout>
126
- <Main>
127
- <Helmet
128
- title={formatMessage({
129
- id: 'admin.pages.MarketPlacePage.helmet',
130
- defaultMessage: 'Marketplace - Plugins',
131
- })}
132
- />
133
- <HeaderLayout
134
- title={formatMessage({
135
- id: 'admin.pages.MarketPlacePage.title',
136
- defaultMessage: 'Marketplace',
137
- })}
138
- subtitle={formatMessage({
139
- id: 'admin.pages.MarketPlacePage.subtitle',
140
- defaultMessage: 'Get more out of Strapi',
141
- })}
142
- primaryAction={
143
- <LinkButton
144
- startIcon={<Plus />}
145
- variant="tertiary"
146
- href="https://market.strapi.io/submit-plugin"
147
- onClick={() => trackUsage('didSubmitPlugin')}
148
- >
149
- {formatMessage({
150
- id: 'admin.pages.MarketPlacePage.submit.plugin.link',
151
- defaultMessage: 'Submit your plugin',
152
- })}
153
- </LinkButton>
154
- }
155
- />
156
- <ActionLayout
157
- startActions={
158
- <Searchbar
159
- name="searchbar"
160
- onClear={() => setSearchQuery('')}
161
- value={searchQuery}
162
- onChange={e => setSearchQuery(e.target.value)}
163
- clearLabel={formatMessage({
164
- id: 'admin.pages.MarketPlacePage.search.clear',
165
- defaultMessage: 'Clear the plugin search',
166
- })}
167
- placeholder={formatMessage({
168
- id: 'admin.pages.MarketPlacePage.search.placeholder',
169
- defaultMessage: 'Search for a plugin',
170
- })}
171
- >
172
- {formatMessage({
173
- id: 'admin.pages.MarketPlacePage.search.placeholder',
174
- defaultMessage: 'Search for a plugin',
175
- })}
176
- </Searchbar>
177
- }
178
- />
179
- <ContentLayout>
180
- {searchQuery.length > 0 && !searchResults.length ? (
181
- <EmptyPluginSearch
182
- content={formatMessage(
183
- {
184
- id: 'admin.pages.MarketPlacePage.search.empty',
185
- defaultMessage: 'No result for "{target}"',
186
- },
187
- { target: searchQuery }
188
- )}
189
- />
190
- ) : (
191
- <Grid gap={4}>
192
- {searchResults.map(plugin => (
193
- <GridItem col={4} s={6} xs={12} style={{ height: '100%' }} key={plugin.id}>
194
- <PluginCard
195
- plugin={plugin}
196
- installedPluginNames={installedPluginNames}
197
- useYarn={appInfoResponse.data.useYarn}
198
- />
199
- </GridItem>
200
- ))}
201
- </Grid>
202
- )}
203
- </ContentLayout>
204
- </Main>
205
- </Layout>
123
+ </CheckPagePermissions>
206
124
  );
207
125
  };
208
126
 
209
- const ProtectedMarketPlace = () => (
210
- <CheckPagePermissions permissions={adminPermissions.marketplace.main}>
211
- <MarketPlacePage />
212
- </CheckPagePermissions>
213
- );
214
-
215
- export { MarketPlacePage };
216
- export default ProtectedMarketPlace;
127
+ export default MarketPlacePage;