Merge branch 'cm-configure-view-lv' of https://github.com/strapi/strapi into cm-settings/drag-and-drop

This commit is contained in:
ronronscelestes 2021-10-18 16:54:24 +02:00
commit 5cce0eb854
30 changed files with 175 additions and 440 deletions

View File

@ -100,6 +100,7 @@ function ListView({
try {
const opts = source ? { cancelToken: source.token } : null;
const {
data: { results, pagination: paginationResult },
} = await axiosInstance.get(endPoint, opts);

View File

@ -4,19 +4,16 @@ import createPluginsFilter from './createPluginsFilter';
/**
* Creates a valid query string from an object of queryParams
* This includes:
* - a _where clause
* - a filters clause
* - plugin options
*/
const buildQueryString = (queryParams = {}) => {
const _where = queryParams._where || [];
/**
* Extracting pluginOptions from the query since we don't want them to be part
* of the url
*/
const { plugins: _, ...otherQueryParams } = {
...queryParams,
_where,
...createPluginsFilter(queryParams.plugins),
};

View File

@ -1,13 +1,4 @@
const createPluginsFilter = obj =>
Object.values(obj || {}).reduce((acc, current) => {
return {
...acc,
...Object.keys(current).reduce((accumulator, key) => {
accumulator[`_${key}`] = current[key];
return accumulator;
}, {}),
};
}, {});
Object.values(obj || {}).reduce((acc, current) => Object.assign(acc, current), {});
export default createPluginsFilter;

View File

@ -25,28 +25,28 @@ describe('buildQueryString', () => {
const queryString = buildQueryString(queryParams);
expect(queryString).toBe('?page=1&pageSize=10&sort=name:ASC&_locale=en');
expect(queryString).toBe('?page=1&pageSize=10&sort=name:ASC&locale=en');
});
it('creates a valid query string with a _where clause', () => {
it('creates a valid query string with a filters clause', () => {
const queryParams = {
page: '1',
pageSize: '10',
sort: 'name:ASC',
_where: [{ name: 'hello world' }],
filters: [{ name: 'hello world' }],
};
const queryString = buildQueryString(queryParams);
expect(queryString).toBe('?page=1&pageSize=10&sort=name:ASC&_where[0][name]=hello world');
expect(queryString).toBe('?page=1&pageSize=10&sort=name:ASC&filters[0][name]=hello world');
});
it('creates a valid query string with a _where and plugin options', () => {
it('creates a valid query string with a filters and plugin options', () => {
const queryParams = {
page: '1',
pageSize: '10',
sort: 'name:ASC',
_where: [{ name: 'hello world' }],
filters: [{ name: 'hello world' }],
plugins: {
i18n: { locale: 'en' },
},
@ -55,7 +55,7 @@ describe('buildQueryString', () => {
const queryString = buildQueryString(queryParams);
expect(queryString).toBe(
'?page=1&pageSize=10&sort=name:ASC&_where[0][name]=hello world&_locale=en'
'?page=1&pageSize=10&sort=name:ASC&filters[0][name]=hello world&locale=en'
);
});
});

View File

@ -1,55 +0,0 @@
// List of all the possible filters
const VALID_REST_OPERATORS = [
'eq',
'ne',
'in',
'nin',
'contains',
'ncontains',
'containss',
'ncontainss',
'lt',
'lte',
'gt',
'gte',
'null',
];
// from strapi-utils/convert-rest-query-params
const findAppliedFilter = whereClause => {
// Useful to remove the mainField of relation fields.
const formattedWhereClause = whereClause.split('.')[0];
const separatorIndex = whereClause.lastIndexOf('_');
if (separatorIndex === -1) {
return { operator: '=', field: formattedWhereClause };
}
const fieldName = formattedWhereClause.substring(0, separatorIndex);
const operator = whereClause.slice(separatorIndex + 1);
// the field as underscores
if (!VALID_REST_OPERATORS.includes(operator)) {
return { operator: '=', field: formattedWhereClause };
}
return { operator: `_${operator}`, field: fieldName };
};
const formatFiltersFromQuery = ({ _where }) => {
if (!_where) {
return [];
}
return _where.map(obj => {
const [key] = Object.keys(obj);
const { field, operator } = findAppliedFilter(key);
const value = obj[key];
return { name: field, filter: operator, value };
});
};
export default formatFiltersFromQuery;
export { findAppliedFilter };

View File

@ -1,27 +0,0 @@
import { get } from 'lodash';
const formatFilterName = (name, metadatas) => {
const mainField = get(metadatas, [name, 'list', 'mainField', 'name'], null);
if (mainField) {
return `${name}.${mainField}`;
}
return name;
};
const formatFiltersToQuery = (array, metadatas) => {
const nextFilters = array.map(({ name, filter, value }) => {
const formattedName = formatFilterName(name, metadatas);
if (filter === '=') {
return { [formattedName]: value };
}
return { [`${formattedName}${filter}`]: value };
});
return { _where: nextFilters };
};
export default formatFiltersToQuery;

View File

@ -2,8 +2,6 @@ export { default as arrayMoveItem } from './arrayMoveItem';
export { default as checkIfAttributeIsDisplayable } from './checkIfAttributeIsDisplayable';
export { default as createDefaultForm } from './createDefaultForm';
export { default as dateFormats } from './dateFormats';
export { default as formatFiltersFromQuery } from './formatFiltersFromQuery';
export { default as formatFiltersToQuery } from './formatFiltersToQuery';
export { default as formatLayoutToApi } from './formatLayoutToApi';
export { default as generatePermissionsObject } from './generatePermissionsObject';
export { default as getDisplayedValue } from './getDisplayedValue';

View File

@ -1,66 +0,0 @@
import formatFiltersFromQuery, { findAppliedFilter } from '../formatFiltersFromQuery';
describe('CONTENT MANAGER | utils', () => {
describe('findAppliedFilter', () => {
it('should return the correct filter', () => {
expect(findAppliedFilter('categories.name')).toEqual({ operator: '=', field: 'categories' });
expect(findAppliedFilter('categories.name_lt')).toEqual({
operator: '_lt',
field: 'categories',
});
expect(findAppliedFilter('city')).toEqual({ operator: '=', field: 'city' });
expect(findAppliedFilter('city_nee')).toEqual({ operator: '=', field: 'city_nee' });
expect(findAppliedFilter('city_ne')).toEqual({ operator: '_ne', field: 'city' });
expect(findAppliedFilter('city_lt')).toEqual({ operator: '_lt', field: 'city' });
expect(findAppliedFilter('city_lte')).toEqual({ operator: '_lte', field: 'city' });
expect(findAppliedFilter('city_gt')).toEqual({ operator: '_gt', field: 'city' });
expect(findAppliedFilter('city_gte')).toEqual({ operator: '_gte', field: 'city' });
});
});
describe('formatFiltersFromQuery', () => {
it('should return an empty array if there is no where clause', () => {
expect(formatFiltersFromQuery({})).toHaveLength(0);
});
it('should return array of filter', () => {
const query = {
_where: [
{
city_ne_ne: 'paris',
},
{
city_ne: 'paris',
},
{
city: 'paris',
},
{
'categories.name_ne': 'first',
},
{
'like.numbers_lt': 34,
},
],
};
const expected = [
{ name: 'city_ne', filter: '_ne', value: 'paris' },
{ name: 'city', filter: '_ne', value: 'paris' },
{ name: 'city', filter: '=', value: 'paris' },
{
name: 'categories',
filter: '_ne',
value: 'first',
},
{
name: 'like',
filter: '_lt',
value: 34,
},
];
expect(formatFiltersFromQuery(query)).toEqual(expected);
});
});
});

View File

@ -1,57 +0,0 @@
import formatFiltersToQuery from '../formatFiltersToQuery';
describe('CONTENT MANAGER | utils', () => {
describe('formatFiltersToQuery', () => {
it('should return the filters query', () => {
const metadatas = {
categories: {
list: {
mainField: { name: 'name' },
},
},
like: {
list: {
mainField: { name: 'numbers' },
},
},
};
const data = [
{ name: 'city_ne', filter: '_ne', value: 'paris' },
{ name: 'city', filter: '_ne', value: 'paris' },
{ name: 'city', filter: '=', value: 'paris' },
{
name: 'categories',
filter: '_ne',
value: 'first',
},
{
name: 'like',
filter: '_lt',
value: 34,
},
];
const expected = {
_where: [
{
city_ne_ne: 'paris',
},
{
city_ne: 'paris',
},
{
city: 'paris',
},
{
'categories.name_ne': 'first',
},
{
'like.numbers_lt': 34,
},
],
};
expect(formatFiltersToQuery(data, metadatas)).toEqual(expected);
});
});
});

View File

@ -223,7 +223,7 @@ module.exports = {
const params = {
...permissionQuery,
filters: {
$and: [idsWhereClause].concat(permissionQuery._where || []),
$and: [idsWhereClause].concat(permissionQuery.filters || []),
},
};

View File

@ -142,7 +142,7 @@ const createEntityManager = db => {
await db.lifecycles.run('beforeCount', uid, { params });
const res = await this.createQueryBuilder(uid)
.init(_.pick(['_q', 'where'], params))
.init(_.pick(['_q', 'where', 'filters'], params))
.count()
.first()
.execute();
@ -172,7 +172,7 @@ const createEntityManager = db => {
await this.attachRelations(uid, id, data);
// TODO: in case there is not select or populate specified return the inserted data ?
// TODO: in case there is no select or populate specified return the inserted data ?
// TODO: do not trigger the findOne lifecycles ?
const result = await this.findOne(uid, {
where: { id },
@ -296,7 +296,7 @@ const createEntityManager = db => {
throw new Error('Delete requires a where parameter');
}
// TODO: avoid trigger the findOne lifecycles in the case ?
// TODO: do not trigger the findOne lifecycles ?
const entity = await this.findOne(uid, {
select: select && ['id'].concat(select),
where,
@ -469,7 +469,6 @@ const createEntityManager = db => {
const { joinTable } = attribute;
const { joinColumn, inverseJoinColumn } = joinTable;
// TODO: validate logic of delete
if (isOneToAny(attribute) && isBidirectional(attribute)) {
await this.createQueryBuilder(joinTable.name)
.delete()

View File

@ -122,7 +122,11 @@ const applyPopulate = async (results, populate, ctx) => {
const attribute = meta.attributes[key];
const targetMeta = db.metadata.get(attribute.target);
const populateValue = pickPopulateParams(populate[key]);
const populateValue = {
...pickPopulateParams(populate[key]),
filters: qb.state.filters,
};
const isCount = populateValue.count === true;
const fromTargetRow = rowOrRows => fromRow(targetMeta, rowOrRows);

View File

@ -29,6 +29,7 @@ const createQueryBuilder = (uid, db) => {
return {
alias: getAlias(),
getAlias,
state,
select(args) {
state.type = 'select';
@ -115,7 +116,7 @@ const createQueryBuilder = (uid, db) => {
},
init(params = {}) {
const { _q, where, select, limit, offset, orderBy, groupBy, populate } = params;
const { _q, filters, where, select, limit, offset, orderBy, groupBy, populate } = params;
if (!_.isNil(where)) {
this.where(where);
@ -151,9 +152,17 @@ const createQueryBuilder = (uid, db) => {
this.populate(populate);
}
if (!_.isNil(filters)) {
this.filters(filters);
}
return this;
},
filters(filters) {
state.filters = filters;
},
first() {
state.first = true;
return this;
@ -206,6 +215,19 @@ const createQueryBuilder = (uid, db) => {
processState() {
state.orderBy = helpers.processOrderBy(state.orderBy, { qb: this, uid, db });
if (!_.isNil(state.filters)) {
if (_.isFunction(state.filters)) {
const filters = state.filters({ qb: this, uid, meta, db });
if (!_.isNil(filters)) {
state.where.push(filters);
}
} else {
state.where.push(state.filters);
}
}
state.where = helpers.processWhere(state.where, { qb: this, uid, db });
state.populate = helpers.processPopulate(state.populate, { qb: this, uid, db });
state.data = helpers.toRow(meta, state.data);

View File

@ -259,7 +259,7 @@ class Strapi {
}
stop(exitCode = 1) {
this.server.destroy();
this.destroy();
if (this.config.get('autoReload')) {
process.send('stop');
@ -431,7 +431,6 @@ class Strapi {
}
if (this.config.get('autoReload')) {
this.destroy();
process.send('reload');
}
};

View File

@ -52,14 +52,12 @@ module.exports = async function({ build, watchAdmin, polling, browser }) {
switch (message) {
case 'reload':
logger.info('The server is restarting\n');
worker.send('isKilled');
worker.send('kill');
break;
case 'kill':
worker.kill();
case 'killed':
cluster.fork();
break;
case 'stop':
worker.kill();
process.exit(1);
default:
return;
@ -85,10 +83,10 @@ module.exports = async function({ build, watchAdmin, polling, browser }) {
process.on('message', async message => {
switch (message) {
case 'isKilled':
await strapiInstance.server.destroy();
process.send('kill');
break;
case 'kill':
await strapiInstance.destroy();
process.send('killed');
process.exit();
default:
// Do nothing.
}

View File

@ -1,6 +1,6 @@
'use strict';
jest.mock('bcrypt', () => ({ hashSync: () => 'secret-password' }));
jest.mock('bcryptjs', () => ({ hashSync: () => 'secret-password' }));
const { EventEmitter } = require('events');
const createEntityService = require('../');

View File

@ -1,7 +1,7 @@
'use strict';
const { getOr, toNumber, isString, isBuffer } = require('lodash/fp');
const bcrypt = require('bcrypt');
const bcrypt = require('bcryptjs');
const transforms = {
password(value, context) {

View File

@ -1,7 +1,6 @@
'use strict';
const delegate = require('delegates');
const { pipe } = require('lodash/fp');
const {
sanitizeEntity,
@ -16,12 +15,7 @@ const {
updateComponents,
deleteComponents,
} = require('./components');
const {
transformCommonParams,
transformPaginationParams,
transformParamsToQuery,
pickSelectionParams,
} = require('./params');
const { transformParamsToQuery, pickSelectionParams } = require('./params');
const { applyTransforms } = require('./attributes');
// TODO: those should be strapi events used by the webhooks not the other way arround
@ -244,13 +238,26 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
const attribute = attributes[field];
const loadParams =
attribute.type === 'relation'
? transformParamsToQuery(attribute.target, params)
: pipe(
transformCommonParams,
transformPaginationParams
)(params);
const loadParams = {};
switch (attribute.type) {
case 'relation': {
Object.assign(loadParams, transformParamsToQuery(attribute.target, params));
break;
}
case 'component': {
Object.assign(loadParams, transformParamsToQuery(attribute.component, params));
break;
}
case 'dynamiczone': {
Object.assign(loadParams, transformParamsToQuery(null, params));
break;
}
case 'media': {
Object.assign(loadParams, transformParamsToQuery('plugin::upload.file', params));
break;
}
}
return db.query(uid).load(entity, field, loadParams);
},

View File

@ -1,6 +1,7 @@
'use strict';
const { pick, pipe, isNil } = require('lodash/fp');
const assert = require('assert').strict;
const { pick, isNil, toNumber, isInteger } = require('lodash/fp');
const {
convertSortQueryParams,
@ -9,62 +10,39 @@ const {
convertPopulateQueryParams,
convertFiltersQueryParams,
convertFieldsQueryParams,
convertPublicationStateParams,
} = require('@strapi/utils/lib/convert-query-params');
const { contentTypes: contentTypesUtils } = require('@strapi/utils');
const pickSelectionParams = pick(['fields', 'populate']);
const { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;
const transformParamsToQuery = (uid, params) => {
// NOTE: can be a CT, a Compo or nothing in the case of polymorphism (DZ & morph relations)
const type = strapi.getModel(uid);
// TODO: to remove once the front is migrated
const convertOldQuery = params => {
const query = {};
Object.keys(params).forEach(key => {
if (key.startsWith('_')) {
query[key.slice(1)] = params[key];
} else {
query[key] = params[key];
}
});
const { _q, sort, filters, fields, populate, page, pageSize, start, limit } = params;
return query;
};
const transformCommonParams = (params = {}) => {
const { _q, sort, filters, _where, fields, populate, ...query } = params;
if (_q) {
if (!isNil(_q)) {
query._q = _q;
}
if (sort) {
if (!isNil(sort)) {
query.orderBy = convertSortQueryParams(sort);
}
if (filters) {
if (!isNil(filters)) {
query.where = convertFiltersQueryParams(filters);
}
if (_where) {
query.where = {
$and: [_where].concat(query.where || []),
};
}
if (fields) {
if (!isNil(fields)) {
query.select = convertFieldsQueryParams(fields);
}
if (populate) {
if (!isNil(populate)) {
query.populate = convertPopulateQueryParams(populate);
}
return { ...convertOldQuery(query), ...query };
};
const transformPaginationParams = (params = {}) => {
const { page, pageSize, start, limit, ...query } = params;
const isPagePagination = !isNil(page) || !isNil(pageSize);
const isOffsetPagination = !isNil(start) || !isNil(limit);
@ -74,72 +52,38 @@ const transformPaginationParams = (params = {}) => {
);
}
if (page) {
query.page = Number(page);
if (!isNil(page)) {
const pageVal = toNumber(page);
const isValid = isInteger(pageVal) && pageVal > 0;
assert(isValid, `Invalid 'page' parameter. Expected an integer > 0, received: ${page}`);
query.page = pageVal;
}
if (pageSize) {
query.pageSize = Number(pageSize);
if (!isNil(pageSize)) {
const pageSizeVal = toNumber(pageSize);
const isValid = isInteger(pageSizeVal) && pageSizeVal > 0;
assert(isValid, `Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`);
query.pageSize = pageSizeVal;
}
if (start) {
if (!isNil(start)) {
query.offset = convertStartQueryParams(start);
}
if (limit) {
if (!isNil(limit)) {
query.limit = convertLimitQueryParams(limit);
}
return { ...convertOldQuery(query), ...query };
};
convertPublicationStateParams(type, params, query);
const transformPublicationStateParams = uid => (params = {}) => {
const contentType = strapi.getModel(uid);
if (!contentType) {
return params;
}
const { publicationState, ...query } = params;
if (publicationState && contentTypesUtils.hasDraftAndPublish(contentType)) {
const { publicationState = 'live' } = params;
const liveClause = {
[PUBLISHED_AT_ATTRIBUTE]: {
$notNull: true,
},
};
if (publicationState === 'live') {
query.where = {
$and: [liveClause].concat(query.where || []),
};
// TODO: propagate nested publicationState filter somehow
}
}
return { ...convertOldQuery(query), ...query };
};
const pickSelectionParams = pick(['fields', 'populate']);
const transformParamsToQuery = (uid, params) => {
return pipe(
// _q, _where, filters, etc...
transformCommonParams,
// page, pageSize, start, limit
transformPaginationParams,
// publicationState
transformPublicationStateParams(uid)
)(params);
return query;
};
module.exports = {
transformCommonParams,
transformPublicationStateParams,
transformPaginationParams,
transformParamsToQuery,
pickSelectionParams,
};

View File

@ -1,6 +1,6 @@
'use strict';
const destroyOnSignal = () => {
const destroyOnSignal = strapi => {
let signalReceived = false;
// For unknown reasons, we receive signals 2 times.

View File

@ -90,7 +90,7 @@
"@strapi/plugin-email": "3.6.8",
"@strapi/plugin-upload": "3.6.8",
"@strapi/utils": "3.6.8",
"bcrypt": "5.0.1",
"bcryptjs": "2.4.3",
"boxen": "5.1.2",
"chalk": "4.1.2",
"chokidar": "3.5.2",

View File

@ -171,6 +171,7 @@ describe('Publication State', () => {
const res = await rq({ method: 'GET', url: `${baseUrl}${query}` });
expect(res.body.data).toHaveLength(lengthFor(modelName, { mode }));
expect(res.body.meta.pagination.total).toBe(lengthFor(modelName, { mode }));
});
});
@ -190,7 +191,7 @@ describe('Publication State', () => {
},
});
products = res.body.data.map(res => ({ id: res.id, ...res.attributes }));
products = res.body.data;
});
test('Payload integrity', () => {
@ -199,35 +200,29 @@ describe('Publication State', () => {
test('Root level', () => {
products.forEach(product => {
expect(product.publishedAt).toBeISODate();
expect(product.attributes.publishedAt).toBeISODate();
});
});
// const getApiRef = id => data.product.find(product => product.id === id);
test('First level (categories) to be published only', () => {
products.forEach(({ attributes }) => {
const categories = attributes.categories.data;
test.todo('First level (categories)');
categories.forEach(category => {
expect(category.attributes.publishedAt).toBeISODate();
});
});
});
// products.forEach(({ id, categories }) => {
// const length = getApiRef(id).categories.filter(c => c.publishedAt !== null).length;
// expect(categories).toHaveLength(length);
test('Second level through component (countries) to be published only', () => {
products.forEach(({ attributes }) => {
const countries = attributes.comp.countries.data;
// categories.forEach(category => {
// expect(category.publishedAt).toBeISODate();
// });
// });
// });
test.todo('Second level through component (countries)');
// products.forEach(({ id, comp: { countries } }) => {
// const length = getApiRef(id).comp.countries.filter(c => c.publishedAt !== null).length;
// expect(countries).toHaveLength(length);
// countries.forEach(country => {
// expect(country.publishedAt).toBeISODate();
// });
// });
// });
countries.forEach(country => {
expect(country.attributes.publishedAt).toBeISODate();
});
});
});
});
});
});

View File

@ -4,11 +4,12 @@
* Converts the standard Strapi REST query params to a more usable format for querying
* You can read more here: https://strapi.io/documentation/developer-docs/latest/developer-resources/content-api/content-api.html#filters
*/
const { has } = require('lodash/fp');
const _ = require('lodash');
const parseType = require('./parse-type');
const contentTypesUtils = require('./content-types');
const QUERY_OPERATORS = ['_where', '_or', '_and'];
const { PUBLISHED_AT_ATTRIBUTE } = contentTypesUtils.constants;
class InvalidOrderError extends Error {
constructor() {
@ -132,13 +133,15 @@ const convertPopulateQueryParams = (populate, depth = 0) => {
if (Array.isArray(populate)) {
// map convert
return populate.flatMap(value => {
if (typeof value !== 'string') {
throw new InvalidPopulateError();
}
return _.uniq(
populate.flatMap(value => {
if (typeof value !== 'string') {
throw new InvalidPopulateError();
}
return value.split(',').map(value => _.trim(value));
});
return value.split(',').map(value => _.trim(value));
})
);
}
if (_.isPlainObject(populate)) {
@ -146,6 +149,7 @@ const convertPopulateQueryParams = (populate, depth = 0) => {
for (const key in populate) {
transformedPopulate[key] = convertNestedPopulate(populate[key]);
}
return transformedPopulate;
}
@ -212,9 +216,31 @@ const convertFieldsQueryParams = (fields, depth = 0) => {
throw new Error('Invalid fields parameter. Expected a string or an array of strings');
};
// NOTE: We could validate the parameters are on existing / non private attributes
const convertFiltersQueryParams = filters => filters;
const convertPublicationStateParams = (type, params = {}, query = {}) => {
if (!type) {
return;
}
const { publicationState } = params;
if (!_.isNil(publicationState)) {
if (!contentTypesUtils.constants.DP_PUB_STATES.includes(publicationState)) {
throw new Error(
`Invalid publicationState. Expected one of 'preview','live' received: ${publicationState}.`
);
}
// NOTE: this is the query layer filters not the entity service filters
query.filters = ({ meta }) => {
if (publicationState === 'live' && has(PUBLISHED_AT_ATTRIBUTE, meta.attributes)) {
return { [PUBLISHED_AT_ATTRIBUTE]: { $notNull: true } };
}
};
}
};
module.exports = {
convertSortQueryParams,
convertStartQueryParams,
@ -222,5 +248,5 @@ module.exports = {
convertPopulateQueryParams,
convertFiltersQueryParams,
convertFieldsQueryParams,
QUERY_OPERATORS,
convertPublicationStateParams,
};

View File

@ -4,7 +4,6 @@
* Export shared utilities
*/
const { buildQuery, hasDeepFilters } = require('./build-query');
const { QUERY_OPERATORS } = require('./convert-query-params');
const parseMultipartData = require('./parse-multipart');
const sanitizeEntity = require('./sanitize-entity');
const parseType = require('./parse-type');
@ -38,7 +37,6 @@ module.exports = {
formatYupErrors,
policy,
templateConfiguration,
QUERY_OPERATORS,
buildQuery,
hasDeepFilters,
parseMultipartData,

View File

@ -19,7 +19,7 @@ const enhanceRelationLayout = (layout, locale) =>
if (get(current, ['targetModelPluginOptions', 'i18n', 'localized'], false)) {
queryInfos = {
...queryInfos,
defaultParams: { ...queryInfos.defaultParams, _locale: locale },
defaultParams: { ...queryInfos.defaultParams, locale },
paramsToKeep: ['plugins.i18n.locale'],
};
}
@ -82,7 +82,7 @@ const enhanceComponentLayoutForRelations = (layout, locale) =>
) {
const queryInfos = {
...field.queryInfos,
defaultParams: { ...field.queryInfos.defaultParams, _locale: locale },
defaultParams: { ...field.queryInfos.defaultParams, locale },
paramsToKeep: ['plugins.i18n.locale'],
};

View File

@ -277,7 +277,7 @@ describe('i18n | contentManagerHooks | mutateEditViewLayout', () => {
fieldSchema: { type: 'relation' },
targetModelPluginOptions: { i18n: { localized: true } },
queryInfos: {
defaultParams: { test: true, _locale: 'en' },
defaultParams: { test: true, locale: 'en' },
paramsToKeep: ['plugins.i18n.locale'],
},
},
@ -299,7 +299,7 @@ describe('i18n | contentManagerHooks | mutateEditViewLayout', () => {
fieldSchema: { type: 'relation' },
targetModelPluginOptions: { i18n: { localized: true } },
queryInfos: {
defaultParams: { test: true, _locale: 'en' },
defaultParams: { test: true, locale: 'en' },
paramsToKeep: ['plugins.i18n.locale'],
},
},
@ -518,7 +518,7 @@ describe('i18n | contentManagerHooks | mutateEditViewLayout', () => {
queryInfos: {
defaultParams: {
test: true,
_locale: 'en',
locale: 'en',
},
paramsToKeep: ['plugins.i18n.locale'],
},

View File

@ -141,7 +141,7 @@ describe('Entity service decorator', () => {
}
);
test('Replaces _locale param', async () => {
test('Replaces locale param', async () => {
const defaultService = {
wrapParams: jest.fn(opts => Promise.resolve(opts)),
};

View File

@ -19,7 +19,6 @@ const paramsContain = (key, params) => {
* @param {object} params - query params
* @param {object} ctx
*/
// TODO: remove _locale
const wrapParams = async (params = {}, ctx = {}) => {
const { action } = ctx;
@ -36,20 +35,6 @@ const wrapParams = async (params = {}, ctx = {}) => {
};
}
// TODO: remove when the _locale is renamed to locale
if (has('_locale', params)) {
if (params['_locale'] === 'all') {
return omit('_locale', params);
}
return {
...omit('_locale', params),
filters: {
$and: [{ locale: params['_locale'] }].concat(params.filters || []),
},
};
}
const entityDefinedById = paramsContain('id', params) && SINGLE_ENTRY_ACTIONS.includes(action);
const entitiesDefinedByIds = paramsContain('id.$in', params) && BULK_ACTIONS.includes(action);

View File

@ -5,8 +5,14 @@
* @param {{ strapi: import('@strapi/strapi').Strapi }}
*/
module.exports = ({ strapi }) => {
const sentry = strapi.plugin('sentry').service('sentry');
sentry.init();
const sentryService = strapi.plugin('sentry').service('sentry');
sentryService.init();
const sentry = sentryService.getInstance();
if (!sentry) {
// initialization failed
return;
}
strapi.server.use(async (ctx, next) => {
try {

View File

@ -2881,21 +2881,6 @@
npmlog "^4.1.2"
write-file-atomic "^2.3.0"
"@mapbox/node-pre-gyp@^1.0.0":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz#2a0b32fcb416fb3f2250fd24cb2a81421a4f5950"
integrity sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==
dependencies:
detect-libc "^1.0.3"
https-proxy-agent "^5.0.0"
make-dir "^3.1.0"
node-fetch "^2.6.1"
nopt "^5.0.0"
npmlog "^4.1.2"
rimraf "^3.0.2"
semver "^7.3.4"
tar "^6.1.0"
"@mdx-js/loader@^1.6.22":
version "1.6.22"
resolved "https://registry.yarnpkg.com/@mdx-js/loader/-/loader-1.6.22.tgz#d9e8fe7f8185ff13c9c8639c048b123e30d322c4"
@ -7221,15 +7206,7 @@ bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
dependencies:
tweetnacl "^0.14.3"
bcrypt@5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.0.1.tgz#f1a2c20f208e2ccdceea4433df0c8b2c54ecdf71"
integrity sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==
dependencies:
"@mapbox/node-pre-gyp" "^1.0.0"
node-addon-api "^3.1.0"
bcryptjs@^2.4.3:
bcryptjs@2.4.3, bcryptjs@^2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=
@ -17349,13 +17326,6 @@ nopt@^4.0.1:
abbrev "1"
osenv "^0.1.4"
nopt@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
dependencies:
abbrev "1"
normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"