mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 19:04:38 +00:00
Merge branch 'develop' into enhancement/config-password-rules-u
This commit is contained in:
commit
68b78b685a
File diff suppressed because one or more lines are too long
4
.github/actions/check-pr-status/package.json
vendored
4
.github/actions/check-pr-status/package.json
vendored
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "check-pr-status",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
@ -14,6 +14,6 @@
|
||||
"@actions/github": "6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "0.38.0"
|
||||
"@vercel/ncc": "0.38.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
<h3 align="center">Open-source headless CMS, self-hosted or Cloud you’re in control.</h3>
|
||||
<p align="center">The leading open-source headless CMS, 100% JavaScript/TypeScript, flexible and fully customizable.</p>
|
||||
<p align="center"><a href="https://cloud.strapi.io/signups?source=github1">Cloud</a> · <a href="https://strapi.io/demo?utm_campaign=Growth-Experiments&utm_source=strapi%2Fstrapi%20README.md">Try live demo</a> · <a href="https://strapi.io/five?utm_campaign=Product%20Marketing%20Strapi%205%20Launch%20Q1%20Q2%202024&utm_source=GitHub&utm_medium=strapi%2Fstrapi%20README.md">Strapi 5 (coming soon)</a></p>
|
||||
<p align="center"><a href="https://cloud.strapi.io/signups?source=github1">Cloud</a> · <a href="https://strapi.io/demo?utm_campaign=Growth-Experiments&utm_source=strapi%2Fstrapi%20README.md">Try live demo</a></p>
|
||||
<br />
|
||||
|
||||
<p align="center">
|
||||
|
||||
@ -27,9 +27,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@cmfcmf/docusaurus-search-local": "1.1.0",
|
||||
"@docusaurus/core": "3.1.1",
|
||||
"@docusaurus/preset-classic": "3.1.1",
|
||||
"@docusaurus/theme-mermaid": "3.1.1",
|
||||
"@docusaurus/core": "3.5.2",
|
||||
"@docusaurus/preset-classic": "3.5.2",
|
||||
"@docusaurus/theme-mermaid": "3.5.2",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"clsx": "^1.1.1",
|
||||
"prism-react-renderer": "^2.1.0",
|
||||
@ -37,7 +37,7 @@
|
||||
"react-dom": "18.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "3.1.1",
|
||||
"@docusaurus/module-type-aliases": "3.5.2",
|
||||
"docusaurus-plugin-typedoc": "0.22.0",
|
||||
"typedoc": "0.25.9",
|
||||
"typedoc-plugin-markdown": "3.17.1",
|
||||
|
||||
4073
docs/yarn.lock
4073
docs/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,6 @@
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-react": "4.2.1",
|
||||
"babel-plugin-react-compiler": "0.0.0-experimental-c23de8d-20240515",
|
||||
"vite": "5.1.7"
|
||||
"vite": "5.2.14"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"npmClient": "yarn"
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "6.7.3",
|
||||
"@typescript-eslint/parser": "6.7.3",
|
||||
"chalk": "4.1.2",
|
||||
"chokidar": "3.5.3",
|
||||
"chokidar": "3.6.0",
|
||||
"coffee": "5.5.1",
|
||||
"core-js": "3.36.0",
|
||||
"create-strapi-app": "workspace:*",
|
||||
@ -136,7 +136,7 @@
|
||||
"jest-environment-jsdom": "29.6.1",
|
||||
"jest-watch-typeahead": "2.2.2",
|
||||
"lerna": "8.1.2",
|
||||
"lint-staged": "13.3.0",
|
||||
"lint-staged": "15.2.10",
|
||||
"lodash": "4.17.21",
|
||||
"nx": "18.2.2",
|
||||
"plop": "2.7.6",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/admin-test-utils",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"private": true,
|
||||
"description": "Test utilities for the Strapi administration panel",
|
||||
"license": "MIT",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/cloud-cli",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Commands to interact with the Strapi Cloud",
|
||||
"keywords": [
|
||||
"strapi",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-strapi-app",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Generate a new Strapi application.",
|
||||
"keywords": [
|
||||
"create-strapi-app",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-strapi",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Generate a new Strapi application.",
|
||||
"keywords": [
|
||||
"create-strapi",
|
||||
|
||||
@ -460,7 +460,7 @@ const LinkCustom = styled(LinkButton)`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: none;
|
||||
|
||||
justify-content: left;
|
||||
svg {
|
||||
width: ${({ theme }) => theme.spaces[6]};
|
||||
height: ${({ theme }) => theme.spaces[6]};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/admin",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Strapi Admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -164,7 +164,7 @@
|
||||
"react-dom": "18.3.1",
|
||||
"react-router-dom": "6.22.3",
|
||||
"styled-components": "6.1.8",
|
||||
"vite": "5.1.7",
|
||||
"vite": "5.2.14",
|
||||
"vite-plugin-dts": "3.7.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@ -202,6 +202,12 @@ describe('useDocument', () => {
|
||||
"visible": false,
|
||||
"writable": false,
|
||||
},
|
||||
"dz": {
|
||||
"components": [
|
||||
"blog.test-como",
|
||||
],
|
||||
"type": "dynamiczone",
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
},
|
||||
|
||||
@ -71,6 +71,32 @@ describe('useDocumentLayout', () => {
|
||||
|
||||
expect(result.current.edit.layout).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"attribute": {
|
||||
"components": [
|
||||
"blog.test-como",
|
||||
],
|
||||
"type": "dynamiczone",
|
||||
},
|
||||
"disabled": false,
|
||||
"hint": "",
|
||||
"label": "dz",
|
||||
"mainField": {
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
},
|
||||
"name": "dz",
|
||||
"placeholder": "",
|
||||
"required": false,
|
||||
"size": 12,
|
||||
"type": "dynamiczone",
|
||||
"unique": false,
|
||||
"visible": true,
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{
|
||||
@ -90,6 +116,8 @@ describe('useDocumentLayout', () => {
|
||||
"visible": true,
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{
|
||||
"attribute": {
|
||||
|
||||
@ -250,9 +250,10 @@ const formatEditLayout = (
|
||||
currentPanelIndex += 2;
|
||||
} else {
|
||||
if (!panels[currentPanelIndex]) {
|
||||
panels.push([]);
|
||||
panels.push([row]);
|
||||
} else {
|
||||
panels[currentPanelIndex].push(row);
|
||||
}
|
||||
panels[currentPanelIndex].push(row);
|
||||
}
|
||||
|
||||
return panels;
|
||||
|
||||
@ -120,6 +120,7 @@ const EditViewPage = () => {
|
||||
|
||||
return transformDocument(schema, components)(form);
|
||||
}, [document, isCreatingDocument, isSingleType, schema, components]);
|
||||
|
||||
if (hasError) {
|
||||
return <Page.Error />;
|
||||
}
|
||||
|
||||
@ -19,9 +19,10 @@ import {
|
||||
ButtonProps,
|
||||
} from '@strapi/design-system';
|
||||
import { Cross, More, WarningCircle } from '@strapi/icons';
|
||||
import mapValues from 'lodash/fp/mapValues';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useMatch, useNavigate } from 'react-router-dom';
|
||||
import { styled, DefaultTheme } from 'styled-components';
|
||||
import { DefaultTheme } from 'styled-components';
|
||||
|
||||
import { PUBLISHED_AT_ATTRIBUTE_NAME } from '../../../constants/attributes';
|
||||
import { SINGLE_TYPES } from '../../../constants/collections';
|
||||
@ -35,6 +36,7 @@ import { getTranslation } from '../../../utils/translations';
|
||||
|
||||
import type { RelationsFormValue } from './FormInputs/Relations';
|
||||
import type { DocumentActionComponent } from '../../../content-manager';
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Types
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
@ -493,6 +495,22 @@ const DocumentActionModal = ({
|
||||
);
|
||||
};
|
||||
|
||||
const transformData = (data: Record<string, any>): any => {
|
||||
if (Array.isArray(data)) {
|
||||
return data.map(transformData);
|
||||
}
|
||||
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if ('apiData' in data) {
|
||||
return data.apiData;
|
||||
}
|
||||
|
||||
return mapValues(transformData)(data);
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* DocumentActionComponents
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
@ -643,7 +661,7 @@ const PublishAction: DocumentActionComponent = ({
|
||||
documentId,
|
||||
params,
|
||||
},
|
||||
formValues
|
||||
transformData(formValues)
|
||||
);
|
||||
|
||||
if ('data' in res && collectionType !== SINGLE_TYPES) {
|
||||
@ -797,7 +815,7 @@ const UpdateAction: DocumentActionComponent = ({
|
||||
documentId: cloneMatch.params.origin!,
|
||||
params,
|
||||
},
|
||||
document
|
||||
transformData(document)
|
||||
);
|
||||
|
||||
if ('data' in res) {
|
||||
@ -823,7 +841,7 @@ const UpdateAction: DocumentActionComponent = ({
|
||||
documentId,
|
||||
params,
|
||||
},
|
||||
document
|
||||
transformData(document)
|
||||
);
|
||||
|
||||
if (
|
||||
@ -841,7 +859,7 @@ const UpdateAction: DocumentActionComponent = ({
|
||||
model,
|
||||
params,
|
||||
},
|
||||
document
|
||||
transformData(document)
|
||||
);
|
||||
|
||||
if ('data' in res && collectionType !== SINGLE_TYPES) {
|
||||
|
||||
@ -84,7 +84,13 @@ function useHandleDisconnect(fieldName: string, consumerName: string) {
|
||||
}
|
||||
}
|
||||
|
||||
addFieldRow(`${fieldName}.disconnect`, { id: relation.id });
|
||||
addFieldRow(`${fieldName}.disconnect`, {
|
||||
id: relation.id,
|
||||
apiData: {
|
||||
documentId: relation.documentId,
|
||||
locale: relation.locale,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return handleDisconnect;
|
||||
@ -145,14 +151,23 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
const isMorph = props.attribute.relation.toLowerCase().includes('morph');
|
||||
const isDisabled = isMorph || disabled;
|
||||
|
||||
const { id: componentId, uid } = useComponent('RelationsField', ({ uid, id }) => ({ id, uid }));
|
||||
const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id }) => ({
|
||||
componentId: id,
|
||||
componentUID: uid,
|
||||
}));
|
||||
|
||||
const isSubmitting = useForm('RelationsList', (state) => state.isSubmitting);
|
||||
|
||||
React.useEffect(() => {
|
||||
setCurrentPage(1);
|
||||
}, [isSubmitting]);
|
||||
|
||||
/**
|
||||
* We'll always have a documentId in a created entry, so we look for a componentId first.
|
||||
* Same with `uid` and `documentModel`.
|
||||
*/
|
||||
const id = componentId ? componentId.toString() : documentId;
|
||||
const model = uid ?? documentModel;
|
||||
const model = componentUID ?? documentModel;
|
||||
|
||||
/**
|
||||
* The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
|
||||
@ -199,6 +214,7 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
|
||||
const realServerRelationsCount =
|
||||
'pagination' in data && data.pagination ? data.pagination.total : 0;
|
||||
|
||||
/**
|
||||
* Items that are already connected, but reordered would be in
|
||||
* this list, so to get an accurate figure, we remove them.
|
||||
@ -259,6 +275,10 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
|
||||
const item = {
|
||||
id: relation.id,
|
||||
apiData: {
|
||||
documentId: relation.documentId,
|
||||
locale: relation.locale,
|
||||
},
|
||||
status: relation.status,
|
||||
/**
|
||||
* If there's a last item, that's the first key we use to generate out next one.
|
||||
@ -268,7 +288,7 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
[props.mainField?.name ?? 'documentId']: relation[props.mainField?.name ?? 'documentId'],
|
||||
label: getRelationLabel(relation, props.mainField),
|
||||
// @ts-expect-error – targetModel does exist on the attribute, but it's not typed.
|
||||
href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}`,
|
||||
href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`,
|
||||
};
|
||||
|
||||
if (ONE_WAY_RELATIONS.includes(props.attribute.relation)) {
|
||||
@ -294,7 +314,8 @@ const RelationsField = React.forwardRef<HTMLDivElement, RelationsFieldProps>(
|
||||
<StyledFlex direction="column" alignItems="start" gap={2} width="100%">
|
||||
<RelationsInput
|
||||
disabled={isDisabled}
|
||||
id={id}
|
||||
// NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
|
||||
id={componentUID ? (componentId ? `${componentId}` : '') : documentId}
|
||||
label={`${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`}
|
||||
model={model}
|
||||
onChange={handleConnect}
|
||||
@ -389,7 +410,7 @@ const addLabelAndHref =
|
||||
// Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
|
||||
[mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
|
||||
label: getRelationLabel(relation, mainField),
|
||||
href: `${href}/${relation.documentId}`,
|
||||
href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`,
|
||||
};
|
||||
});
|
||||
|
||||
@ -454,6 +475,7 @@ const RelationsInput = ({
|
||||
* individual components. Therefore we split the string and take the last item.
|
||||
*/
|
||||
const [targetField] = name.split('.').slice(-1);
|
||||
|
||||
searchForTrigger({
|
||||
model,
|
||||
targetField,
|
||||
@ -701,9 +723,7 @@ const RelationsList = ({
|
||||
*/
|
||||
const connectedRelations = newData
|
||||
.reduce<Relation[]>((acc, relation, currentIndex, array) => {
|
||||
const relationOnServer = serverData.find(
|
||||
(oldRelation) => oldRelation.documentId === relation.documentId
|
||||
);
|
||||
const relationOnServer = serverData.find((oldRelation) => oldRelation.id === relation.id);
|
||||
|
||||
const relationInFront = array[currentIndex + 1];
|
||||
|
||||
@ -712,11 +732,23 @@ const RelationsList = ({
|
||||
? {
|
||||
before: relationInFront.documentId,
|
||||
locale: relationInFront.locale,
|
||||
status: relationInFront.status,
|
||||
status:
|
||||
'publishedAt' in relationInFront && relationInFront.publishedAt
|
||||
? 'published'
|
||||
: 'draft',
|
||||
}
|
||||
: { end: true };
|
||||
|
||||
const relationWithPosition: Relation = { ...relation, position };
|
||||
const relationWithPosition: Relation = {
|
||||
...relation,
|
||||
...{
|
||||
apiData: {
|
||||
documentId: relation.documentId,
|
||||
locale: relation.locale,
|
||||
position,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return [...acc, relationWithPosition];
|
||||
}
|
||||
@ -899,7 +931,7 @@ const ListItem = ({ data, index, style }: ListItemProps) => {
|
||||
} = data;
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const { href, documentId, label, status } = relations[index];
|
||||
const { href, id, label, status } = relations[index];
|
||||
|
||||
const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] =
|
||||
useDragAndDrop<number, Omit<RelationDragPreviewProps, 'width'>, HTMLDivElement>(
|
||||
@ -910,7 +942,7 @@ const ListItem = ({ data, index, style }: ListItemProps) => {
|
||||
item: {
|
||||
displayedValue: label,
|
||||
status,
|
||||
id: documentId,
|
||||
id: id,
|
||||
index,
|
||||
},
|
||||
onMoveItem: handleMoveItem,
|
||||
|
||||
@ -67,11 +67,8 @@ const relationsApi = contentManagerApi.injectEndpoints({
|
||||
* Relations will always have unique IDs, so we can therefore assume
|
||||
* that we only need to push the new items to the cache.
|
||||
*/
|
||||
const existingIds = currentCache.results.map((item) => item.documentId);
|
||||
const uniqueNewItems = newItems.results.filter(
|
||||
(item) => !existingIds.includes(item.documentId)
|
||||
);
|
||||
currentCache.results.push(...prepareTempKeys(uniqueNewItems, currentCache.results));
|
||||
|
||||
currentCache.results.push(...prepareTempKeys(newItems.results, currentCache.results));
|
||||
currentCache.pagination = newItems.pagination;
|
||||
} else if (newItems.pagination.page === 1) {
|
||||
/**
|
||||
|
||||
@ -398,6 +398,10 @@ const CM_CONTENT_TYPE_MOCK_DATA = [
|
||||
allowedTypes: ['images'],
|
||||
pluginOptions: {},
|
||||
},
|
||||
dz: {
|
||||
type: 'dynamiczone',
|
||||
components: ['blog.test-como'],
|
||||
},
|
||||
city: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
@ -718,6 +722,22 @@ const CM_COLLECTION_TYPE_LAYOUT_MOCK_DATA = {
|
||||
mainField: 'name',
|
||||
},
|
||||
},
|
||||
dz: {
|
||||
edit: {
|
||||
label: 'dz',
|
||||
description: '',
|
||||
placeholder: '',
|
||||
visible: true,
|
||||
editable: true,
|
||||
mainField: 'name',
|
||||
},
|
||||
list: {
|
||||
label: 'dz',
|
||||
searchable: false,
|
||||
sortable: false,
|
||||
mainField: 'name',
|
||||
},
|
||||
},
|
||||
cover: {
|
||||
edit: {
|
||||
label: 'cover',
|
||||
@ -894,6 +914,7 @@ const CM_COLLECTION_TYPE_LAYOUT_MOCK_DATA = {
|
||||
layouts: {
|
||||
list: ['id', 'categories', 'cover', 'postal_code'],
|
||||
edit: [
|
||||
[{ name: 'dz', size: 12 }],
|
||||
[
|
||||
{
|
||||
name: 'slug',
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/content-manager",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "A powerful UI to easily manage your data.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -49,17 +49,39 @@ const sanitizeMainField = (model: any, mainField: any, userAbility: any) => {
|
||||
return mainField;
|
||||
};
|
||||
|
||||
const addStatusToRelations = async (uid: UID.ContentType, relations: RelationEntity[]) => {
|
||||
if (!contentTypes.hasDraftAndPublish(strapi.contentTypes[uid])) {
|
||||
/**
|
||||
*
|
||||
* All relations sent to this function should have the same status or no status
|
||||
*/
|
||||
const addStatusToRelations = async (targetUid: UID.Schema, relations: RelationEntity[]) => {
|
||||
if (!contentTypes.hasDraftAndPublish(strapi.getModel(targetUid))) {
|
||||
return relations;
|
||||
}
|
||||
|
||||
const documentMetadata = getService('document-metadata');
|
||||
const documentsAvailableStatus = await documentMetadata.getManyAvailableStatus(uid, relations);
|
||||
|
||||
if (!relations.length) {
|
||||
return relations;
|
||||
}
|
||||
|
||||
const firstRelation = relations[0];
|
||||
|
||||
const filters: any = {
|
||||
documentId: { $in: relations.map((r) => r.documentId) },
|
||||
// NOTE: find the "opposite" status
|
||||
publishedAt: firstRelation.publishedAt !== null ? { $null: true } : { $notNull: true },
|
||||
};
|
||||
|
||||
const availableStatus = await strapi.query(targetUid).findMany({
|
||||
select: ['id', 'documentId', 'locale', 'updatedAt', 'createdAt', 'publishedAt'],
|
||||
filters,
|
||||
});
|
||||
|
||||
return relations.map((relation: RelationEntity) => {
|
||||
const availableStatuses = documentsAvailableStatus.filter(
|
||||
(availableDocument: RelationEntity) => availableDocument.documentId === relation.documentId
|
||||
const availableStatuses = availableStatus.filter(
|
||||
(availableDocument: RelationEntity) =>
|
||||
availableDocument.documentId === relation.documentId &&
|
||||
(relation.locale ? availableDocument.locale === relation.locale : true)
|
||||
);
|
||||
|
||||
return {
|
||||
@ -396,14 +418,14 @@ export default {
|
||||
attribute,
|
||||
targetField,
|
||||
fieldsToSelect,
|
||||
source: {
|
||||
schema: { uid: sourceUid },
|
||||
},
|
||||
target: {
|
||||
schema: { uid: targetUid },
|
||||
},
|
||||
status,
|
||||
source: { schema: sourceSchema },
|
||||
target: { schema: targetSchema },
|
||||
} = await this.extractAndValidateRequestInfo(ctx, id);
|
||||
|
||||
const { uid: sourceUid } = sourceSchema;
|
||||
const { uid: targetUid } = targetSchema;
|
||||
|
||||
const permissionQuery = await getService('permission-checker')
|
||||
.create({ userAbility, model: targetUid })
|
||||
.sanitizedQuery.read({ fields: fieldsToSelect });
|
||||
@ -424,6 +446,23 @@ export default {
|
||||
// Ensure response is an array
|
||||
.then((res) => ({ results: res ? [res] : [] }));
|
||||
|
||||
const filters: {
|
||||
publishedAt?: Record<string, any>;
|
||||
} = {};
|
||||
|
||||
if (sourceSchema?.options?.draftAndPublish) {
|
||||
if (targetSchema?.options?.draftAndPublish) {
|
||||
if (status === 'published') {
|
||||
filters.publishedAt = { $notNull: true };
|
||||
} else {
|
||||
filters.publishedAt = { $null: true };
|
||||
}
|
||||
}
|
||||
} else if (targetSchema?.options?.draftAndPublish) {
|
||||
// NOTE: we must return the drafts as some targets might not have a published version yet
|
||||
filters.publishedAt = { $null: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* If user does not have access to specific relations (custom conditions),
|
||||
* only the ids of the relations are returned.
|
||||
@ -434,10 +473,11 @@ export default {
|
||||
* The response contains the union of the two queries.
|
||||
*/
|
||||
const res = await loadRelations({ id: entryId }, targetField, {
|
||||
select: ['id', 'documentId', 'locale', 'publishedAt'],
|
||||
select: ['id', 'documentId', 'locale', 'publishedAt', 'updatedAt'],
|
||||
ordering: 'desc',
|
||||
page: ctx.request.query.page,
|
||||
pageSize: ctx.request.query.pageSize,
|
||||
filters,
|
||||
});
|
||||
|
||||
/**
|
||||
@ -458,6 +498,7 @@ export default {
|
||||
ordering: 'desc',
|
||||
});
|
||||
|
||||
// NOTE: the order is very import to make sure sanitized relations are kept in priority
|
||||
const relationsUnion = uniqBy('id', concat(sanitizedRes.results, res.results));
|
||||
|
||||
ctx.body = {
|
||||
|
||||
@ -7,11 +7,11 @@ import type { DocumentMetadata } from '../../../shared/contracts/collection-type
|
||||
import { getValidatableFieldsPopulate } from './utils/populate';
|
||||
|
||||
export interface DocumentVersion {
|
||||
id: number;
|
||||
id: string | number;
|
||||
documentId: Modules.Documents.ID;
|
||||
locale: string;
|
||||
updatedAt: string | null | Date;
|
||||
publishedAt: string | null | Date;
|
||||
locale?: string;
|
||||
updatedAt?: string | null | Date;
|
||||
publishedAt?: string | null | Date;
|
||||
}
|
||||
|
||||
const AVAILABLE_STATUS_FIELDS = [
|
||||
@ -86,7 +86,9 @@ export default ({ strapi }: { strapi: Core.Strapi }) => ({
|
||||
const versionsByLocale = groupBy('locale', allVersions);
|
||||
|
||||
// Delete the current locale
|
||||
delete versionsByLocale[version.locale];
|
||||
if (version.locale) {
|
||||
delete versionsByLocale[version.locale];
|
||||
}
|
||||
|
||||
// For each locale, get the ones with the same status
|
||||
// There will not be a draft and a version counterpart if the content
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import '@strapi/types';
|
||||
|
||||
import { DocumentManagerService } from 'src/services/document-manager';
|
||||
import DocumentMetadata from 'src/services/document-metadata';
|
||||
|
||||
type Services = {
|
||||
'document-manager': DocumentManagerService;
|
||||
'document-metadata': typeof DocumentMetadata;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/content-releases",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Strapi plugin for organizing and releasing content",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -85,11 +85,11 @@
|
||||
"react-query": "3.39.3",
|
||||
"react-router-dom": "6.22.3",
|
||||
"styled-components": "6.1.8",
|
||||
"typescript": "5.2.2"
|
||||
"typescript": "5.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@strapi/admin": "^5.0.0 || ^5.0.0-beta || ^5.0.0-alpha || ^5.0.0-rc",
|
||||
"@strapi/content-manager": "^5.0.0 || ^5.0.0-beta || ^5.0.0-alpha || ^5.0.0-rc",
|
||||
"@strapi/admin": "^5.0.0",
|
||||
"@strapi/content-manager": "^5.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0",
|
||||
"react-router-dom": "^6.0.0",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/content-type-builder",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Create and manage content types",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/core",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Core of Strapi",
|
||||
"homepage": "https://strapi.io",
|
||||
"bugs": {
|
||||
@ -102,7 +102,7 @@
|
||||
"resolve.exports": "2.0.2",
|
||||
"semver": "7.5.4",
|
||||
"statuses": "2.0.1",
|
||||
"typescript": "5.2.2",
|
||||
"typescript": "5.3.2",
|
||||
"undici": "6.19.2",
|
||||
"yup": "0.32.9"
|
||||
},
|
||||
|
||||
@ -291,7 +291,10 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
||||
]);
|
||||
|
||||
// Load any unidirectional relation targetting the old published entries
|
||||
const relationsToSync = await unidirectionalRelations.load(uid, oldPublishedVersions);
|
||||
const relationsToSync = await unidirectionalRelations.load(uid, {
|
||||
newVersions: draftsToPublish,
|
||||
oldVersions: oldPublishedVersions,
|
||||
});
|
||||
|
||||
// Delete old published versions
|
||||
await async.map(oldPublishedVersions, (entry: any) => entries.delete(entry.id));
|
||||
@ -302,7 +305,11 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
||||
);
|
||||
|
||||
// Sync unidirectional relations with the new published entries
|
||||
await unidirectionalRelations.sync(oldPublishedVersions, publishedEntries, relationsToSync);
|
||||
await unidirectionalRelations.sync(
|
||||
[...oldPublishedVersions, ...draftsToPublish],
|
||||
publishedEntries,
|
||||
relationsToSync
|
||||
);
|
||||
|
||||
publishedEntries.forEach(emitEvent('entry.publish'));
|
||||
|
||||
@ -358,7 +365,10 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
||||
]);
|
||||
|
||||
// Load any unidirectional relation targeting the old drafts
|
||||
const relationsToSync = await unidirectionalRelations.load(uid, oldDrafts);
|
||||
const relationsToSync = await unidirectionalRelations.load(uid, {
|
||||
newVersions: versionsToDraft,
|
||||
oldVersions: oldDrafts,
|
||||
});
|
||||
|
||||
// Delete old drafts
|
||||
await async.map(oldDrafts, (entry: any) => entries.delete(entry.id));
|
||||
@ -369,7 +379,11 @@ export const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {
|
||||
);
|
||||
|
||||
// Sync unidirectional relations with the new draft entries
|
||||
await unidirectionalRelations.sync(oldDrafts, draftEntries, relationsToSync);
|
||||
await unidirectionalRelations.sync(
|
||||
[...oldDrafts, ...versionsToDraft],
|
||||
draftEntries,
|
||||
relationsToSync
|
||||
);
|
||||
|
||||
draftEntries.forEach(emitEvent('entry.draft-discard'));
|
||||
return { documentId, entries: draftEntries };
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
/* eslint-disable no-continue */
|
||||
import { keyBy } from 'lodash/fp';
|
||||
import { keyBy, omit } from 'lodash/fp';
|
||||
|
||||
import { UID, Schema } from '@strapi/types';
|
||||
|
||||
interface LoadContext {
|
||||
oldVersions: { id: string; locale: string }[];
|
||||
newVersions: { id: string; locale: string }[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads lingering relations that need to be updated when overriding a published or draft entry.
|
||||
* This is necessary because the relations are uni-directional and the target entry is not aware of the source entry.
|
||||
* This is not the case for bi-directional relations, where the target entry is also linked to the source entry.
|
||||
*
|
||||
* @param uid The content type uid
|
||||
* @param oldEntries The old entries that are being overridden
|
||||
* @returns An array of relations that need to be updated with the join table reference.
|
||||
*/
|
||||
const load = async (uid: UID.ContentType, oldEntries: { id: string; locale: string }[]) => {
|
||||
const load = async (uid: UID.ContentType, { oldVersions, newVersions }: LoadContext) => {
|
||||
const updates = [] as any;
|
||||
|
||||
// Iterate all components and content types to find relations that need to be updated
|
||||
@ -27,29 +28,80 @@ const load = async (uid: UID.ContentType, oldEntries: { id: string; locale: stri
|
||||
/**
|
||||
* Only consider unidirectional relations
|
||||
*/
|
||||
if (attribute.type !== 'relation') continue;
|
||||
if (attribute.target !== uid) continue;
|
||||
if (attribute.inversedBy || attribute.mappedBy) continue;
|
||||
const joinTable = attribute.joinTable;
|
||||
// TODO: joinColumn relations
|
||||
if (!joinTable) continue;
|
||||
if (
|
||||
attribute.type !== 'relation' ||
|
||||
attribute.target !== uid ||
|
||||
attribute.inversedBy ||
|
||||
attribute.mappedBy
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { name } = joinTable.inverseJoinColumn;
|
||||
// TODO: joinColumn relations
|
||||
const joinTable = attribute.joinTable;
|
||||
if (!joinTable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { name: sourceColumnName } = joinTable.joinColumn;
|
||||
const { name: targetColumnName } = joinTable.inverseJoinColumn;
|
||||
|
||||
/**
|
||||
* Load all relations that need to be updated
|
||||
*/
|
||||
const oldEntriesIds = oldEntries.map((entry) => entry.id);
|
||||
const relations = await strapi.db
|
||||
// NOTE: when the model has draft and publish, we can assume relation are only draft to draft & published to published
|
||||
const ids = oldVersions.map((entry) => entry.id);
|
||||
|
||||
const oldVersionsRelations = await strapi.db
|
||||
.getConnection()
|
||||
.select('*')
|
||||
.from(joinTable.name)
|
||||
.whereIn(name, oldEntriesIds)
|
||||
.whereIn(targetColumnName, ids)
|
||||
.transacting(trx);
|
||||
|
||||
if (relations.length === 0) continue;
|
||||
if (oldVersionsRelations.length > 0) {
|
||||
updates.push({ joinTable, relations: oldVersionsRelations });
|
||||
}
|
||||
|
||||
updates.push({ joinTable, relations });
|
||||
/**
|
||||
* if publishing
|
||||
* if published version exists
|
||||
* updated published versions links
|
||||
* else
|
||||
* create link to newly published version
|
||||
*
|
||||
* if discarding
|
||||
* if published version link exists & not draft version link
|
||||
* create link to new draft version
|
||||
*/
|
||||
|
||||
if (!model.options?.draftAndPublish) {
|
||||
const ids = newVersions.map((entry) => entry.id);
|
||||
|
||||
const newVersionsRelations = await strapi.db
|
||||
.getConnection()
|
||||
.select('*')
|
||||
.from(joinTable.name)
|
||||
.whereIn(targetColumnName, ids)
|
||||
.transacting(trx);
|
||||
|
||||
if (newVersionsRelations.length > 0) {
|
||||
// when publishing a draft that doesn't have a published version yet,
|
||||
// copy the links to the draft over to the published version
|
||||
// when discarding a published version, if no drafts exists
|
||||
const discardToAdd = newVersionsRelations
|
||||
.filter((relation) => {
|
||||
const matchingOldVerion = oldVersionsRelations.find((oldRelation) => {
|
||||
return oldRelation[sourceColumnName] === relation[sourceColumnName];
|
||||
});
|
||||
|
||||
return !matchingOldVerion;
|
||||
})
|
||||
.map(omit('id'));
|
||||
|
||||
updates.push({ joinTable, relations: discardToAdd });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -89,8 +141,9 @@ const sync = async (
|
||||
// Iterate old relations that are deleted and insert the new ones
|
||||
for (const { joinTable, relations } of oldRelations) {
|
||||
// Update old ids with the new ones
|
||||
const column = joinTable.inverseJoinColumn.name;
|
||||
|
||||
const newRelations = relations.map((relation) => {
|
||||
const column = joinTable.inverseJoinColumn.name;
|
||||
const newId = oldEntriesMap[relation[column]];
|
||||
return { ...relation, [column]: newId };
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/data-transfer",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Data transfer capabilities for Strapi",
|
||||
"keywords": [
|
||||
"strapi",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/database",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Strapi's database layer",
|
||||
"homepage": "https://strapi.io",
|
||||
"bugs": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/email",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Easily configure your Strapi application to send emails.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/permissions",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Strapi's permission layer.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/review-workflows",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Review workflows for your content",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/strapi",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MySQL, MariaDB, PostgreSQL, SQLite",
|
||||
"keywords": [
|
||||
"strapi",
|
||||
@ -134,7 +134,7 @@
|
||||
"browserslist": "^4.23.0",
|
||||
"browserslist-to-esbuild": "1.2.0",
|
||||
"chalk": "4.1.2",
|
||||
"chokidar": "3.5.3",
|
||||
"chokidar": "3.6.0",
|
||||
"ci-info": "3.8.0",
|
||||
"cli-progress": "3.12.0",
|
||||
"cli-table3": "0.6.5",
|
||||
@ -159,14 +159,14 @@
|
||||
"ora": "5.4.1",
|
||||
"outdent": "0.8.0",
|
||||
"pkg-up": "3.1.0",
|
||||
"prettier": "3.2.5",
|
||||
"prettier": "3.3.3",
|
||||
"react-refresh": "0.14.0",
|
||||
"read-pkg-up": "7.0.1",
|
||||
"resolve-from": "5.0.0",
|
||||
"semver": "7.5.4",
|
||||
"style-loader": "3.3.4",
|
||||
"typescript": "5.3.2",
|
||||
"vite": "5.1.7",
|
||||
"vite": "5.2.14",
|
||||
"webpack": "^5.90.3",
|
||||
"webpack-bundle-analyzer": "^4.10.1",
|
||||
"webpack-dev-middleware": "6.1.2",
|
||||
|
||||
@ -23,7 +23,6 @@ const watch = async (ctx: BuildContext): Promise<WebpackWatcher> => {
|
||||
|
||||
const devMiddleware = webpackDevMiddleware(compiler);
|
||||
|
||||
// @ts-expect-error incompatible types between hotMiddleware and webpack
|
||||
const hotMiddleware = webpackHotMiddleware(compiler, {
|
||||
log: false,
|
||||
path: '/__webpack_hmr',
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/types",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Shared typescript types for Strapi internal use",
|
||||
"keywords": [
|
||||
"strapi"
|
||||
|
||||
@ -12,6 +12,9 @@ import { BulkMoveButton } from './BulkMoveButton';
|
||||
|
||||
export const BulkActions = ({ selected, onSuccess, currentFolder }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const numberAssets = selected.reduce(function (_this, val) {
|
||||
return val?.type === 'folder' ? _this + val.files.count : _this + 1;
|
||||
}, 0);
|
||||
|
||||
return (
|
||||
<Flex gap={2} paddingBottom={5}>
|
||||
@ -24,7 +27,7 @@ export const BulkActions = ({ selected, onSuccess, currentFolder }) => {
|
||||
},
|
||||
{
|
||||
numberFolders: selected.filter(({ type }) => type === 'folder').length,
|
||||
numberAssets: selected.filter(({ type }) => type === 'asset').length,
|
||||
numberAssets,
|
||||
}
|
||||
)}
|
||||
</Typography>
|
||||
|
||||
@ -58,7 +58,11 @@ describe('BulkActions', () => {
|
||||
onSuccess: jest.fn(),
|
||||
selected: [
|
||||
...[...Array(ASSET_COUNT).keys()].map((index) => ({ id: index, type: 'asset' })),
|
||||
...[...Array(FOLDER_COUNT).keys()].map((index) => ({ id: index, type: 'folder' })),
|
||||
...[...Array(FOLDER_COUNT).keys()].map((index) => ({
|
||||
id: index,
|
||||
type: 'folder',
|
||||
files: { count: 0 },
|
||||
})),
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/upload",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Makes it easy to upload images and files to your Strapi Application.",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"author": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/utils",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Shared utilities for the Strapi packages",
|
||||
"keywords": [
|
||||
"strapi",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/generators",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Interactive API generator.",
|
||||
"keywords": [
|
||||
"strapi",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/plugin-cloud",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Instructions to deploy your local project to Strapi Cloud",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
@ -49,7 +49,7 @@
|
||||
"react-router-dom": "6.22.3",
|
||||
"styled-components": "6.1.8",
|
||||
"tsconfig": "workspace:*",
|
||||
"typescript": "5.2.2"
|
||||
"typescript": "5.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@strapi/strapi": "^5.0.0 || ^5.0.0-beta || ^5.0.0-alpha || ^5.0.0-rc",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/plugin-color-picker",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Strapi maintained Custom Fields",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/plugin-documentation",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Create an OpenAPI Document and visualize your API with SWAGGER UI.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -66,7 +66,7 @@
|
||||
"immer": "9.0.21",
|
||||
"koa-static": "^5.0.0",
|
||||
"lodash": "4.17.21",
|
||||
"path-to-regexp": "6.2.1",
|
||||
"path-to-regexp": "6.3.0",
|
||||
"react-intl": "6.6.2",
|
||||
"swagger-ui-dist": "4.19.0",
|
||||
"yaml": "1.10.2",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/plugin-graphql",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Adds GraphQL endpoint with default API methods.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -48,7 +48,7 @@
|
||||
"watch": "strapi-plugin watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/server": "4.10.0",
|
||||
"@apollo/server": "4.11.0",
|
||||
"@as-integrations/koa": "1.1.1",
|
||||
"@graphql-tools/schema": "10.0.3",
|
||||
"@graphql-tools/utils": "^10.1.3",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/i18n",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Create read and update content in different languages, both from the Admin Panel and from the API",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/plugin-sentry",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Send Strapi error events to Sentry",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/plugin-users-permissions",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Protect your API with a full-authentication process based on JWT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/provider-email-amazon-ses",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Amazon SES provider for strapi email",
|
||||
"keywords": [
|
||||
"email",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/provider-email-mailgun",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Mailgun provider for strapi email plugin",
|
||||
"keywords": [
|
||||
"email",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/provider-email-nodemailer",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Nodemailer provider for Strapi 3",
|
||||
"keywords": [
|
||||
"strapi",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/provider-email-sendgrid",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Sendgrid provider for strapi email",
|
||||
"keywords": [
|
||||
"email",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/provider-email-sendmail",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Sendmail provider for strapi email",
|
||||
"keywords": [
|
||||
"email",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/provider-upload-aws-s3",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "AWS S3 provider for strapi upload",
|
||||
"keywords": [
|
||||
"upload",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/provider-upload-cloudinary",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Cloudinary provider for strapi upload",
|
||||
"keywords": [
|
||||
"upload",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/provider-upload-local",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Local provider for strapi upload",
|
||||
"keywords": [
|
||||
"upload",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "api-tests",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"dotenv": "16.4.5",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eslint-config-custom",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"private": true,
|
||||
"main": "index.js"
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/logger",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Strapi's logger",
|
||||
"homepage": "https://strapi.io",
|
||||
"bugs": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tsconfig",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@tsconfig/node18": "18.2.2"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/typescript-utils",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "Typescript support for Strapi",
|
||||
"keywords": [
|
||||
"strapi",
|
||||
@ -39,7 +39,7 @@
|
||||
"cli-table3": "0.6.5",
|
||||
"fs-extra": "11.2.0",
|
||||
"lodash": "4.17.21",
|
||||
"prettier": "3.2.5",
|
||||
"prettier": "3.3.3",
|
||||
"typescript": "5.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strapi/upgrade",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"description": "CLI to upgrade Strapi applications effortless",
|
||||
"keywords": [
|
||||
"strapi",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "scripts-front",
|
||||
"version": "5.0.1",
|
||||
"version": "5.0.2-beta.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test:front": "jest --config jest.config.front.js"
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
"@strapi/plugin-graphql": "^5.0.0",
|
||||
"@strapi/plugin-users-permissions": "^5.0.0",
|
||||
"@strapi/strapi": "^5.0.0",
|
||||
"lodash.set": "^4.3.2",
|
||||
"lodash": "^4.17.19",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-router-dom": "^6.0.0",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import fs from 'fs';
|
||||
import set from 'lodash.set';
|
||||
import { set } from 'lodash';
|
||||
|
||||
import en from '../data/en.json';
|
||||
import fr from '../data/fr.json';
|
||||
|
||||
@ -5537,9 +5537,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"body-parser@npm:1.20.2":
|
||||
version: 1.20.2
|
||||
resolution: "body-parser@npm:1.20.2"
|
||||
"body-parser@npm:1.20.3":
|
||||
version: 1.20.3
|
||||
resolution: "body-parser@npm:1.20.3"
|
||||
dependencies:
|
||||
bytes: "npm:3.1.2"
|
||||
content-type: "npm:~1.0.5"
|
||||
@ -5549,11 +5549,11 @@ __metadata:
|
||||
http-errors: "npm:2.0.0"
|
||||
iconv-lite: "npm:0.4.24"
|
||||
on-finished: "npm:2.4.1"
|
||||
qs: "npm:6.11.0"
|
||||
qs: "npm:6.13.0"
|
||||
raw-body: "npm:2.5.2"
|
||||
type-is: "npm:~1.6.18"
|
||||
unpipe: "npm:1.0.0"
|
||||
checksum: 10c0/06f1438fff388a2e2354c96aa3ea8147b79bfcb1262dfcc2aae68ec13723d01d5781680657b74e9f83c808266d5baf52804032fbde2b7382b89bd8cdb273ace9
|
||||
checksum: 10c0/0a9a93b7518f222885498dcecaad528cf010dd109b071bf471c93def4bfe30958b83e03496eb9c1ad4896db543d999bb62be1a3087294162a88cfa1b42c16310
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -7179,9 +7179,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"dset@npm:^3.1.2":
|
||||
version: 3.1.3
|
||||
resolution: "dset@npm:3.1.3"
|
||||
checksum: 10c0/b1ff68f1f42af373baa85b00b04d89094cd0d7f74f94bd11364cba575f2762ed52a0a0503bbfcc92eccd07c6d55426813c8a7a6cfa020338eaea1f4edfd332c2
|
||||
version: 3.1.4
|
||||
resolution: "dset@npm:3.1.4"
|
||||
checksum: 10c0/b67bbd28dd8a539e90c15ffb61100eb64ef995c5270a124d4f99bbb53f4d82f55a051b731ba81f3215dd9dce2b4c8d69927dc20b3be1c5fc88bab159467aa438
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -7279,6 +7279,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"encodeurl@npm:~2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "encodeurl@npm:2.0.0"
|
||||
checksum: 10c0/5d317306acb13e6590e28e27924c754163946a2480de11865c991a3a7eed4315cd3fba378b543ca145829569eefe9b899f3d84bb09870f675ae60bc924b01ceb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"encoding@npm:^0.1.13":
|
||||
version: 0.1.13
|
||||
resolution: "encoding@npm:0.1.13"
|
||||
@ -7896,41 +7903,41 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"express@npm:^4.17.1":
|
||||
version: 4.19.2
|
||||
resolution: "express@npm:4.19.2"
|
||||
version: 4.21.0
|
||||
resolution: "express@npm:4.21.0"
|
||||
dependencies:
|
||||
accepts: "npm:~1.3.8"
|
||||
array-flatten: "npm:1.1.1"
|
||||
body-parser: "npm:1.20.2"
|
||||
body-parser: "npm:1.20.3"
|
||||
content-disposition: "npm:0.5.4"
|
||||
content-type: "npm:~1.0.4"
|
||||
cookie: "npm:0.6.0"
|
||||
cookie-signature: "npm:1.0.6"
|
||||
debug: "npm:2.6.9"
|
||||
depd: "npm:2.0.0"
|
||||
encodeurl: "npm:~1.0.2"
|
||||
encodeurl: "npm:~2.0.0"
|
||||
escape-html: "npm:~1.0.3"
|
||||
etag: "npm:~1.8.1"
|
||||
finalhandler: "npm:1.2.0"
|
||||
finalhandler: "npm:1.3.1"
|
||||
fresh: "npm:0.5.2"
|
||||
http-errors: "npm:2.0.0"
|
||||
merge-descriptors: "npm:1.0.1"
|
||||
merge-descriptors: "npm:1.0.3"
|
||||
methods: "npm:~1.1.2"
|
||||
on-finished: "npm:2.4.1"
|
||||
parseurl: "npm:~1.3.3"
|
||||
path-to-regexp: "npm:0.1.7"
|
||||
path-to-regexp: "npm:0.1.10"
|
||||
proxy-addr: "npm:~2.0.7"
|
||||
qs: "npm:6.11.0"
|
||||
qs: "npm:6.13.0"
|
||||
range-parser: "npm:~1.2.1"
|
||||
safe-buffer: "npm:5.2.1"
|
||||
send: "npm:0.18.0"
|
||||
serve-static: "npm:1.15.0"
|
||||
send: "npm:0.19.0"
|
||||
serve-static: "npm:1.16.2"
|
||||
setprototypeof: "npm:1.2.0"
|
||||
statuses: "npm:2.0.1"
|
||||
type-is: "npm:~1.6.18"
|
||||
utils-merge: "npm:1.0.1"
|
||||
vary: "npm:~1.1.2"
|
||||
checksum: 10c0/e82e2662ea9971c1407aea9fc3c16d6b963e55e3830cd0ef5e00b533feda8b770af4e3be630488ef8a752d7c75c4fcefb15892868eeaafe7353cb9e3e269fdcb
|
||||
checksum: 10c0/4cf7ca328f3fdeb720f30ccb2ea7708bfa7d345f9cc460b64a82bf1b2c91e5b5852ba15a9a11b2a165d6089acf83457fc477dc904d59cd71ed34c7a91762c6cc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -8081,18 +8088,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"finalhandler@npm:1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "finalhandler@npm:1.2.0"
|
||||
"finalhandler@npm:1.3.1":
|
||||
version: 1.3.1
|
||||
resolution: "finalhandler@npm:1.3.1"
|
||||
dependencies:
|
||||
debug: "npm:2.6.9"
|
||||
encodeurl: "npm:~1.0.2"
|
||||
encodeurl: "npm:~2.0.0"
|
||||
escape-html: "npm:~1.0.3"
|
||||
on-finished: "npm:2.4.1"
|
||||
parseurl: "npm:~1.3.3"
|
||||
statuses: "npm:2.0.1"
|
||||
unpipe: "npm:~1.0.0"
|
||||
checksum: 10c0/64b7e5ff2ad1fcb14931cd012651631b721ce657da24aedb5650ddde9378bf8e95daa451da43398123f5de161a81e79ff5affe4f9f2a6d2df4a813d6d3e254b7
|
||||
checksum: 10c0/d38035831865a49b5610206a3a9a9aae4e8523cbbcd01175d0480ffbf1278c47f11d89be3ca7f617ae6d94f29cf797546a4619cd84dd109009ef33f12f69019f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -10678,13 +10685,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.set@npm:^4.3.2":
|
||||
version: 4.3.2
|
||||
resolution: "lodash.set@npm:4.3.2"
|
||||
checksum: 10c0/c641d31905e51df43170dce8a1d11a1cff11356e2e2e75fe2615995408e9687d58c3e1d64c3c284c2df2bc519f79a98af737d2944d382ff82ffd244ff6075c29
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.sortby@npm:^4.7.0":
|
||||
version: 4.7.0
|
||||
resolution: "lodash.sortby@npm:4.7.0"
|
||||
@ -11059,10 +11059,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"merge-descriptors@npm:1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "merge-descriptors@npm:1.0.1"
|
||||
checksum: 10c0/b67d07bd44cfc45cebdec349bb6e1f7b077ee2fd5beb15d1f7af073849208cb6f144fe403e29a36571baf3f4e86469ac39acf13c318381e958e186b2766f54ec
|
||||
"merge-descriptors@npm:1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "merge-descriptors@npm:1.0.3"
|
||||
checksum: 10c0/866b7094afd9293b5ea5dcd82d71f80e51514bed33b4c4e9f516795dc366612a4cbb4dc94356e943a8a6914889a914530badff27f397191b9b75cda20b6bae93
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -12324,17 +12324,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-to-regexp@npm:0.1.7":
|
||||
version: 0.1.7
|
||||
resolution: "path-to-regexp@npm:0.1.7"
|
||||
checksum: 10c0/50a1ddb1af41a9e68bd67ca8e331a705899d16fb720a1ea3a41e310480948387daf603abb14d7b0826c58f10146d49050a1291ba6a82b78a382d1c02c0b8f905
|
||||
"path-to-regexp@npm:0.1.10":
|
||||
version: 0.1.10
|
||||
resolution: "path-to-regexp@npm:0.1.10"
|
||||
checksum: 10c0/34196775b9113ca6df88e94c8d83ba82c0e1a2063dd33bfe2803a980da8d49b91db8104f49d5191b44ea780d46b8670ce2b7f4a5e349b0c48c6779b653f1afe4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-to-regexp@npm:^6.2.0, path-to-regexp@npm:^6.2.1":
|
||||
version: 6.2.2
|
||||
resolution: "path-to-regexp@npm:6.2.2"
|
||||
checksum: 10c0/4b60852d3501fd05ca9dd08c70033d73844e5eca14e41f499f069afa8364f780f15c5098002f93bd42af8b3514de62ac6e82a53b5662de881d2b08c9ef21ea6b
|
||||
version: 6.3.0
|
||||
resolution: "path-to-regexp@npm:6.3.0"
|
||||
checksum: 10c0/73b67f4638b41cde56254e6354e46ae3a2ebc08279583f6af3d96fe4664fc75788f74ed0d18ca44fa4a98491b69434f9eee73b97bb5314bd1b5adb700f5c18d6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -12745,15 +12745,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:6.11.0":
|
||||
version: 6.11.0
|
||||
resolution: "qs@npm:6.11.0"
|
||||
dependencies:
|
||||
side-channel: "npm:^1.0.4"
|
||||
checksum: 10c0/4e4875e4d7c7c31c233d07a448e7e4650f456178b9dd3766b7cfa13158fdb24ecb8c4f059fa91e820dc6ab9f2d243721d071c9c0378892dcdad86e9e9a27c68f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:6.11.1":
|
||||
version: 6.11.1
|
||||
resolution: "qs@npm:6.11.1"
|
||||
@ -12763,7 +12754,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.11.2, qs@npm:^6.5.2, qs@npm:^6.9.6":
|
||||
"qs@npm:6.13.0, qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.11.2, qs@npm:^6.5.2, qs@npm:^6.9.6":
|
||||
version: 6.13.0
|
||||
resolution: "qs@npm:6.13.0"
|
||||
dependencies:
|
||||
@ -13848,9 +13839,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"send@npm:0.18.0":
|
||||
version: 0.18.0
|
||||
resolution: "send@npm:0.18.0"
|
||||
"send@npm:0.19.0":
|
||||
version: 0.19.0
|
||||
resolution: "send@npm:0.19.0"
|
||||
dependencies:
|
||||
debug: "npm:2.6.9"
|
||||
depd: "npm:2.0.0"
|
||||
@ -13865,7 +13856,7 @@ __metadata:
|
||||
on-finished: "npm:2.4.1"
|
||||
range-parser: "npm:~1.2.1"
|
||||
statuses: "npm:2.0.1"
|
||||
checksum: 10c0/0eb134d6a51fc13bbcb976a1f4214ea1e33f242fae046efc311e80aff66c7a43603e26a79d9d06670283a13000e51be6e0a2cb80ff0942eaf9f1cd30b7ae736a
|
||||
checksum: 10c0/ea3f8a67a8f0be3d6bf9080f0baed6d2c51d11d4f7b4470de96a5029c598a7011c497511ccc28968b70ef05508675cebff27da9151dd2ceadd60be4e6cf845e3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -13907,15 +13898,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"serve-static@npm:1.15.0":
|
||||
version: 1.15.0
|
||||
resolution: "serve-static@npm:1.15.0"
|
||||
"serve-static@npm:1.16.2":
|
||||
version: 1.16.2
|
||||
resolution: "serve-static@npm:1.16.2"
|
||||
dependencies:
|
||||
encodeurl: "npm:~1.0.2"
|
||||
encodeurl: "npm:~2.0.0"
|
||||
escape-html: "npm:~1.0.3"
|
||||
parseurl: "npm:~1.3.3"
|
||||
send: "npm:0.18.0"
|
||||
checksum: 10c0/fa9f0e21a540a28f301258dfe1e57bb4f81cd460d28f0e973860477dd4acef946a1f41748b5bd41c73b621bea2029569c935faa38578fd34cd42a9b4947088ba
|
||||
send: "npm:0.19.0"
|
||||
checksum: 10c0/528fff6f5e12d0c5a391229ad893910709bc51b5705962b09404a1d813857578149b8815f35d3ee5752f44cd378d0f31669d4b1d7e2d11f41e08283d5134bd1f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -15889,7 +15880,7 @@ __metadata:
|
||||
"@strapi/plugin-graphql": "npm:^5.0.0"
|
||||
"@strapi/plugin-users-permissions": "npm:^5.0.0"
|
||||
"@strapi/strapi": "npm:^5.0.0"
|
||||
lodash.set: "npm:^4.3.2"
|
||||
lodash: "npm:^4.17.19"
|
||||
react: "npm:^18.0.0"
|
||||
react-dom: "npm:^18.0.0"
|
||||
react-router-dom: "npm:^6.0.0"
|
||||
|
||||
@ -138,7 +138,7 @@ describe('Relation permissions', () => {
|
||||
|
||||
const shopEntry = await createEntry(
|
||||
'api::shop.shop',
|
||||
{ name: 'Shop', products: [product.id] },
|
||||
{ name: 'Shop', products: [product.documentId] },
|
||||
populateShop
|
||||
);
|
||||
shop = shopEntry.data;
|
||||
|
||||
@ -23,7 +23,7 @@ const getRelations = async (modelName, field, id) => {
|
||||
url: `/content-manager/relations/api::${modelName}.${modelName}/${id}/${field}`,
|
||||
});
|
||||
|
||||
return res.body.data;
|
||||
return res.body;
|
||||
};
|
||||
|
||||
const deleteFixtures = async () => {
|
||||
@ -48,8 +48,7 @@ const deleteFixtures = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Fix relations
|
||||
describe.skip('Relations', () => {
|
||||
describe('Relations', () => {
|
||||
beforeAll(async () => {
|
||||
await builder
|
||||
.addContentTypes(
|
||||
@ -329,7 +328,8 @@ describe.skip('Relations', () => {
|
||||
expect(tags.length).toBe(0);
|
||||
});
|
||||
|
||||
test('Delete all articles should remove the association in each tags related to them', async () => {
|
||||
test('Delete all articles should remove the association from all tags related to them', async () => {
|
||||
// Create a tag
|
||||
const {
|
||||
body: { data: createdTag },
|
||||
} = await rq({
|
||||
@ -340,6 +340,7 @@ describe.skip('Relations', () => {
|
||||
},
|
||||
});
|
||||
|
||||
// Create the first article associated with the created tag
|
||||
const {
|
||||
body: { data: article12 },
|
||||
} = await rq({
|
||||
@ -352,6 +353,7 @@ describe.skip('Relations', () => {
|
||||
},
|
||||
});
|
||||
|
||||
// Retrieve the updated tag to ensure it has the association
|
||||
const {
|
||||
body: { data: updatedTag },
|
||||
} = await rq({
|
||||
@ -359,6 +361,7 @@ describe.skip('Relations', () => {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
// Create a second article associated with the same tag
|
||||
const {
|
||||
body: { data: article13 },
|
||||
} = await rq({
|
||||
@ -371,6 +374,7 @@ describe.skip('Relations', () => {
|
||||
},
|
||||
});
|
||||
|
||||
// Retrieve the tag again to validate that it is associated with both articles
|
||||
const {
|
||||
body: { data: foundTag },
|
||||
} = await rq({
|
||||
@ -378,38 +382,75 @@ describe.skip('Relations', () => {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
// Assert that the tag is linked to both articles
|
||||
expect(foundTag.articles.count).toBe(2);
|
||||
|
||||
await rq({
|
||||
// Bulk delete both articles using their document IDs
|
||||
const bulkDelete = await rq({
|
||||
url: '/content-manager/collection-types/api::article.article/actions/bulkDelete',
|
||||
method: 'POST',
|
||||
body: {
|
||||
ids: [article12.documentId, article13.documentId],
|
||||
documentIds: [article12.documentId, article13.documentId],
|
||||
},
|
||||
});
|
||||
|
||||
expect(bulkDelete.status).toBe(200);
|
||||
|
||||
// Retrieve the tag again to check that no articles are associated with it
|
||||
const {
|
||||
body: { data: foundTag2 },
|
||||
} = await rq({
|
||||
url: `/content-manager/collection-types/api::tag.tag/${createdTag.documentId}`,
|
||||
url: `/content-manager/collection-types/api::tag.tag/${createdTag.documentId}?populate=articles`,
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
// Expect that the tag has no associated articles after the bulk delete
|
||||
expect(foundTag2.articles.count).toBe(0);
|
||||
});
|
||||
|
||||
test('Bulk delete of unknown or already deleted entries should succeed', async () => {
|
||||
const res = await rq({
|
||||
url: '/content-manager/collection-types/api::article.article/actions/bulkDelete',
|
||||
test('Bulk delete with some known and some unknown should delete and return SUCCESS', async () => {
|
||||
const {
|
||||
body: { data: article12 },
|
||||
} = await rq({
|
||||
url: '/content-manager/collection-types/api::article.article',
|
||||
method: 'POST',
|
||||
body: {
|
||||
ids: [9999999],
|
||||
title: 'article12',
|
||||
content: 'Content',
|
||||
tags: [],
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.body).toEqual({
|
||||
count: 0,
|
||||
const bulkDelete = await rq({
|
||||
url: '/content-manager/collection-types/api::article.article/actions/bulkDelete',
|
||||
method: 'POST',
|
||||
body: {
|
||||
documentIds: [article12.documentId, 9999999],
|
||||
},
|
||||
});
|
||||
|
||||
expect(bulkDelete.status).toBe(200);
|
||||
expect(bulkDelete.body.count).toBe(1);
|
||||
|
||||
// article has been deleted
|
||||
const article = await rq({
|
||||
url: `/content-manager/collection-types/api::article.article/${article12.documentId}`,
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
expect(article.status).toBe(404);
|
||||
});
|
||||
|
||||
test('Bulk delete of entirely unknown entries should return a NOT FOUND', async () => {
|
||||
const bulkDelete = await rq({
|
||||
url: '/content-manager/collection-types/api::article.article/actions/bulkDelete',
|
||||
method: 'POST',
|
||||
body: {
|
||||
documentIds: [9999999],
|
||||
},
|
||||
});
|
||||
|
||||
expect(bulkDelete.status).toBe(404);
|
||||
});
|
||||
});
|
||||
|
||||
@ -562,8 +603,9 @@ describe.skip('Relations', () => {
|
||||
const tags = (await getRelations('article', 'tags', body.data.documentId)).results;
|
||||
expect(tags.length).toBe(0);
|
||||
|
||||
const category = (await getRelations('article', 'category', body.data.documentId)).data;
|
||||
expect(category.name).toBe(data.categories[0].name);
|
||||
const categories = (await getRelations('article', 'category', body.data.documentId)).results;
|
||||
expect(categories.length).toBe(1);
|
||||
expect(categories[0].name).toBe(data.categories[0].name);
|
||||
});
|
||||
|
||||
test('Update article1 with cat2', async () => {
|
||||
@ -592,8 +634,9 @@ describe.skip('Relations', () => {
|
||||
const tags = (await getRelations('article', 'tags', body.data.documentId)).results;
|
||||
expect(tags.length).toBe(0);
|
||||
|
||||
const category = (await getRelations('article', 'category', body.data.documentId)).data;
|
||||
expect(category.name).toBe(data.categories[1].name);
|
||||
const categories = (await getRelations('article', 'category', body.data.documentId)).results;
|
||||
expect(categories.length).toBe(1);
|
||||
expect(categories[0].name).toBe(data.categories[1].name);
|
||||
});
|
||||
|
||||
test('Create article2', async () => {
|
||||
@ -652,8 +695,9 @@ describe.skip('Relations', () => {
|
||||
const tags = (await getRelations('article', 'tags', body.data.documentId)).results;
|
||||
expect(tags.length).toBe(0);
|
||||
|
||||
const category = (await getRelations('article', 'category', body.data.documentId)).data;
|
||||
expect(category.name).toBe(data.categories[1].name);
|
||||
const categories = (await getRelations('article', 'category', body.data.documentId)).results;
|
||||
expect(categories.length).toBe(1);
|
||||
expect(categories[0].name).toBe(data.categories[1].name);
|
||||
});
|
||||
|
||||
test('Update cat1 with article1', async () => {
|
||||
@ -717,7 +761,7 @@ describe.skip('Relations', () => {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
expect(body.data).toMatchObject({ data: { name: 'cat3' } });
|
||||
expect(body).toMatchObject({ results: [{ name: 'cat3' }] });
|
||||
});
|
||||
|
||||
test('Get article2 with cat2', async () => {
|
||||
@ -726,7 +770,7 @@ describe.skip('Relations', () => {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
expect(body.data).toMatchObject({ data: { name: 'cat2' } });
|
||||
expect(body).toMatchObject({ results: [{ name: 'cat2' }] });
|
||||
});
|
||||
|
||||
test('Get cat1 without relations', async () => {
|
||||
@ -735,7 +779,7 @@ describe.skip('Relations', () => {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
expect(body.data).toMatchObject({
|
||||
expect(body).toMatchObject({
|
||||
results: [],
|
||||
pagination: {
|
||||
total: 0,
|
||||
@ -752,7 +796,7 @@ describe.skip('Relations', () => {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
expect(body.data).toMatchObject({
|
||||
expect(body).toMatchObject({
|
||||
pagination: { page: 1, pageCount: 1, pageSize: 10, total: 1 },
|
||||
results: [{ title: 'Article 2' }],
|
||||
});
|
||||
@ -764,7 +808,7 @@ describe.skip('Relations', () => {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
expect(body.data).toMatchObject({
|
||||
expect(body).toMatchObject({
|
||||
pagination: { page: 1, pageCount: 1, pageSize: 10, total: 1 },
|
||||
results: [{ title: 'Article 1' }],
|
||||
});
|
||||
@ -857,8 +901,8 @@ describe.skip('Relations', () => {
|
||||
username: null,
|
||||
});
|
||||
|
||||
const reference = (await getRelations('article', 'reference', body.data.documentId)).data;
|
||||
expect(reference.documentId).toBe(data.references[0].documentId);
|
||||
const references = await getRelations('article', 'reference', body.data.documentId);
|
||||
expect(references.results[0].documentId).toBe(data.references[0].documentId);
|
||||
});
|
||||
|
||||
test('Create article2 with ref1', async () => {
|
||||
@ -887,14 +931,16 @@ describe.skip('Relations', () => {
|
||||
id: 1,
|
||||
username: null,
|
||||
});
|
||||
const reference = (await getRelations('article', 'reference', body.data.documentId)).data;
|
||||
expect(reference.documentId).toBe(data.references[0].documentId);
|
||||
const references = await getRelations('article', 'reference', body.data.documentId);
|
||||
expect(references.results[0].documentId).toBe(data.references[0].documentId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test oneWay relation (reference - tag) with Content Manager', () => {
|
||||
test('Attach Tag to a Reference', async () => {
|
||||
const { body: createdTag } = await rq({
|
||||
const {
|
||||
body: { data: createdTag },
|
||||
} = await rq({
|
||||
url: '/content-manager/collection-types/api::tag.tag',
|
||||
method: 'POST',
|
||||
body: {
|
||||
@ -902,7 +948,9 @@ describe.skip('Relations', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const { body: createdReference } = await rq({
|
||||
const {
|
||||
body: { data: createdReference },
|
||||
} = await rq({
|
||||
url: '/content-manager/collection-types/api::reference.reference',
|
||||
method: 'POST',
|
||||
body: {
|
||||
@ -913,8 +961,8 @@ describe.skip('Relations', () => {
|
||||
|
||||
expect(createdReference.documentId).toBeDefined();
|
||||
|
||||
const tag = (await getRelations('reference', 'tag', createdReference.documentId)).data;
|
||||
expect(tag.documentId).toBe(createdTag.documentId);
|
||||
const tags = await getRelations('reference', 'tag', createdReference.documentId);
|
||||
expect(tags.results[0].documentId).toBe(createdTag.documentId);
|
||||
});
|
||||
|
||||
test('Detach Tag to a Reference', async () => {
|
||||
@ -939,8 +987,8 @@ describe.skip('Relations', () => {
|
||||
},
|
||||
});
|
||||
|
||||
let tag = (await getRelations('reference', 'tag', createdReference.documentId)).data;
|
||||
expect(tag.documentId).toBe(createdTag.documentId);
|
||||
let tags = await getRelations('reference', 'tag', createdReference.documentId);
|
||||
expect(tags.results[0].documentId).toBe(createdTag.documentId);
|
||||
|
||||
const {
|
||||
body: { data: referenceToUpdate },
|
||||
@ -952,8 +1000,8 @@ describe.skip('Relations', () => {
|
||||
},
|
||||
});
|
||||
|
||||
tag = (await getRelations('reference', 'tag', referenceToUpdate.documentId)).results;
|
||||
expect(isEmpty(tag)).toBe(true);
|
||||
tags = await getRelations('reference', 'tag', referenceToUpdate.documentId);
|
||||
expect(isEmpty(tags.results)).toBe(true);
|
||||
});
|
||||
|
||||
test('Delete Tag so the relation in the Reference side should be removed', async () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user