Merge branch 'master' into fix-838

This commit is contained in:
Jim LAURIE 2018-04-26 16:12:55 +02:00 committed by GitHub
commit 0410f12cb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 340 additions and 246 deletions

File diff suppressed because one or more lines are too long

View File

@ -10,17 +10,20 @@
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"analyze": "node ./node_modules/strapi-helper-plugin/lib/internals/scripts/analyze.js",
"prebuild": "APP_PATH=$APP_PATH node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/lib/internals/scripts/loadAdminConfigurations.js",
"build:dev": "npm run build:dll && node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build": "APP_PATH=$APP_PATH npm run build:dll && node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build:dll": "APP_PATH=$APP_PATH node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.dll.babel.js --color -p --progress",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"prestart": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development PORT=4000 IS_ADMIN=true node ./node_modules/strapi-helper-plugin/lib/internals/scripts/loadAdminConfigurations.js",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development PORT=4000 IS_ADMIN=true node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/plop --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path ./admin/.gitignore --ignore-pattern build --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "npm run lint",
"prepublishOnly": "npm run build",
"setup": "node ./scripts/setup.js"
"setup": "node ./scripts/setup.js",
"presetup": "node ./scripts/preSetup.js"
},
"dependencies": {
"react-ga": "^2.4.1",
@ -49,4 +52,4 @@
"npm": ">= 5.0.0"
},
"license": "MIT"
}
}

View File

@ -0,0 +1,43 @@
const shell = require('shelljs');
const path = require('path');
const _ = require('lodash');
shell.echo('');
shell.echo('🕓 The setup process can take few minutes.');
shell.echo('');
shell.echo('🔸 Administration Panel');
shell.echo('📦 Installing packages...');
const pwd = shell.pwd();
const silent = process.env.npm_config_debug !== 'true';
const isDevelopmentMode = path.resolve(pwd.stdout).indexOf('strapi-admin') !== -1;
const appPath = isDevelopmentMode ? path.resolve(process.env.PWD, '..') : path.resolve(pwd.stdout, '..');
// We just install the admin's dependencies here
// Remove package-lock.json.
shell.rm('-rf', path.resolve(appPath, 'package-lock.json'));
shell.rm('-rf', path.resolve(appPath, 'admin', 'package-lock.json'));
// Install the project dependencies.
shell.exec(`cd "${appPath}" && npm install --ignore-scripts`, {
silent
});
// Install the administration dependencies.
shell.exec(`cd "${path.resolve(appPath, 'admin')}" && npm install`, {
silent
});
if (isDevelopmentMode) {
shell.exec(`cd "${path.resolve(appPath, 'admin')}" && npm link strapi-helper-plugin && npm link strapi-utils`, {
silent
});
} else {
shell.exec(`cd "${path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin')}" && npm install`, {
silent
});
}
shell.echo('Packaged installed successfully');

View File

