@strapi/admin 4.1.4-alpha.2 → 4.2.0-alpha.5
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.
- package/.env +0 -0
- package/admin/src/app.js +7 -4
- package/admin/src/components/GuidedTour/Homepage/index.js +13 -3
- package/admin/src/components/GuidedTour/Modal/index.js +4 -1
- package/admin/src/components/GuidedTour/layout.js +9 -0
- package/admin/src/content-manager/components/Inputs/index.js +3 -4
- package/admin/src/hooks/index.js +1 -0
- package/admin/src/hooks/useFetchPluginsFromMarketPlace/index.js +49 -0
- package/admin/src/pages/AuthPage/index.js +1 -0
- package/admin/src/pages/InstalledPluginsPage/Plugins.js +15 -6
- package/admin/src/{hooks/useFetchInstalledPlugins → pages/InstalledPluginsPage}/utils/api.js +4 -2
- package/admin/src/pages/MarketplacePage/MarketplaceBanner/Wrapper.js +28 -0
- package/admin/src/pages/MarketplacePage/MarketplaceBanner/index.js +37 -0
- package/admin/src/pages/MarketplacePage/PluginCard/Wrapper.js +148 -0
- package/admin/src/pages/MarketplacePage/PluginCard/index.js +185 -0
- package/admin/src/pages/MarketplacePage/Wrapper.js +5 -0
- package/admin/src/pages/MarketplacePage/assets/marketplace-coming-soon.png +0 -0
- package/admin/src/pages/MarketplacePage/index.js +107 -199
- package/admin/src/translations/en.json +15 -18
- package/admin/src/translations/ja.json +2 -2
- package/admin/src/translations/ko.json +2 -2
- package/build/01a600d9e6e0dea21e33.png +0 -0
- package/build/4362.dbe98749.chunk.js +1 -0
- package/build/9260.d9bb874f.chunk.js +2 -0
- package/build/{9260.fa40c7bd.chunk.js.LICENSE.txt → 9260.d9bb874f.chunk.js.LICENSE.txt} +0 -0
- package/build/Admin-authenticatedApp.a24ebaa0.chunk.js +1 -0
- package/build/Admin_homePage.86604515.chunk.js +1 -0
- package/build/Admin_marketplace.419010d8.chunk.js +1 -0
- package/build/Admin_pluginsPage.7d1bd7ce.chunk.js +1 -0
- package/build/admin-users.1fda1f27.chunk.js +1 -0
- package/build/content-manager.31be1448.chunk.js +1 -0
- package/build/en-json.bce44d39.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/ja-json.e13f04e8.chunk.js +1 -0
- package/build/ko-json.2200c9c9.chunk.js +1 -0
- package/build/{main.7fa5bc38.js → main.4ea77c5f.js} +2 -2
- package/build/{main.7fa5bc38.js.LICENSE.txt → main.4ea77c5f.js.LICENSE.txt} +0 -0
- package/build/{runtime~main.7bb09ab1.js → runtime~main.83b9ee0b.js} +1 -1
- package/index.js +53 -244
- package/package.json +7 -5
- package/server/controllers/admin.js +1 -12
- package/server/routes/serve-admin-panel.js +1 -1
- package/utils/create-cache-dir.js +119 -0
- package/utils/get-custom-webpack-config.js +38 -0
- package/utils/index.js +13 -0
- package/utils/should-build-admin.js +51 -0
- package/utils/watch-admin-files.js +56 -0
- package/webpack.config.js +36 -3
- package/admin/src/assets/images/icon_made-by-strapi.svg +0 -5
- package/admin/src/hooks/useFetchInstalledPlugins/index.js +0 -23
- package/admin/src/hooks/useFetchMarketplacePlugins/index.js +0 -23
- package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +0 -17
- package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/EmptyPluginGrid.js +0 -27
- package/admin/src/pages/MarketplacePage/components/EmptyPluginSearch/index.js +0 -30
- package/admin/src/pages/MarketplacePage/components/PluginCard/index.js +0 -186
- package/admin/src/pages/MarketplacePage/utils/api.js +0 -9
- package/build/4362.5c92d240.chunk.js +0 -1
- package/build/90f49a385afb000fb1d4.svg +0 -5
- package/build/9260.fa40c7bd.chunk.js +0 -2
- package/build/Admin-authenticatedApp.6d27d55a.chunk.js +0 -1
- package/build/Admin_homePage.964ff5d7.chunk.js +0 -1
- package/build/Admin_marketplace.89a0a014.chunk.js +0 -1
- package/build/Admin_pluginsPage.97a514db.chunk.js +0 -1
- package/build/admin-users.2740c223.chunk.js +0 -1
- package/build/content-manager.e1189026.chunk.js +0 -1
- package/build/en-json.086acf41.chunk.js +0 -1
- package/build/ja-json.46e29f04.chunk.js +0 -1
- package/build/ko-json.dd36fdc0.chunk.js +0 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const _ = require('lodash');
|
|
6
|
+
const webpack = require('webpack');
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const getWebpackConfig = require('../webpack.config');
|
|
9
|
+
|
|
10
|
+
const getCustomWebpackConfig = (dir, config) => {
|
|
11
|
+
const adminConfigPath = path.join(dir, 'src', 'admin', 'webpack.config.js');
|
|
12
|
+
|
|
13
|
+
let webpackConfig = getWebpackConfig(config);
|
|
14
|
+
|
|
15
|
+
if (fs.existsSync(adminConfigPath)) {
|
|
16
|
+
const webpackAdminConfig = require(path.resolve(adminConfigPath));
|
|
17
|
+
|
|
18
|
+
if (_.isFunction(webpackAdminConfig)) {
|
|
19
|
+
// Expose the devServer configuration
|
|
20
|
+
if (config.devServer) {
|
|
21
|
+
webpackConfig.devServer = config.devServer;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
webpackConfig = webpackAdminConfig(webpackConfig, webpack);
|
|
25
|
+
|
|
26
|
+
if (!webpackConfig) {
|
|
27
|
+
console.error(
|
|
28
|
+
`${chalk.red('Error:')} Nothing was returned from your custom webpack configuration`
|
|
29
|
+
);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return webpackConfig;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
module.exports = getCustomWebpackConfig;
|
package/utils/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const createCacheDir = require('./create-cache-dir');
|
|
4
|
+
const getCustomWebpackConfig = require('./get-custom-webpack-config');
|
|
5
|
+
const shouldBuildAdmin = require('./should-build-admin');
|
|
6
|
+
const watchAdminFiles = require('./watch-admin-files');
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
createCacheDir,
|
|
10
|
+
getCustomWebpackConfig,
|
|
11
|
+
shouldBuildAdmin,
|
|
12
|
+
watchAdminFiles,
|
|
13
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_PLUGINS = [
|
|
7
|
+
'content-type-builder',
|
|
8
|
+
'content-manager',
|
|
9
|
+
'upload',
|
|
10
|
+
'email',
|
|
11
|
+
'i18n',
|
|
12
|
+
'users-permissions',
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks if the project's installed plugins are not the same as a default one.
|
|
17
|
+
* @param {Object} plugins
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
const hasNonDefaultPlugins = plugins => {
|
|
21
|
+
// List of plugins that are not the ones installed in a generated app
|
|
22
|
+
const installedPlugins = Object.keys(plugins).filter(x => !DEFAULT_PLUGINS.includes(x));
|
|
23
|
+
|
|
24
|
+
// List of default plugins uninstalled from a generated app
|
|
25
|
+
const missingPlugins = DEFAULT_PLUGINS.filter(x => !Object.keys(plugins).includes(x));
|
|
26
|
+
|
|
27
|
+
const diff = [...installedPlugins, ...missingPlugins];
|
|
28
|
+
|
|
29
|
+
return diff.length > 0;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const hasCustomAdminCode = async (dir, useTypeScript) => {
|
|
33
|
+
const customAdminPath = path.join(dir, 'src', 'admin');
|
|
34
|
+
const customAdminConfigFileExtension = useTypeScript ? 'app.tsx' : 'app.js';
|
|
35
|
+
const customAdminConfigFile = path.join(customAdminPath, customAdminConfigFileExtension);
|
|
36
|
+
const customAdminWebpackFile = path.join(customAdminPath, 'webpack.config.js');
|
|
37
|
+
|
|
38
|
+
const hasCustomConfigFile = await fs.pathExists(customAdminConfigFile);
|
|
39
|
+
const hasCustomWebpackFile = await fs.pathExists(customAdminWebpackFile);
|
|
40
|
+
|
|
41
|
+
return hasCustomConfigFile || hasCustomWebpackFile;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const shouldBuildAdmin = async ({ appDir, plugins, useTypeScript }) => {
|
|
45
|
+
const appHasCustomAdminCode = await hasCustomAdminCode(appDir, useTypeScript);
|
|
46
|
+
const appHasNonDefaultPlugins = hasNonDefaultPlugins(plugins);
|
|
47
|
+
|
|
48
|
+
return appHasCustomAdminCode || appHasNonDefaultPlugins;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
module.exports = shouldBuildAdmin;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const chokidar = require('chokidar');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Listen to files change and copy the changed files in the .cache/admin folder
|
|
9
|
+
* when using the dev mode
|
|
10
|
+
* @param {string} dir
|
|
11
|
+
*/
|
|
12
|
+
async function watchAdminFiles(dir, useTypeScript) {
|
|
13
|
+
const cacheDir = path.join(dir, '.cache');
|
|
14
|
+
const targetExtensionFile = useTypeScript ? 'app.tsx' : 'app.js';
|
|
15
|
+
const appExtensionFile = path.join(dir, 'src', 'admin', targetExtensionFile);
|
|
16
|
+
const extensionsPath = path.join(dir, 'src', 'admin', 'extensions');
|
|
17
|
+
|
|
18
|
+
// Only watch the admin/app.js file and the files that are in the ./admin/extensions/folder
|
|
19
|
+
const filesToWatch = [appExtensionFile, extensionsPath];
|
|
20
|
+
|
|
21
|
+
const watcher = chokidar.watch(filesToWatch, {
|
|
22
|
+
ignoreInitial: true,
|
|
23
|
+
ignorePermissionErrors: true,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
watcher.on('all', async (event, filePath) => {
|
|
27
|
+
const isAppFile = filePath.includes(appExtensionFile);
|
|
28
|
+
|
|
29
|
+
// The app.js file needs to be copied in the .cache/admin/src/app.js and the other ones needs to
|
|
30
|
+
// be copied in the .cache/admin/src/extensions folder
|
|
31
|
+
const targetPath = isAppFile
|
|
32
|
+
? path.join(path.normalize(filePath.split(appExtensionFile)[1]), targetExtensionFile)
|
|
33
|
+
: path.join('extensions', path.normalize(filePath.split(extensionsPath)[1]));
|
|
34
|
+
|
|
35
|
+
const destFolder = path.join(cacheDir, 'admin', 'src');
|
|
36
|
+
|
|
37
|
+
if (event === 'unlink' || event === 'unlinkDir') {
|
|
38
|
+
// Remove the file or folder
|
|
39
|
+
// We need to copy the original files when deleting an override one
|
|
40
|
+
try {
|
|
41
|
+
fs.removeSync(path.join(destFolder, targetPath));
|
|
42
|
+
} catch (err) {
|
|
43
|
+
console.log('An error occured while deleting the file', err);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
// In any other case just copy the file into the .cache/admin/src folder
|
|
47
|
+
try {
|
|
48
|
+
await fs.copy(filePath, path.join(destFolder, targetPath));
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.log(err);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = watchAdminFiles;
|
package/webpack.config.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const webpack = require('webpack');
|
|
5
5
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
6
|
+
const ForkTsCheckerPlugin = require('fork-ts-checker-webpack-plugin');
|
|
6
7
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
7
8
|
const TerserPlugin = require('terser-webpack-plugin');
|
|
8
9
|
const WebpackBar = require('webpackbar');
|
|
@@ -12,12 +13,13 @@ const alias = require('./webpack.alias');
|
|
|
12
13
|
const getClientEnvironment = require('./env');
|
|
13
14
|
|
|
14
15
|
module.exports = ({
|
|
15
|
-
|
|
16
|
+
appDir,
|
|
16
17
|
cacheDir,
|
|
17
|
-
pluginsPath,
|
|
18
18
|
dest,
|
|
19
|
+
entry,
|
|
19
20
|
env,
|
|
20
21
|
optimize,
|
|
22
|
+
pluginsPath,
|
|
21
23
|
options = {
|
|
22
24
|
backend: 'http://localhost:1337',
|
|
23
25
|
adminPath: '/admin/',
|
|
@@ -27,6 +29,7 @@ module.exports = ({
|
|
|
27
29
|
eeRoot: './ee/admin',
|
|
28
30
|
ceRoot: './admin/src',
|
|
29
31
|
},
|
|
32
|
+
useTypeScript,
|
|
30
33
|
}) => {
|
|
31
34
|
const isProduction = env === 'production';
|
|
32
35
|
|
|
@@ -47,6 +50,35 @@ module.exports = ({
|
|
|
47
50
|
]
|
|
48
51
|
: [];
|
|
49
52
|
|
|
53
|
+
if (useTypeScript) {
|
|
54
|
+
const tsChecker = new ForkTsCheckerPlugin({
|
|
55
|
+
typescript: {
|
|
56
|
+
// FIXME
|
|
57
|
+
configFile: path.join(appDir, 'tsconfig-admin.json'),
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
webpackPlugins.push(tsChecker);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const rules = [];
|
|
65
|
+
|
|
66
|
+
// webpack is quite slow to compile so it is best not to use the ts loader when
|
|
67
|
+
// it is not needed in javascript apps.
|
|
68
|
+
// Users can still add it by using the custom webpack config.
|
|
69
|
+
if (useTypeScript) {
|
|
70
|
+
rules.push({
|
|
71
|
+
test: /\.tsx?$/,
|
|
72
|
+
loader: require.resolve('esbuild-loader'),
|
|
73
|
+
include: [cacheDir, ...pluginsPath],
|
|
74
|
+
exclude: /node_modules/,
|
|
75
|
+
options: {
|
|
76
|
+
loader: 'tsx',
|
|
77
|
+
target: 'es2015',
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
50
82
|
return {
|
|
51
83
|
mode: isProduction ? 'production' : 'development',
|
|
52
84
|
bail: isProduction ? true : false,
|
|
@@ -166,12 +198,13 @@ module.exports = ({
|
|
|
166
198
|
},
|
|
167
199
|
},
|
|
168
200
|
},
|
|
201
|
+
...rules,
|
|
169
202
|
],
|
|
170
203
|
},
|
|
171
204
|
resolve: {
|
|
172
205
|
alias,
|
|
173
206
|
symlinks: false,
|
|
174
|
-
extensions: ['.js', '.jsx', '.react.js'],
|
|
207
|
+
extensions: ['.js', '.jsx', '.react.js', '.ts', '.tsx'],
|
|
175
208
|
mainFields: ['browser', 'jsnext:main', 'main'],
|
|
176
209
|
modules: ['node_modules', path.resolve(__dirname, 'node_modules')],
|
|
177
210
|
},
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<rect x="3" y="3" width="18" height="18" rx="4" fill="#4945FF"/>
|
|
3
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.8075 7.625H9.03058V11.1792H12.2533C12.4977 11.1792 12.6958 11.3773 12.6958 11.6216V14.8444H16.25V8.06746C16.25 7.82309 16.0519 7.625 15.8075 7.625Z" fill="white"/>
|
|
4
|
-
<path opacity="0.4" fill-rule="evenodd" clip-rule="evenodd" d="M9.0308 7.625V11.1792H6.01073C5.81364 11.1792 5.71494 10.9409 5.8543 10.8015L9.0308 7.625ZM13.0735 18.0209C12.9342 18.1603 12.6959 18.0616 12.6959 17.8645V14.8444H16.25L13.0735 18.0209ZM12.4746 11.1792H9.03058V14.4019C9.03058 14.6463 9.22868 14.8444 9.47304 14.8444H12.6958V11.4004C12.6958 11.2782 12.5968 11.1792 12.4746 11.1792Z" fill="#DAD9FF"/>
|
|
5
|
-
</svg>
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { useQuery } from 'react-query';
|
|
2
|
-
import { useNotification } from '@strapi/helper-plugin';
|
|
3
|
-
import { fetchInstalledPlugins } from './utils/api';
|
|
4
|
-
|
|
5
|
-
const useFetchInstalledPlugins = notifyLoad => {
|
|
6
|
-
const toggleNotification = useNotification();
|
|
7
|
-
|
|
8
|
-
return useQuery('list-installed-plugins', () => fetchInstalledPlugins(), {
|
|
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 useFetchInstalledPlugins;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { useQuery } from 'react-query';
|
|
2
|
-
import { useNotification } from '@strapi/helper-plugin';
|
|
3
|
-
import { fetchMarketplacePlugins } from './utils/api';
|
|
4
|
-
|
|
5
|
-
const useFetchMarketplacePlugins = notifyLoad => {
|
|
6
|
-
const toggleNotification = useNotification();
|
|
7
|
-
|
|
8
|
-
return useQuery('list-marketplace-plugins', () => 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 useFetchMarketplacePlugins;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
|
|
3
|
-
const MARKETPLACE_API_URL = 'https://market-api.strapi.io';
|
|
4
|
-
|
|
5
|
-
const fetchMarketplacePlugins = async () => {
|
|
6
|
-
const { data: response } = await axios.get(`${MARKETPLACE_API_URL}/plugins`);
|
|
7
|
-
|
|
8
|
-
// Only keep v4 plugins
|
|
9
|
-
const filteredResponse = {
|
|
10
|
-
...response,
|
|
11
|
-
data: response.data.filter(plugin => plugin.attributes.strapiCompatibility === 'v4'),
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
return filteredResponse;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export { fetchMarketplacePlugins };
|
|
@@ -1,27 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,30 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,186 +0,0 @@
|
|
|
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;
|