@ -1,44 +1,15 @@
const fs = require('fs');
const shell = require('shelljs');
const path = require('path');
const _ = require('lodash');
shell.echo('');
shell.echo('🕓 The setup process can take few minutes.');
shell.echo('');
shell.echo('🔸 Administration Panel');
shell.echo('📦 Installing packages...');
const pwd = shell.pwd();
const silent = process.env.npm_config_debug !== 'true';
const isDevelopmentMode = path.resolve(pwd.stdout).indexOf('strapi-admin') !== -1;
const appPath = isDevelopmentMode ? path.resolve(process.env.PWD, '..') : path.resolve(pwd.stdout, '..');
// Remove package-lock.json.
shell.rm('-rf', path.resolve(appPath, 'package-lock.json'));
shell.rm('-rf', path.resolve(appPath, 'admin', 'package-lock.json'));
// Install the project dependencies.
shell.exec(`cd "${appPath}" && npm install --ignore-scripts`, {
silent
});
// Install the administration dependencies.
shell.exec(`cd "${path.resolve(appPath, 'admin')}" && npm install`, {
silent
});
if (isDevelopmentMode) {
shell.exec(`cd "${path.resolve(appPath, 'admin')}" && npm link strapi-helper-plugin && npm link strapi-utils`, {
silent
});
} else {
shell.exec(`cd "${path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin')}" && npm install`, {
silent
});
}
shell.echo('🏗 Building...');
shell.echo('🏗 Building the admin...');
const build = shell.exec(`cd "${path.resolve(appPath, 'admin')}" && APP_PATH="${appPath}" npm run build`, {
silent
@ -55,35 +26,49 @@ shell.echo('');
if (process.env.npm_config_plugins === 'true') {
const plugins = path.resolve(appPath, 'plugins');
shell.ls('* -d', plugins).forEach(function (plugin) {
shell.echo(`🔸 Plugin - ${_.upperFirst(plugin)}`);
shell.echo('📦 Installing packages...');
shell.exec(`cd "${path.resolve(plugins, plugin)}" && npm install`, {
silent
});
// TODO: build plugins in async
shell.ls('* -d', plugins)
.filter(x => {
let hasAdminFolder;
if (isDevelopmentMode) {
shell.exec(`cd "${path.resolve(plugins, plugin)}" && npm link strapi-helper-plugin`, {
try {
fs.accessSync(path.resolve(appPath, 'plugins', x, 'admin', 'src', 'containers', 'App'));
hasAdminFolder = true;
} catch(err) {
hasAdminFolder = false;
}
return hasAdminFolder;
})
.forEach(function (plugin) {
shell.echo(`🔸 Plugin - ${_.upperFirst(plugin)}`);
shell.echo('📦 Installing packages...');
shell.exec(`cd "${path.resolve(plugins, plugin)}" && npm install`, {
silent
});
} else {
shell.exec(`cd "${path.resolve(plugins, plugin, 'node_modules', 'strapi-helper-plugin')}" && npm install`, {
if (isDevelopmentMode) {
shell.exec(`cd "${path.resolve(plugins, plugin)}" && npm link strapi-helper-plugin`, {
silent
});
} else {
shell.exec(`cd "${path.resolve(plugins, plugin, 'node_modules', 'strapi-helper-plugin')}" && npm install`, {
silent
});
}
shell.echo('🏗 Building...');
const build = shell.exec(`cd "${path.resolve(plugins, plugin)}" && APP_PATH="${appPath}" npm run build`, {
silent
});
}
shell.echo('🏗 Building...');
if (build.stderr && build.code !== 0) {
console.error(build.stderr);
process.exit(1);
}
const build = shell.exec(`cd "${path.resolve(plugins, plugin)}" && APP_PATH="${appPath}" npm run build`, {
silent
shell.echo('✅ Success');
shell.echo('');
});
if (build.stderr && build.code !== 0) {
console.error(build.stderr);
process.exit(1);
}
shell.echo('✅ Success');
shell.echo('');
});
}

View File

@ -0,0 +1,22 @@
const path = require('path');
const shell = require('shelljs');
const pwd = shell.pwd();
const isDevelopmentMode = path.resolve(pwd.stdout).indexOf('strapi-admin') !== -1;
const appPath = isDevelopmentMode ? path.resolve(process.env.PWD, '..') : path.resolve(pwd.stdout, '..');
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
// Load the app configurations only when :
// - starting the app in dev mode
// - building the admin from an existing app (`npm run setup` at the root of the project)
if (!isSetup) {
const strapi = require(path.join(appPath, 'node_modules', 'strapi'));
strapi.config.appPath = appPath;
strapi.log.level = 'silent';
(async () => {
await strapi.load({
environment: process.env.NODE_ENV,
});
})();
}

View File

@ -12,6 +12,8 @@ const pkg = require(path.resolve(process.cwd(), 'package.json'));
const pluginId = pkg.name.replace(/^strapi-/i, '');
const isAdmin = process.env.IS_ADMIN === 'true';
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const appPath = (() => {
if (process.env.APP_PATH) {
return process.env.APP_PATH;
@ -28,25 +30,6 @@ const adminPath = (() => {
return path.resolve(process.env.PWD);
})();
if (!isSetup) {
try {
// Load app' configurations to update `plugins.json` automatically.
const strapi = require(path.join(appPath, 'node_modules', 'strapi'));
strapi.config.appPath = appPath;
strapi.log.level = 'silent';
(async () => {
await strapi.load({
environment: process.env.NODE_ENV,
});
})();
} catch (e) {
console.log(e);
throw new Error(`You need to start the WebPack server from the /admin or /plugins/**/admin directories in a Strapi's project.`);
}
}
// Define remote and backend URLs.
const URLs = {
host: '/admin',
@ -100,7 +83,9 @@ if (process.env.npm_lifecycle_event === 'start') {
plugins.exist = true;
}
// Read `plugins` directory and check if the plugin comes with an UI.
// Read `plugins` directory and check if the plugin comes with an UI (it has an App container).
// If we don't do this check webpack expects the plugin to have a containers/App/reducer.js to create
// the plugin's store (redux).
plugins.src = isAdmin && !plugins.exist ? fs.readdirSync(path.resolve(appPath, 'plugins')).filter(x => {
let hasAdminFolder;
@ -121,166 +106,221 @@ if (process.env.npm_lifecycle_event === 'start') {
}, {});
}
module.exports = (options) => ({
entry: options.entry,
output: Object.assign({ // Compile into js/build.js
path: path.join(adminPath, 'admin', 'build'),
}, options.output), // Merge with env dependent settings
module: {
loaders: [{
test: /\.js$/, // Transform all .js files required somewhere with Babel,
use: {
loader: 'babel-loader',
options: {
presets: options.babelPresets,
env: {
production: {
only: [
'src',
],
plugins: [
require.resolve('babel-plugin-transform-react-remove-prop-types'),
require.resolve('babel-plugin-transform-react-constant-elements'),
require.resolve('babel-plugin-transform-react-inline-elements'),
require.resolve('babel-plugin-transform-es2015-destructuring'),
require.resolve('babel-plugin-transform-es2015-parameters'),
require.resolve('babel-plugin-transform-object-rest-spread'),
],
},
test: {
plugins: [
'istanbul',
],
},
},
},
},
include: [path.join(adminPath, 'admin', 'src')]
.concat(plugins.src.reduce((acc, current) => {
acc.push(path.resolve(appPath, 'plugins', current, 'admin', 'src'), plugins.folders[current]);
// Tell webpack to use a loader only for those files
const foldersToInclude = [path.join(adminPath, 'admin', 'src')]
.concat(plugins.src.reduce((acc, current) => {
acc.push(path.resolve(appPath, 'plugins', current, 'admin', 'src'), plugins.folders[current]);
return acc;
}, []))
.concat([path.join(adminPath, 'node_modules', 'strapi-helper-plugin', 'lib', 'src')]),
}, {
// Transform our own .scss files
test: /\.scss$/,
use: [{
loader: 'style-loader',
}, {
loader: 'css-loader',
options: {
localIdentName: `${pluginId}[local]__[path][name]__[hash:base64:5]`,
modules: true,
importLoaders: 1,
sourceMap: true,
minimize: process.env.NODE_ENV === 'production',
},
}, {
loader: 'postcss-loader',
options: {
config: {
path: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
},
},
}, {
loader: 'sass-loader',
}],
}, {
// Do not transform vendor's CSS with CSS-modules
// The point is that they remain in global scope.
// Since we require these CSS files in our JS or CSS files,
// they will be a part of our compilation either way.
// So, no need for ExtractTextPlugin here.
test: /\.css$/,
include: /node_modules/,
loaders: ['style-loader', {
loader: 'css-loader',
options: {
minimize: process.env.NODE_ENV === 'production',
sourceMap: true,
},
}],
}, {
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file-loader',
}, {
test: /\.(jpg|png|gif)$/,
loaders: [
'file-loader',
return acc;
}, []))
.concat([path.join(adminPath, 'node_modules', 'strapi-helper-plugin', 'lib', 'src')]);
module.exports = (options) => {
// The disable option is only for production
// Config from https://github.com/facebook/create-react-app/blob/next/packages/react-scripts/config/webpack.config.prod.js
const extractSass = new ExtractTextPlugin({
filename: '[name].[contenthash].css',
disable: options.disableExtractTextPlugin || true,
});
return {
entry: options.entry,
output: Object.assign({ // Compile into js/build.js
path: path.join(adminPath, 'admin', 'build'),
}, options.output), // Merge with env dependent settings
module: {
rules: [ // TODO: add eslint formatter
{
loader: 'image-webpack-loader',
query: {
mozjpeg: {
progressive: true,
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
// back to the "file" loader at the end of the loader list.
oneOf: [
{
test: /\.js$/, // Transform all .js files required somewhere with Babel,
loader: require.resolve('babel-loader'),
include: foldersToInclude,
options: {
presets: options.babelPresets,
env: {
production: {
only: [
'src',
],
plugins: [
require.resolve('babel-plugin-transform-react-remove-prop-types'),
require.resolve('babel-plugin-transform-react-constant-elements'),
require.resolve('babel-plugin-transform-react-inline-elements'),
require.resolve('babel-plugin-transform-es2015-destructuring'),
require.resolve('babel-plugin-transform-es2015-parameters'),
require.resolve('babel-plugin-transform-object-rest-spread'),
],
},
test: {
plugins: [
'istanbul',
],
},
},
},
},
gifsicle: {
interlaced: false,
// The notation here is somewhat confusing.
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader normally turns CSS into JS modules injecting <style>,
// but unlike in development configuration, we do something different.
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
// (second argument), then grabs the result CSS and puts it into a
// separate file in our build process. This way we actually ship
// a single CSS file in production instead of JS code injecting <style>
// tags. If you use code splitting, however, any async bundles will still
// use the "style" loader inside the async code so CSS from them won't be
// in the main CSS file.
{
test: /\.css$/,
include: /node_modules/,
use: extractSass.extract({
fallback: require.resolve('style-loader'),
use: [
{
loader: require.resolve('css-loader'),
options: {
minimize: process.env.NODE_ENV === 'production',
sourceMap: false,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
config: {
path: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
},
},
},
],
}),
},
optipng: {
optimizationLevel: 4,
{
test: /\.scss$/,
include: foldersToInclude,
use: extractSass.extract({
use: [
{
loader: require.resolve('css-loader'),
options: {
localIdentName: `${pluginId}[local]__[path][name]__[hash:base64:5]`,
modules: true,
importLoaders: 1,
sourceMap: false,
minimize: process.env.NODE_ENV === 'production',
},
},
{
loader: require.resolve('postcss-loader'),
options: {
config: {
path: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
},
},
},
{
loader: 'sass-loader',
},
],
fallback: require.resolve('style-loader'),
}),
},
pngquant: {
quality: '65-90',
speed: 4,
{
test: /\.(eot|svg|otf|ttf|woff|woff2)$/,
use: 'file-loader',
},
},
{
test: /\.(jpg|png|gif)$/,
loaders: [
require.resolve('file-loader'),
{
loader: require.resolve('image-webpack-loader'),
query: {
mozjpeg: {
progressive: true,
},
gifsicle: {
interlaced: false,
},
optipng: {
optimizationLevel: 4,
},
pngquant: {
quality: '65-90',
speed: 4,
},
},
},
],
},
{
test: /\.html$/,
include: [path.join(adminPath, 'admin', 'src')],
use: require.resolve('html-loader'),
},
{
test: /\.(mp4|webm)$/,
loader: require.resolve('url-loader'),
options: {
limit: 10000,
},
},
],
},
],
}, {
test: /\.html$/,
loader: 'html-loader',
}, {
test: /\.(mp4|webm)$/,
loader: 'url-loader?limit=10000',
}],
},
plugins: [
new webpack.ProvidePlugin({
// make fetch available
fetch: 'exports-loader?self.fetch!whatwg-fetch',
}),
},
plugins: [
new webpack.ProvidePlugin({
// make fetch available
fetch: 'exports-loader?self.fetch!whatwg-fetch',
}),
// Always expose NODE_ENV to webpack, in order to use `process.env.NODE_ENV`
// inside your code for any environment checks; UglifyJS will automatically
// drop any unreachable code.
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
REMOTE_URL: JSON.stringify(URLs.host),
BACKEND_URL: JSON.stringify(URLs.backend),
MODE: JSON.stringify(URLs.mode), // Allow us to define the public path for the plugins assets.
},
}),
new webpack.NamedModulesPlugin(),
].concat(options.plugins),
resolve: {
modules: [
'admin/src',
'node_modules/strapi-helper-plugin/lib/src',
'node_modules/strapi-helper-plugin/node_modules',
'node_modules',
],
alias: options.alias,
symlinks: false,
extensions: [
'.js',
'.jsx',
'.react.js',
],
mainFields: [
'browser',
'jsnext:main',
'main',
],
},
externals: options.externals,
resolveLoader: {
modules: [
path.join(__dirname, '..', '..', '..', 'node_modules'),
path.join(process.cwd(), 'node_modules'),
],
},
devtool: options.devtool,
target: 'web', // Make web variables accessible to webpack, e.g. window,
});
// Always expose NODE_ENV to webpack, in order to use `process.env.NODE_ENV`
// inside your code for any environment checks; UglifyJS will automatically
// drop any unreachable code.
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
REMOTE_URL: JSON.stringify(URLs.host),
BACKEND_URL: JSON.stringify(URLs.backend),
MODE: JSON.stringify(URLs.mode), // Allow us to define the public path for the plugins assets.
},
}),
new webpack.NamedModulesPlugin(),
extractSass,
].concat(options.plugins),
resolve: {
modules: [
'admin/src',
'node_modules/strapi-helper-plugin/lib/src',
'node_modules/strapi-helper-plugin/node_modules',
'node_modules',
],
alias: options.alias,
symlinks: false,
extensions: [
'.js',
'.jsx',
'.react.js',
],
mainFields: [
'browser',
'jsnext:main',
'main',
],
},
externals: options.externals,
resolveLoader: {
modules: [
path.join(__dirname, '..', '..', '..', 'node_modules'),
path.join(process.cwd(), 'node_modules'),
],
},
devtool: options.devtool,
target: 'web', // Make web variables accessible to webpack, e.g. window,
};
};

View File

@ -48,7 +48,8 @@ if (process.env.npm_lifecycle_event === 'start') {
plugins.src = process.env.IS_ADMIN === 'true' && !plugins.exist ? fs.readdirSync(path.resolve(appPath, 'plugins')).filter(x => {
let hasAdminFolder;
// Don't inject the plugins that don't have an admin into the app
try {
fs.accessSync(path.resolve(appPath, 'plugins', x, 'admin', 'src', 'containers', 'App'));
hasAdminFolder = true;

View File

@ -3,7 +3,6 @@ const path = require('path');
const _ = require('lodash');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const cssnext = require('postcss-cssnext');
const postcssFocus = require('postcss-focus');
const postcssReporter = require('postcss-reporter');
@ -14,10 +13,6 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
const base = require('./webpack.base.babel');
// const pkg = require(path.resolve(process.cwd(), 'package.json'));
// const pluginId = pkg.name.replace(/^strapi-plugin-/i, '');
// const dllPlugin = pkg.dllPlugin;
const isAdmin = process.env.IS_ADMIN === 'true';
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const appPath = (() => {
@ -105,7 +100,6 @@ if (isAdmin) {
chunks: ['main'],
inject: true,
}));
plugins.push(new ExtractTextPlugin('[name].[contenthash].css'));
plugins.push(new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, 'dist/*.dll.js'),
}));
@ -180,4 +174,5 @@ module.exports = base({
},
devtool: 'cheap-module-source-map',
disableExtractTextPlugin: false,
});

View File

@ -7,7 +7,7 @@
import React from 'react';
import moment from 'moment';
import PropTypes from 'prop-types';
// import DateTimeStyle from 'react-datetime/css/react-datetime.css';
import DateTimeStyle from 'react-datetime/css/react-datetime.css'; /* eslint-disable-line no-unused-vars */
import DateTime from 'react-datetime';
import { FormattedMessage } from 'react-intl';
import { isEmpty, isObject } from 'lodash';

View File

@ -47,4 +47,4 @@
"npm": ">= 5.0.0"
},
"license": "MIT"
}
}

View File

@ -81,7 +81,9 @@ function formReducer(state = initialState, action) {
case RESET_FORM_ERRORS:
return state.set('formErrors', List());
case RESET_IS_FORM_SET:
return state.set('isFormSet', false);
return state
.set('isFormSet', false)
.update('modifiedData', () => Map({}));
case SET_ATTRIBUTE_FORM: {
if (state.get('isFormSet')) {
return state

View File

@ -4,7 +4,8 @@ export default function checkAttributeValidations(errors) {
const attributeIndex = split(this.props.hash, '::')[3];
const sameAttributes = filter(this.props.contentTypeData.attributes, (attr) => attr.name === this.props.modifiedDataAttribute.name);
const sameParamsKey = filter(this.props.contentTypeData.attributes, (attr) => attr.params.key === this.props.modifiedDataAttribute.params.key);
const sameParamsKey = filter(this.props.contentTypeData.attributes, (attr) =>
attr.params.key === this.props.modifiedDataAttribute.params.key && attr.params.target === this.props.modifiedDataAttribute.params.target);
const sameParamsKeyAndName = filter(this.props.contentTypeData.attributes, (attr) => attr.name === this.props.modifiedDataAttribute.params.key);
const formErrors = concat(errors, hasNestedValue(this.props.modifiedDataAttribute));
const isEditingParamsKey = this.props.modifiedDataAttribute.params.key !== get(this.props.contentTypeData.attributes, [attributeIndex, 'params', 'key']);

View File

@ -51,4 +51,4 @@
"npm": ">= 5.0.0"
},
"license": "MIT"
}
}

View File

@ -48,4 +48,4 @@
"npm": ">= 5.0.0"
},
"license": "MIT"
}
}

View File

@ -48,4 +48,4 @@
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -55,4 +55,4 @@
"npm": ">= 5.0.0"
},
"license": "MIT"
}
}

View File

@ -176,6 +176,8 @@ class Strapi extends EventEmitter {
}
async load() {
await this.enhancer();
this.app.use(async (ctx, next) => {
if (ctx.request.url === '/_health' && ctx.request.method === 'HEAD') {
ctx.set('strapi', 'You are so French!');