From eab8369fe87ab91f63fff241bacb5caf156eb358 Mon Sep 17 00:00:00 2001 From: ivanThePleasant Date: Thu, 10 Nov 2022 17:37:04 +0200 Subject: [PATCH 01/27] Remove iso locales duplicates and save new tests snapshot --- .../i18n/server/constants/iso-locales.json | 48 ------------------- .../__snapshots__/iso-locales.test.js.snap | 48 ------------------- 2 files changed, 96 deletions(-) diff --git a/packages/plugins/i18n/server/constants/iso-locales.json b/packages/plugins/i18n/server/constants/iso-locales.json index 67c15bbcc7..9ad9618daa 100644 --- a/packages/plugins/i18n/server/constants/iso-locales.json +++ b/packages/plugins/i18n/server/constants/iso-locales.json @@ -591,22 +591,6 @@ "code":"en-GG", "name":"English (Guernsey) (en-GG)" }, - { - "code":"en-CA", - "name":"English (Canada) (en-CA)" - }, - { - "code":"en-EG", - "name":"English (Egypt) (en-EG)" - }, - { - "code":"en-EU", - "name":"English (Europe) (en-EU)" - }, - { - "code":"en-GU", - "name":"English (Guam) (en-GU)" - }, { "code":"en-GY", "name":"English (Guyana) (en-GY)" @@ -667,10 +651,6 @@ "code":"en-MY", "name":"English (Malaysia) (en-MY)" }, - { - "code":"en-JM", - "name":"English (Jamaica) (en-JM)" - }, { "code":"en-MT", "name":"English (Malta) (en-MT)" @@ -719,14 +699,6 @@ "code":"en-NF", "name":"English (Norfolk Island) (en-NF)" }, - { - "code":"en-NA", - "name":"English (Namibia) (en-NA)" - }, - { - "code":"en-NZ", - "name":"English (New Zealand) (en-NZ)" - }, { "code":"en-MP", "name":"English (Northern Mariana Islands) (en-MP)" @@ -795,10 +767,6 @@ "code":"en-SB", "name":"English (Solomon Islands) (en-SB)" }, - { - "code":"en-ZA", - "name":"English (South Africa) (en-ZA)" - }, { "code":"en-SS", "name":"English (South Sudan) (en-SS)" @@ -859,26 +827,10 @@ "code":"en-TV", "name":"English (Tuvalu) (en-TV)" }, - { - "code":"en-PH", - "name":"English (Philippines) (en-PH)" - }, - { - "code":"en-SA", - "name":"English (Saudi Arabia) (en-SA)" - }, - { - "code":"en-SG", - "name":"English (Singapore) (en-SG)" - }, { "code":"en-ZA", "name":"English (South Africa) (en-ZA)" }, - { - "code":"en-TT", - "name":"English (Trinidad and Tobago) (en-TT)" - }, { "code":"en-AE", "name":"English (U.A.E.) (en-AE)" diff --git a/packages/plugins/i18n/server/services/__tests__/__snapshots__/iso-locales.test.js.snap b/packages/plugins/i18n/server/services/__tests__/__snapshots__/iso-locales.test.js.snap index 7484dcef95..c5a1d2dfb7 100644 --- a/packages/plugins/i18n/server/services/__tests__/__snapshots__/iso-locales.test.js.snap +++ b/packages/plugins/i18n/server/services/__tests__/__snapshots__/iso-locales.test.js.snap @@ -594,22 +594,6 @@ exports[`ISO locales getIsoLocales 1`] = ` "code": "en-GG", "name": "English (Guernsey) (en-GG)", }, - { - "code": "en-CA", - "name": "English (Canada) (en-CA)", - }, - { - "code": "en-EG", - "name": "English (Egypt) (en-EG)", - }, - { - "code": "en-EU", - "name": "English (Europe) (en-EU)", - }, - { - "code": "en-GU", - "name": "English (Guam) (en-GU)", - }, { "code": "en-GY", "name": "English (Guyana) (en-GY)", @@ -670,10 +654,6 @@ exports[`ISO locales getIsoLocales 1`] = ` "code": "en-MY", "name": "English (Malaysia) (en-MY)", }, - { - "code": "en-JM", - "name": "English (Jamaica) (en-JM)", - }, { "code": "en-MT", "name": "English (Malta) (en-MT)", @@ -722,14 +702,6 @@ exports[`ISO locales getIsoLocales 1`] = ` "code": "en-NF", "name": "English (Norfolk Island) (en-NF)", }, - { - "code": "en-NA", - "name": "English (Namibia) (en-NA)", - }, - { - "code": "en-NZ", - "name": "English (New Zealand) (en-NZ)", - }, { "code": "en-MP", "name": "English (Northern Mariana Islands) (en-MP)", @@ -798,10 +770,6 @@ exports[`ISO locales getIsoLocales 1`] = ` "code": "en-SB", "name": "English (Solomon Islands) (en-SB)", }, - { - "code": "en-ZA", - "name": "English (South Africa) (en-ZA)", - }, { "code": "en-SS", "name": "English (South Sudan) (en-SS)", @@ -862,26 +830,10 @@ exports[`ISO locales getIsoLocales 1`] = ` "code": "en-TV", "name": "English (Tuvalu) (en-TV)", }, - { - "code": "en-PH", - "name": "English (Philippines) (en-PH)", - }, - { - "code": "en-SA", - "name": "English (Saudi Arabia) (en-SA)", - }, - { - "code": "en-SG", - "name": "English (Singapore) (en-SG)", - }, { "code": "en-ZA", "name": "English (South Africa) (en-ZA)", }, - { - "code": "en-TT", - "name": "English (Trinidad and Tobago) (en-TT)", - }, { "code": "en-AE", "name": "English (U.A.E.) (en-AE)", From f60a188f71f409dbdf35f11eb4ebd90ffcd3c26e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Nov 2022 09:11:17 +0000 Subject: [PATCH 02/27] chore(deps): bump swagger-ui-dist from 4.12.0 to 4.15.5 Bumps [swagger-ui-dist](https://github.com/swagger-api/swagger-ui) from 4.12.0 to 4.15.5. - [Release notes](https://github.com/swagger-api/swagger-ui/releases) - [Commits](https://github.com/swagger-api/swagger-ui/compare/v4.12.0...v4.15.5) --- updated-dependencies: - dependency-name: swagger-ui-dist dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/plugins/documentation/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/plugins/documentation/package.json b/packages/plugins/documentation/package.json index 2cb70f6429..718405ca15 100644 --- a/packages/plugins/documentation/package.json +++ b/packages/plugins/documentation/package.json @@ -42,7 +42,7 @@ "react-router-dom": "5.2.0", "redux": "^4.0.1", "reselect": "^4.0.0", - "swagger-ui-dist": "4.12.0", + "swagger-ui-dist": "4.15.5", "yaml": "1.10.2" }, "peerDependencies": { diff --git a/yarn.lock b/yarn.lock index 3a9e54e588..78c2e91cc9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21630,10 +21630,10 @@ svg-tags@^1.0.0: resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" integrity sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA== -swagger-ui-dist@4.12.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-4.12.0.tgz#986d90f05e81fb9db3ca40372278a5d8ce71db3a" - integrity sha512-B0Iy2ueXtbByE6OOyHTi3lFQkpPi/L7kFOKFeKTr44za7dJIELa9kzaca6GkndCgpK1QTjArnoXG+aUy0XQp1w== +swagger-ui-dist@4.15.5: + version "4.15.5" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-4.15.5.tgz#cda226a79db2a9192579cc1f37ec839398a62638" + integrity sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA== swap-case@^1.1.0: version "1.1.2" From 073b79e76bbda29ac0268844ca2fe4a3363d7864 Mon Sep 17 00:00:00 2001 From: ivanThePleasant Date: Tue, 15 Nov 2022 11:22:04 +0200 Subject: [PATCH 03/27] Add new test to check for duplicate iso locales --- .../plugins/i18n/server/constants/__tests__/index.test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/plugins/i18n/server/constants/__tests__/index.test.js b/packages/plugins/i18n/server/constants/__tests__/index.test.js index e0618330c6..c94bdb58cc 100644 --- a/packages/plugins/i18n/server/constants/__tests__/index.test.js +++ b/packages/plugins/i18n/server/constants/__tests__/index.test.js @@ -1,6 +1,6 @@ 'use strict'; -const { getInitLocale } = require('..'); +const { getInitLocale, isoLocales } = require('..'); describe('I18N default locale', () => { describe('getInitLocale', () => { @@ -23,5 +23,10 @@ describe('I18N default locale', () => { process.env.STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE = 'zzzzz'; expect(() => getInitLocale()).toThrow(); }); + + test('Checks if there are any duplicate locales present in the "iso-locales.json" file', () => { + const set = new Set(isoLocales.map((item) => item.code)).size !== isoLocales.length; + expect(set).toBe(false); + }); }); }); From e0e24c16c2cf762ef8f785d667377e1b1b7d85d7 Mon Sep 17 00:00:00 2001 From: Jorge Rambla Date: Tue, 15 Nov 2022 10:27:05 +0100 Subject: [PATCH 04/27] Rewrite invalid uid prefix error message --- packages/core/strapi/lib/core/domain/content-type/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/strapi/lib/core/domain/content-type/index.js b/packages/core/strapi/lib/core/domain/content-type/index.js index bded92c00f..5323400748 100644 --- a/packages/core/strapi/lib/core/domain/content-type/index.js +++ b/packages/core/strapi/lib/core/domain/content-type/index.js @@ -54,7 +54,7 @@ const createContentType = (uid, definition) => { }); } else { throw new Error( - `Incorrect Content Type UID "${uid}". The UID should start with api::, plugin:: or strapi::.` + `Incorrect Content Type UID "${uid}". The UID should start with api::, plugin:: or admin::.` ); } From 1d9ec79211ebfa939d9e197fa40ff5c103fa3c82 Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Tue, 15 Nov 2022 18:15:38 +0100 Subject: [PATCH 05/27] Refactor nested grids into component for readability --- .../pages/EditView/GridRow/index.js | 56 ++++++++++++++++ .../content-manager/pages/EditView/index.js | 66 ++----------------- 2 files changed, 61 insertions(+), 61 deletions(-) create mode 100644 packages/core/admin/admin/src/content-manager/pages/EditView/GridRow/index.js diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/GridRow/index.js b/packages/core/admin/admin/src/content-manager/pages/EditView/GridRow/index.js new file mode 100644 index 0000000000..0f3064012b --- /dev/null +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/GridRow/index.js @@ -0,0 +1,56 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Grid, GridItem } from '@strapi/design-system/Grid'; +import Inputs from '../../../components/Inputs'; +import FieldComponent from '../../../components/FieldComponent'; + +const GridRow = ({ grid }) => { + return ( + + {grid.map(({ fieldSchema, labelAction, metadatas, name, size, queryInfos }) => { + const isComponent = fieldSchema.type === 'component'; + + if (isComponent) { + const { component, max, min, repeatable = false, required = false } = fieldSchema; + + return ( + + + + ); + } + + return ( + + + + ); + })} + + ); +}; + +GridRow.propTypes = { + grid: PropTypes.array.isRequired, +}; + +export default GridRow; diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js index 0ed1f16a0e..980365106c 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js @@ -18,8 +18,7 @@ import Pencil from '@strapi/icons/Pencil'; import { InjectionZone } from '../../../shared/components'; import permissions from '../../../permissions'; import DynamicZone from '../../components/DynamicZone'; -import FieldComponent from '../../components/FieldComponent'; -import Inputs from '../../components/Inputs'; + import CollectionTypeFormWrapper from '../../components/CollectionTypeFormWrapper'; import EditViewDataManagerProvider from '../../components/EditViewDataManagerProvider'; import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper'; @@ -29,6 +28,7 @@ import Informations from './Informations'; import Header from './Header'; import { createAttributesLayout, getFieldsActionMatchingPermissions } from './utils'; import DeleteLink from './DeleteLink'; +import GridRow from './GridRow'; const cmPermissions = permissions.contentManager; const ctbPermissions = [{ action: 'plugin::content-type-builder.read', subject: null }]; @@ -171,65 +171,9 @@ const EditView = ({ borderColor="neutral150" > - {row.map((grid, gridIndex) => { - return ( - - {grid.map( - ({ - fieldSchema, - labelAction, - metadatas, - name, - size, - queryInfos, - }) => { - const isComponent = fieldSchema.type === 'component'; - - if (isComponent) { - const { - component, - max, - min, - repeatable = false, - required = false, - } = fieldSchema; - - return ( - - - - ); - } - - return ( - - - - ); - } - )} - - ); - })} + {row.map((grid, gridRowIndex) => ( + + ))} ); From 96401f044d00b41d0ddd26183c884564ecd351d2 Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Tue, 15 Nov 2022 18:20:33 +0100 Subject: [PATCH 06/27] Refactor createAttributeLayout function to avoid eslint warning --- .../content-manager/pages/EditView/index.js | 22 +++---------- .../EditView/utils/createAttributesLayout.js | 16 ++++++---- .../tests/createAttributesLayout.test.js | 32 ++++++++++++++++--- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js index 980365106c..8ecb1b0371 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js @@ -1,4 +1,4 @@ -import React, { Suspense, memo, useCallback, useMemo } from 'react'; +import React, { Suspense, memo, useMemo } from 'react'; import PropTypes from 'prop-types'; import get from 'lodash/get'; import { @@ -63,28 +63,16 @@ const EditView = ({ }/${slug}/configurations/edit`; const currentContentTypeLayoutData = get(layout, ['contentType'], {}); - const DataManagementWrapper = useMemo( - () => (isSingleType ? SingleTypeFormWrapper : CollectionTypeFormWrapper), - [isSingleType] - ); + const DataManagementWrapper = isSingleType ? SingleTypeFormWrapper : CollectionTypeFormWrapper; // Check if a block is a dynamic zone - const isDynamicZone = useCallback((block) => { + const isDynamicZone = (block) => { return block.every((subBlock) => { return subBlock.every((obj) => obj.fieldSchema.type === 'dynamiczone'); }); - }, []); + }; - const formattedContentTypeLayout = useMemo(() => { - if (!currentContentTypeLayoutData.layouts) { - return []; - } - - return createAttributesLayout( - currentContentTypeLayoutData.layouts.edit, - currentContentTypeLayoutData.attributes - ); - }, [currentContentTypeLayoutData]); + const formattedContentTypeLayout = createAttributesLayout(currentContentTypeLayoutData); return ( diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js index 793d5b93bd..245ee08f7b 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js @@ -1,14 +1,18 @@ import { get, isEmpty } from 'lodash'; -// TODO: refacto this file to avoid eslint issues -/* eslint-disable no-restricted-syntax */ -/* eslint-disable no-unused-vars */ -const createAttributesLayout = (currentLayout, attributes) => { +const createAttributesLayout = (currentContentTypeLayoutData) => { const getType = (name) => get(attributes, [name, 'type'], ''); let currentRowIndex = 0; const newLayout = []; - for (let row of currentLayout) { + if (!currentContentTypeLayoutData) { + return newLayout; + } + + const currentLayout = currentContentTypeLayoutData.layouts.edit; + const attributes = currentContentTypeLayoutData.attributes; + + currentLayout.forEach((row) => { const hasDynamicZone = row.some(({ name }) => getType(name) === 'dynamiczone'); if (!newLayout[currentRowIndex]) { @@ -27,7 +31,7 @@ const createAttributesLayout = (currentLayout, attributes) => { } else { newLayout[currentRowIndex].push(row); } - } + }); return newLayout.filter((arr) => arr.length > 0); }; diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/tests/createAttributesLayout.test.js b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/tests/createAttributesLayout.test.js index 823bd444a8..c0f6da8b0a 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/tests/createAttributesLayout.test.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/tests/createAttributesLayout.test.js @@ -27,6 +27,12 @@ describe('Content Manager | EditView | utils | createAttributesLayout', () => { [{ name: 'postal_code', size: 6 }], [{ name: 'geolocation', size: 12 }], ]; + const currentLayoutData = { + layouts: { + edit: currentLayout, + }, + attributes, + }; const expected = [ [ [ @@ -38,7 +44,7 @@ describe('Content Manager | EditView | utils | createAttributesLayout', () => { ], ]; - expect(createAttributesLayout(currentLayout, attributes)).toEqual(expected); + expect(createAttributesLayout(currentLayoutData)).toEqual(expected); }); it('Should return an array of size 2 if there is a dynamic zone at the end of the layout', () => { @@ -68,6 +74,12 @@ describe('Content Manager | EditView | utils | createAttributesLayout', () => { [{ name: 'geolocation', size: 12 }], [{ name: 'dynamicZone1', size: 12 }], ]; + const currentLayoutData = { + layouts: { + edit: currentLayout, + }, + attributes, + }; const expected = [ [ [ @@ -80,7 +92,7 @@ describe('Content Manager | EditView | utils | createAttributesLayout', () => { [[{ name: 'dynamicZone1', size: 12 }]], ]; - expect(createAttributesLayout(currentLayout, attributes)).toEqual(expected); + expect(createAttributesLayout(currentLayoutData)).toEqual(expected); }); it('Should return an array of size 2 if there is a dynamic zone at the beginning of the layout', () => { @@ -114,6 +126,12 @@ describe('Content Manager | EditView | utils | createAttributesLayout', () => { [{ name: 'postal_code', size: 6 }], [{ name: 'geolocation', size: 12 }], ]; + const currentLayoutData = { + layouts: { + edit: currentLayout, + }, + attributes, + }; const expected = [ [[{ name: 'dynamicZone1', size: 12 }]], [ @@ -126,7 +144,7 @@ describe('Content Manager | EditView | utils | createAttributesLayout', () => { ], ]; - expect(createAttributesLayout(currentLayout, attributes)).toEqual(expected); + expect(createAttributesLayout(currentLayoutData)).toEqual(expected); }); it('Should return an array of size 5 if there are 3 dynamic zones', () => { @@ -164,6 +182,12 @@ describe('Content Manager | EditView | utils | createAttributesLayout', () => { [{ name: 'geolocation', size: 12 }], [{ name: 'dynamicZone3', size: 12 }], ]; + const currentLayoutData = { + layouts: { + edit: currentLayout, + }, + attributes, + }; const expected = [ [[{ name: 'dynamicZone1', size: 12 }]], [ @@ -177,6 +201,6 @@ describe('Content Manager | EditView | utils | createAttributesLayout', () => { [[{ name: 'dynamicZone3', size: 12 }]], ]; - expect(createAttributesLayout(currentLayout, attributes)).toEqual(expected); + expect(createAttributesLayout(currentLayoutData)).toEqual(expected); }); }); From 7f25aaf7961bb6b773c53b11ce1527e8fbd7503a Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Tue, 15 Nov 2022 18:21:09 +0100 Subject: [PATCH 07/27] Remove useMemo --- .../src/content-manager/pages/EditView/index.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js index 8ecb1b0371..57aac3fe9e 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js @@ -1,4 +1,4 @@ -import React, { Suspense, memo, useMemo } from 'react'; +import React, { Suspense, memo } from 'react'; import PropTypes from 'prop-types'; import get from 'lodash/get'; import { @@ -47,15 +47,11 @@ const EditView = ({ const { trackUsage } = useTracking(); const { formatMessage } = useIntl(); const { createActionAllowedFields, readActionAllowedFields, updateActionAllowedFields } = - useMemo(() => { - return getFieldsActionMatchingPermissions(userPermissions, slug); - }, [userPermissions, slug]); + getFieldsActionMatchingPermissions(userPermissions, slug); - const configurationPermissions = useMemo(() => { - return isSingleType - ? cmPermissions.singleTypesConfigurations - : cmPermissions.collectionTypesConfigurations; - }, [isSingleType]); + const configurationPermissions = isSingleType + ? cmPermissions.singleTypesConfigurations + : cmPermissions.collectionTypesConfigurations; // // FIXME when changing the routing const configurationsURL = `/content-manager/${ From 9f404467fa59882099a2d882e6ee532289682ec0 Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Tue, 15 Nov 2022 18:44:14 +0100 Subject: [PATCH 08/27] Fix check for layouts --- .../pages/EditView/utils/createAttributesLayout.js | 2 +- .../EditView/utils/tests/createAttributesLayout.test.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js index 245ee08f7b..2172ec8c3a 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js @@ -5,7 +5,7 @@ const createAttributesLayout = (currentContentTypeLayoutData) => { let currentRowIndex = 0; const newLayout = []; - if (!currentContentTypeLayoutData) { + if (!currentContentTypeLayoutData.layouts) { return newLayout; } diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/tests/createAttributesLayout.test.js b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/tests/createAttributesLayout.test.js index c0f6da8b0a..2332fa17aa 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/tests/createAttributesLayout.test.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/tests/createAttributesLayout.test.js @@ -203,4 +203,9 @@ describe('Content Manager | EditView | utils | createAttributesLayout', () => { expect(createAttributesLayout(currentLayoutData)).toEqual(expected); }); + + it('Should return an empty array when no layouts are found', () => { + const currentLayoutData = {}; + expect(createAttributesLayout(currentLayoutData)).toEqual([]); + }); }); From 6320f9dcfc6af3306597d9475040d8f92b1896c0 Mon Sep 17 00:00:00 2001 From: a-ulasevich Date: Tue, 15 Nov 2022 23:20:14 +0300 Subject: [PATCH 09/27] Update russian translation --- .../core/admin/admin/src/translations/ru.json | 1278 ++++++++++------- 1 file changed, 789 insertions(+), 489 deletions(-) diff --git a/packages/core/admin/admin/src/translations/ru.json b/packages/core/admin/admin/src/translations/ru.json index 1f75770f03..49fbeaded5 100644 --- a/packages/core/admin/admin/src/translations/ru.json +++ b/packages/core/admin/admin/src/translations/ru.json @@ -1,491 +1,791 @@ { - "Analytics": "Аналитика", - "Auth.components.Oops.text": "Ваш аккаунт был заморожен", - "Auth.form.button.forgot-password": "Отправить письмо", - "Auth.form.button.go-home": "ВЕРНУТЬСЯ НА ГЛАВНУЮ", - "Auth.form.button.login": "Войти", - "Auth.form.button.login.providers.error": "Мы не можем подключить вас через выбранного провайдера.", - "Auth.form.button.login.strapi": "ВОЙТИ ЧЕРЕЗ STRAPI", - "Auth.form.button.register": "Давайте начнем", - "Auth.form.confirmPassword.label": "Подтверждение пароля", - "Auth.form.email.label": "Email", - "Auth.form.email.placeholder": "kai@doe.com", - "Auth.form.error.blocked": "Ваш аккаунт был заблокирован администратором.", - "Auth.form.error.code.provide": "Указан неверный код.", - "Auth.form.error.confirmed": "Ваш e-mail не подтвержден.", - "Auth.form.error.email.invalid": "Неправильный e-mail.", - "Auth.form.error.email.provide": "Укажите свое имя пользователя или e-mail.", - "Auth.form.error.email.taken": "Данный e-mail уже используется", - "Auth.form.error.invalid": "Неверный логин или пароль.", - "Auth.form.error.params.provide": "Предоставлены неверные параметры.", - "Auth.form.error.password.format": "Пароль не может содержать символ `$` больше трех раз.", - "Auth.form.error.password.local": "Этот пользователь никогда не задавал пароль, пожалуйста, войдите в систему через провайдера, используемого при создании учетной записи.", - "Auth.form.error.password.matching": "Пароли не совпадают.", - "Auth.form.error.password.provide": "Укажите свой пароль.", - "Auth.form.error.ratelimit": "Слишком много попыток, повторите через минуту", - "Auth.form.error.user.not-exist": "Этот e-mail не существует.", - "Auth.form.error.username.taken": "Имя пользователя уже используется", - "Auth.form.firstname.label": "Имя", - "Auth.form.firstname.placeholder": "Иван", - "Auth.form.forgot-password.email.label": "Введите ваш e-mail", - "Auth.form.forgot-password.email.label.success": "Письмо успешно отправлено e-mail", - "Auth.form.lastname.label": "Фамилия", - "Auth.form.lastname.placeholder": "Иванов", - "Auth.form.register.news.label": "Держите меня в курсе о новых функциях и предстоящих улучшениях (делая это, вы принимаете {terms} и {policy}).", - "Auth.form.rememberMe.label": "Запомнить меня", - "Auth.form.username.label": "Имя пользователя", - "Auth.form.username.placeholder": "Иван Иванов", - "Auth.link.forgot-password": "Забыли пароль?", - "Auth.link.ready": "Готовы войти?", - "Auth.link.signin": "Войти", - "Auth.link.signin.account": "Уже есть аккаунт?", - "Auth.privacy-policy-agreement.policy": "политика конфиденциальности", - "Auth.privacy-policy-agreement.terms": "условия", - "Content Manager": "Редактор контента", - "Content Type Builder": "Типы контента", - "Documentation": "Документация", - "Email": "E-mail", - "Files Upload": "Загрузка файлов", - "HomePage.helmet.title": "Домашняя страница", - "HomePage.roadmap": "Смотрите нашу дорожную карту", - "HomePage.welcome.congrats": "Поздравляем!", - "HomePage.welcome.congrats.content": "Вы вошли как первый администратор. Чтобы открыть для себя мощные функции, предоставляемые Strapi,", - "HomePage.welcome.congrats.content.bold": "мы рекомендуем вам создать свою первую коллекцию.", - "Media Library": "Медиа-библиотека", - "New entry": "Новая запись", - "Password": "Пароль", - "Provider": "Провайдер", - "ResetPasswordToken": "Сброс токена пароля", - "Role": "Роль", - "Roles & Permissions": "Роли и разрешения", - "Roles.ListPage.notification.delete-all-not-allowed": "Некоторые роли нельзя было удалить, так как они связаны с пользователями.", - "Roles.ListPage.notification.delete-not-allowed": "Невозможно удалить роль, если она связана с пользователями", - "Roles.components.List.empty.withSearch": "Нет роли, соответствующей поиску ({search})...", - "Settings.PageTitle": "Настройки - {name}", - "Settings.apiTokens.copy.editMessage": "Из соображений безопасности вы можете увидеть свой токен только один раз.", - "Settings.apiTokens.copy.editTitle": "Этот токен больше не доступен", - "Settings.apiTokens.types.full-access": "Полный доступ", - "Settings.apiTokens.types.read-only": "Только для чтения", - "Settings.apiTokens.title": "API Токены", - "Settings.apiTokens.description": "Список сгенерированных токенов для использования API", - "Settings.application.description": "Смотреть детали вашего проекта", - "Settings.application.edition-title": "ТЕКУЩИЙ ПЛАН", - "Settings.application.link-pricing": "Смотреть все тарифы", - "Settings.application.link-upgrade": "Обновить ваше приложение", - "Settings.application.node-version": "ВЕРСИЯ NODE", - "Settings.application.strapi-version": "ВЕРСИЯ STRAPI", - "Settings.application.strapiVersion": "ВЕРСИЯ STRAPI", - "Settings.application.title": "Приложение", - "Settings.error": "Ошибка", - "Settings.global": "Глобальные настройки", - "Settings.permissions": "Панель администратора", - "Settings.permissions.category": "Настройки разрешений для {category}", - "Settings.permissions.category.plugins": "Настройки разрешений для плагина {category}", - "Settings.permissions.conditions.anytime": "Всегда", - "Settings.permissions.conditions.apply": "Применить", - "Settings.permissions.conditions.can": "Можно", - "Settings.permissions.conditions.conditions": "Определить условия", - "Settings.permissions.conditions.links": "Ссылки", - "Settings.permissions.conditions.no-actions": "Нет действия", - "Settings.permissions.conditions.none-selected": "Любое время", - "Settings.permissions.conditions.or": "ИЛИ", - "Settings.permissions.conditions.when": "Когда", - "Settings.permissions.users.create": "Создать нового пользователя", - "Settings.permissions.users.email": "Email", - "Settings.permissions.users.firstname": "Имя", - "Settings.permissions.users.lastname": "Фамилия", - "Settings.permissions.users.form.sso": "Соединить с SSO", - "Settings.permissions.users.form.sso.description": "Когда включено (ВКЛЮЧЕНО), пользователи смогут входить через SSO", - "Settings.profile.form.section.experience.interfaceLanguage": "Язык интерфейса", - "Settings.profile.form.section.experience.interfaceLanguage.hint": "Только ваш интерфейс будет отображаться на выбранном языке.", - "Settings.profile.form.section.experience.title": "Опыт", - "Settings.roles.create.description": "Определите права, предоставленные ролью", - "Settings.roles.create.title": "Создать роль", - "Settings.roles.created": "Роль создана", - "Settings.roles.edit.title": "Изменить роль", - "Settings.roles.form.button.users-with-role": "Пользователи с этой ролью", - "Settings.roles.form.created": "Создано", - "Settings.roles.form.description": "Название и описание роли", - "Settings.roles.form.permission.property-label": "{label} разрешения", - "Settings.roles.form.permissions.attributesPermissions": "Разрешения полей", - "Settings.roles.form.permissions.create": "Создать", - "Settings.roles.form.permissions.delete": "Удалить", - "Settings.roles.form.permissions.publish": "Опубликовать", - "Settings.roles.form.permissions.read": "Прочесть", - "Settings.roles.form.permissions.update": "Обновить", - "Settings.roles.list.button.add": "Добавить новую роль", - "Settings.roles.list.description": "Список ролей", - "Settings.roles.title.singular": "роль", - "Settings.sso.description": "Настройте параметры для функции единого входа.", - "Settings.sso.form.defaultRole.description": "Присоединит нового аутентифицированного пользователя к выбранной роли", - "Settings.sso.form.defaultRole.description-not-allowed": "У вас должно быть разрешение на чтение ролей администратора", - "Settings.sso.form.defaultRole.label": "Роль по умолчанию", - "Settings.sso.form.registration.description": "Создать нового пользователя при входе через SSO, если учетной записи нет", - "Settings.sso.form.registration.label": "Авто-регистрация", - "Settings.sso.title": "Функция единого входа", - "Settings.webhooks.create": "Создание webhook", - "Settings.webhooks.create.header": "Создание нового заголовка", - "Settings.webhooks.created": "Webhook создан", - "Settings.webhooks.event.publish-tooltip": "Это событие существует только для содержимого с включенной системой черновиков/публикаций.", - "Settings.webhooks.events.create": "Создание", - "Settings.webhooks.events.update": "Обновление", - "Settings.webhooks.form.events": "События", - "Settings.webhooks.form.headers": "Заголовки", - "Settings.webhooks.form.url": "Url", - "Settings.webhooks.key": "Ключ", - "Settings.webhooks.list.button.add": "Добавить новый webhook", - "Settings.webhooks.list.description": "Уведомления с помощью POST событий.", - "Settings.webhooks.list.empty.description": "Добавить первый в этот список.", - "Settings.webhooks.list.empty.link": "Просмотреть документацию", - "Settings.webhooks.list.empty.title": "Пока еще нет webhooks", - "Settings.webhooks.singular": "webhook", - "Settings.webhooks.title": "Webhooks", - "Settings.webhooks.trigger": "Триггер", - "Settings.webhooks.trigger.cancel": "Отмена триггера", - "Settings.webhooks.trigger.pending": "Ожидание…", - "Settings.webhooks.trigger.save": "Пожалуйста сохраните триггер", - "Settings.webhooks.trigger.success": "Успех!", - "Settings.webhooks.trigger.success.label": "Триггер выполнен", - "Settings.webhooks.trigger.test": "Тест триггер", - "Settings.webhooks.trigger.title": "Сохранить перед триггером", - "Settings.webhooks.value": "Значение", - "Username": "Имя пользователя", - "Users": "Пользователи", - "Users & Permissions": "Пользователи и разрешения", - "Users.components.List.empty": "Нет пользователей...", - "Users.components.List.empty.withFilters": "Нет пользователей с примененными фильтрами...", - "Users.components.List.empty.withSearch": "Нет пользователей, соответствующих запросу ({search})...", - "app.components.BlockLink.code": "Примеры кода", - "app.components.Button.cancel": "Отменить", - "app.components.Button.reset": "Сброс", - "app.components.ComingSoonPage.comingSoon": "Скоро", - "app.components.DownloadInfo.download": "Выполняется загрузка...", - "app.components.DownloadInfo.text": "Это может занять около минуты. Спасибо за ваше терпение.", - "app.components.EmptyStateLayout.content-document": "Данные не найдены", - "app.components.EmptyAttributes.title": "Пока нет полей", - "app.components.HomePage.button.blog": "СМОТРИТЕ БОЛЬШЕ В БЛОГЕ", - "app.components.HomePage.community": "Найдите сообщество в интернете", - "app.components.HomePage.community.content": "Обсуждайте с членами команды и разработчиками в разных каналах.", - "app.components.HomePage.create": "Создайте свой первый тип контента", - "app.components.HomePage.welcome": "Добро пожаловать на борт!", - "app.components.HomePage.welcome.again": "Добро пожаловать ", - "app.components.HomePage.welcomeBlock.content": "Мы рады, что вы присоединились к сообществу. Нам необходима обратная связь для развития проекта, поэтому не стесняйтесь писать нам в ", - "app.components.HomePage.welcomeBlock.content.again": "Надеемся, что вы делаете успехи в вашем проекте... Следите за последними новостями Strapi. Мы стараемся изо всех сил, чтобы улучшить продукт, основываясь на ваших пожеланиях.", - "app.components.HomePage.welcomeBlock.content.issues": "проблемах.", - "app.components.HomePage.welcomeBlock.content.raise": " или сообщать о ", - "app.components.ImgPreview.hint": "Перетащите файл в эту область или {browse} файл для загрузки", - "app.components.ImgPreview.hint.browse": "выберите", - "app.components.InputFile.newFile": "Добавить новый файл", - "app.components.InputFileDetails.open": "Открыть в новой вкладке", - "app.components.InputFileDetails.originalName": "Оригинальное название:", - "app.components.InputFileDetails.remove": "Удалить этот файл", - "app.components.InputFileDetails.size": "Размер:", - "app.components.InstallPluginPage.Download.description": "Для загрузки и установки плагина может потребоваться несколько секунд.", - "app.components.InstallPluginPage.Download.title": "Загрузка...", - "app.components.InstallPluginPage.description": "Расширяйте ваше приложение без особых усилий.", - "app.components.LeftMenu.logout": "Выйти", - "app.components.LeftMenu.navbrand.title": "Strapi Панель", - "app.components.LeftMenu.navbrand.workplace": "Рабочая область", - "app.components.LeftMenuFooter.help": "Помощь", - "app.components.LeftMenuFooter.poweredBy": "Работает на ", - "app.components.LeftMenuLinkContainer.collectionTypes": "Типы коллекций", - "app.components.LeftMenuLinkContainer.configuration": "Настройки", - "app.components.LeftMenuLinkContainer.general": "Общие", - "app.components.LeftMenuLinkContainer.noPluginsInstalled": "Нет установленных плагинов", - "app.components.LeftMenuLinkContainer.plugins": "Плагины", - "app.components.LeftMenuLinkContainer.singleTypes": "Страницы", - "app.components.ListPluginsPage.deletePlugin.description": "Удаление плагина может занять несколько секунд.", - "app.components.ListPluginsPage.deletePlugin.title": "Удаление", - "app.components.ListPluginsPage.description": "Список установленных плагинов в проекте.", - "app.components.ListPluginsPage.helmet.title": "Список плагинов", - "app.components.Logout.logout": "Выйти", - "app.components.Logout.profile": "Профиль", - "app.components.NotFoundPage.back": "Вернуться на главную", - "app.components.NotFoundPage.description": "Не найдено", - "app.components.Official": "Официальный", - "app.components.Onboarding.label.completed": "% завершено", - "app.components.Onboarding.title": "Смотреть вводные видео", - "app.components.PluginCard.Button.label.download": "Скачать", - "app.components.PluginCard.Button.label.install": "Уже установлено", - "app.components.PluginCard.PopUpWarning.install.impossible.autoReload.needed": "Функция autoReload (автоматической перезагрузки) должна быть включена. Пожалуйста, запустите ваше приложение с помощью `yarn develop`.", - "app.components.PluginCard.PopUpWarning.install.impossible.confirm": "Я понимаю!", - "app.components.PluginCard.PopUpWarning.install.impossible.environment": "В целях безопасности плагин может быть загружен только в среде разработки.", - "app.components.PluginCard.PopUpWarning.install.impossible.title": "Загрузка невозможна", - "app.components.PluginCard.compatible": "Совместимо с вашим приложением", - "app.components.PluginCard.compatibleCommunity": "Совместимо с сообществом", - "app.components.PluginCard.more-details": "Больше деталей", - "app.components.UpgradePlanModal.button": "УЗНАТЬ БОЛЬШЕ", - "app.components.UpgradePlanModal.limit-reached": "Вы достигли предела", - "app.components.UpgradePlanModal.text-ce": "Community Edition", - "app.components.UpgradePlanModal.text-ee": "Enterprise Edition", - "app.components.UpgradePlanModal.text-power": "Разблокируйте всю мощь", - "app.components.UpgradePlanModal.text-strapi": "Strapi, обновив свой план до", - "app.components.Users.MagicLink.connect": "Отправьте эту ссылку пользователю, чтобы он подключился.", - "app.components.Users.ModalCreateBody.block-title.details": "Детали", - "app.components.Users.ModalCreateBody.block-title.roles": "Роли пользователя", - "app.components.Users.SortPicker.button-label": "Сортировать по", - "app.components.Users.SortPicker.sortby.email_asc": "Электронная почта (от А до Я)", - "app.components.Users.SortPicker.sortby.email_desc": "Электронная почта (от Я до А)", - "app.components.Users.SortPicker.sortby.firstname_asc": "Имя (от А до Я)", - "app.components.Users.SortPicker.sortby.firstname_desc": "Имя (от Я до А)", - "app.components.Users.SortPicker.sortby.lastname_asc": "Фамилия (от А до Я)", - "app.components.Users.SortPicker.sortby.lastname_desc": "Фамилия (от Я до А)", - "app.components.Users.SortPicker.sortby.username_asc": "Имя пользователя (от А до Я)", - "app.components.Users.SortPicker.sortby.username_desc": "Имя пользователя (от Я до А)", - "app.components.listPlugins.button": "Добавить новый плагин", - "app.components.listPlugins.title.none": "Нет установленных плагинов", - "app.components.listPluginsPage.deletePlugin.error": "Произошла ошибка при удалении плагина", - "app.containers.App.notification.error.init": "Произошла ошибка при запросе к API", - "app.containers.AuthPage.ForgotPasswordSuccess.text.contact-admin": "Если вы не получили эту ссылку, обратитесь к администратору.", - "app.containers.AuthPage.ForgotPasswordSuccess.text.email": "Получение ссылки для восстановления пароля может занять несколько минут..", - "app.containers.AuthPage.ForgotPasswordSuccess.title": "Письмо отправлено", - "app.containers.Users.EditPage.form.active.label": "Активный", - "app.containers.Users.EditPage.header.label": "Редактировать {name}", - "app.containers.Users.EditPage.header.label-loading": "Редактировать user", - "app.containers.Users.EditPage.roles-bloc-title": "Атрибуты ролей", - "app.containers.Users.ModalForm.footer.button-success": "Создать пользователя", - "app.links.configure-view": "Настройка представления", - "app.static.links.cheatsheet": "Шпаргалка", - "app.utils.SelectOption.defaultMessage": " ", - "app.utils.add-filter": "Добавить фильтр", - "app.utils.defaultMessage": " ", - "app.utils.errors.file-too-big.message": "Файл слишком большой", - "app.utils.filters": "Фильтры", - "app.utils.placeholder.defaultMessage": " ", - "app.utils.publish": "Публиковать", - "app.utils.select-all": "Выбрать все", - "app.utils.unpublish": "Отменить публикацию", - "admin.pages.MarketPlacePage.subtitle": "Получите больше от Strapi", - "admin.pages.MarketPlacePage.search.placeholder": "Найти плагин", - "component.Input.error.validation.integer": "Значение должно быть целочисленным", - "components.AutoReloadBlocker.description": "Запустите Strapi с помощью одной из следующих команд:", - "components.AutoReloadBlocker.header": "Функционал перезапуска необходим для этого плагина.", - "components.ErrorBoundary.title": "Что-то пошло не так...", - "components.Input.error.attribute.key.taken": "Это значение уже существует", - "components.Input.error.attribute.sameKeyAndName": "Не может быть одинаковым", - "components.Input.error.attribute.taken": "Поле с таким названием уже существует", - "components.Input.error.contain.lowercase": "Пароль должен содержать хотя бы один символ нижнего регистра.", - "components.Input.error.contain.number": "пароль должен содержать как минимум одну цифру", - "components.Input.error.contain.uppercase": "Пароль должен содержать хотя бы один символ верхнего регистра.", - "components.Input.error.contentTypeName.taken": "Это название уже существует", - "components.Input.error.custom-error": "{errorMessage} ", - "components.Input.error.password.noMatch": "Пароль не совпадает", - "components.Input.error.validation.email": "Это не адрес электронной почты", - "components.Input.error.validation.json": "Не соответствует JSON формату", - "components.Input.error.validation.max": "Значение слишком большое.", - "components.Input.error.validation.maxLength": "Значение слишком длинное.", - "components.Input.error.validation.min": "Значение слишком маленькое.", - "components.Input.error.validation.minLength": "Значение слишком короткое.", - "components.Input.error.validation.minSupMax": "Не может быть больше", - "components.Input.error.validation.regex": "Значение не соответствует регулярному выражению.", - "components.Input.error.validation.required": "Обязательное значение.", - "components.Input.error.validation.unique": "Это значение уже используется.", - "components.InputSelect.option.placeholder": "Выберите здесь", - "components.ListRow.empty": "Нет данных для отображения.", - "components.NotAllowedInput.text": "Нет прав на просмотр этого поля", - "components.OverlayBlocker.description": "Вы воспользовались функционалом, который требует перезапуска сервера. Пожалуйста, подождите, пока сервер не будет запущен.", - "components.OverlayBlocker.description.serverError": "Сервер должен был перезагрузиться, пожалуйста, проверьте ваши логи в терминале.", - "components.OverlayBlocker.title": "Ожидание перезапуска...", - "components.OverlayBlocker.title.serverError": "Перезапуск занимает больше времени, чем ожидалось", - "components.PageFooter.select": "записей на странице", - "components.ProductionBlocker.description": "В целях безопасности мы должны отключить этот плагин в других средах.", - "components.ProductionBlocker.header": "Этот плагин доступен только на стадии разработки.", - "components.Search.placeholder": "Поиск...", - "components.Wysiwyg.collapse": "Свернуть", - "components.Wysiwyg.selectOptions.H1": "Заголовок H1", - "components.Wysiwyg.selectOptions.H2": "Заголовок H2", - "components.Wysiwyg.selectOptions.H3": "Заголовок H3", - "components.Wysiwyg.selectOptions.H4": "Заголовок H4", - "components.Wysiwyg.selectOptions.H5": "Заголовок H5", - "components.Wysiwyg.selectOptions.H6": "Заголовок H6", - "components.Wysiwyg.selectOptions.title": "Добавить заголовок", - "components.WysiwygBottomControls.charactersIndicators": "символов", - "components.WysiwygBottomControls.fullscreen": "Развернуть", - "components.WysiwygBottomControls.uploadFiles": "Перетащите файлы в эту область, вставьте из буфера обмена или {browse}.", - "components.WysiwygBottomControls.uploadFiles.browse": "выберите их", - "components.popUpWarning.button.cancel": "Нет, отменить", - "components.popUpWarning.button.confirm": "Да подтверждаю", - "components.popUpWarning.message": "Вы уверены, что хотите удалить это?", - "components.popUpWarning.title": "Пожалуйста, подтвердите", - "content-manager.EditRelations.title": "Связанные данные", - "content-manager.api.id": "API ID", - "content-manager.components.AddFilterCTA.add": "Фильтры", - "content-manager.components.AddFilterCTA.hide": "Фильтры", - "content-manager.components.DraggableAttr.edit": "Нажмите чтобы редактировать", - "content-manager.components.DynamicZone.pick-compo": "Выберите компонент", - "content-manager.components.DynamicZone.required": "Обязательный компонент", - "content-manager.components.EmptyAttributesBlock.button": "Перейти в настройки", - "content-manager.components.EmptyAttributesBlock.description": "Вы можете изменить текущие настройки", - "content-manager.components.FieldItem.linkToComponentLayout": "Установить компоновку компонентов", - "content-manager.components.FilterOptions.button.apply": "Применить", - "content-manager.components.FiltersPickWrapper.PluginHeader.actions.apply": "Применить", - "content-manager.components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Очистить все", - "content-manager.components.FiltersPickWrapper.PluginHeader.description": "Укажите условия для фильтрации записей", - "content-manager.components.FiltersPickWrapper.PluginHeader.title.filter": "Фильтры", - "content-manager.components.FiltersPickWrapper.hide": "Скрыть", - "content-manager.components.LeftMenu.single-types": "Одиночные типы", - "content-manager.components.LeftMenu.collection-types": "Типы коллекций", - "content-manager.components.LimitSelect.itemsPerPage": "Элементов на странице", - "content-manager.components.NotAllowedInput.text": "Нет разрешений на просмотр этого поля", - "content-manager.components.Search.placeholder": "Поиск записей...", - "content-manager.components.Select.draft-info-title": "Состояние: Черновик", - "content-manager.components.Select.publish-info-title": "Состояние: Опубликовано", - "content-manager.components.SettingsViewWrapper.pluginHeader.description.edit-settings": "Настройте, как будет выглядеть вид редактирования.", - "content-manager.components.SettingsViewWrapper.pluginHeader.description.list-settings": "Определите параметры представления списка.", - "content-manager.components.SettingsViewWrapper.pluginHeader.title": "Настройка представления - {name}", - "content-manager.components.TableDelete.delete": "Удалить все", - "content-manager.components.TableDelete.deleteSelected": "Удалить выбранное", - "content-manager.components.TableEmpty.withFilters": "Нет {contentType} с примененными фильтрами...", - "content-manager.components.TableEmpty.withSearch": "Нет {contentType} согласно поиску ({search})", - "content-manager.components.TableEmpty.withoutFilter": "Нет {contentType}...", - "content-manager.components.empty-repeatable": "Еще нет записей. Нажмите кнопку ниже, чтобы добавить одну.", - "content-manager.components.notification.info.maximum-requirement": "Вы уже достигли максимального количества полей", - "content-manager.components.notification.info.minimum-requirement": "Добавлено поле, соответствующее минимальным требованиям", - "content-manager.components.repeatable.reorder.error": "Произошла ошибка при изменении порядка полей вашего компонента. Попробуйте еще раз.", - "content-manager.components.reset-entry": "Сбросить запись", - "content-manager.components.uid.apply": "применить", - "content-manager.components.uid.available": "доступный", - "content-manager.components.uid.regenerate": "восстановить", - "content-manager.components.uid.suggested": "предложенный", - "content-manager.components.uid.unavailable": "недоступный", - "content-manager.containers.Edit.Link.Layout": "Настройка макета", - "content-manager.containers.Edit.Link.Model": "Измените тип коллекции", - "content-manager.containers.Edit.addAnItem": "Добавить элемент", - "content-manager.containers.Edit.clickToJump": "Нажмите для перехода к записи", - "content-manager.containers.Edit.delete": "Удалить", - "content-manager.containers.Edit.delete-entry": "Удалить эту запись", - "content-manager.containers.Edit.editing": "Редактирование...", - "content-manager.containers.Edit.information": "Информация", - "content-manager.containers.Edit.information.by": "по", - "content-manager.containers.Edit.information.draftVersion": "черновая версия", - "content-manager.containers.Edit.information.editing": "редактирование", - "content-manager.containers.Edit.information.lastUpdate": "Последнее обновление", - "content-manager.containers.Edit.information.publishedVersion": "опубликованная версия", - "content-manager.containers.Edit.pluginHeader.title.new": "Создать запись", - "content-manager.containers.Edit.reset": "Сбросить", - "content-manager.containers.Edit.returnList": "Вернуться к списку", - "content-manager.containers.Edit.seeDetails": "Подробнее", - "content-manager.containers.Edit.submit": "Сохранить", - "content-manager.containers.EditSettingsView.modal-form.edit-field": "Отредактируйте это поле", - "content-manager.containers.EditView.notification.errors": "Форма содержит некоторые ошибки", - "content-manager.containers.Home.introduction": "Для того чтобы отредактировать ваши записи используйте соответствующую ссылку в меню слева. У плагина отсутствует полноценная возможность редактировать настройки и он все еще находится в стадии активной разработки.", - "content-manager.containers.Home.pluginHeaderDescription": "Управляйте своими записями с помощью мощного и красивого интерфейса.", - "content-manager.containers.Home.pluginHeaderTitle": "Редактор контента", - "content-manager.containers.List.draft": "Черновик", - "content-manager.containers.List.errorFetchRecords": "Ошибка", - "content-manager.containers.List.published": "Опубликованный", - "content-manager.containers.ListPage.displayedFields": "Отображаемые поля", - "content-manager.containers.ListPage.table-headers.publishedAt": "Состояние", - "content-manager.containers.ListSettingsView.modal-form.edit-label": "Отредактируйте ярлык", - "content-manager.containers.SettingPage.add.field": "Добавить еще одно поле", - "content-manager.containers.SettingPage.attributes": "Поля атрибутов", - "content-manager.containers.SettingPage.attributes.description": "Определить порядок атрибутов", - "content-manager.containers.SettingPage.editSettings.description": "Перетащите поля, чтобы определить макет", - "content-manager.containers.SettingPage.editSettings.entry.title": "Заголовок записи", - "content-manager.containers.SettingPage.editSettings.entry.title.description": "Установите отображаемое поле вашей записи", - "content-manager.containers.SettingPage.editSettings.relation-field.description": "Установите поле, которое будет отображаться как в режиме редактирования, так и в списке.", - "content-manager.containers.SettingPage.editSettings.title": "Редактирование — Настройки", - "content-manager.containers.SettingPage.layout": "Макет", - "content-manager.containers.SettingPage.listSettings.description": "Настройте параметры для этого типа коллекции", - "content-manager.containers.SettingPage.listSettings.title": "Просмотр списка (настройки)", - "content-manager.containers.SettingPage.pluginHeaderDescription": "Настройте конкретные параметры для этого типа коллекции", - "content-manager.containers.SettingPage.settings": "Настройки", - "content-manager.containers.SettingPage.view": "Вид", - "content-manager.containers.SettingViewModel.pluginHeader.title": "Контент менеджер - {name}", - "content-manager.containers.SettingsPage.Block.contentType.description": "Настроить отдельные параметры", - "content-manager.containers.SettingsPage.Block.contentType.title": "Типы коллекций", - "content-manager.containers.SettingsPage.Block.generalSettings.description": "Настройте параметры по умолчанию для ваших типов коллекций", - "content-manager.containers.SettingsPage.Block.generalSettings.title": "Общее", - "content-manager.containers.SettingsPage.pluginHeaderDescription": "Настройте параметры для всех ваших типов коллекций и групп.", - "content-manager.containers.SettingsView.list.subtitle": "Настройте макет и отображение ваших типов и групп Коллекции", - "content-manager.containers.SettingsView.list.title": "Конфигурация отображения", - "content-manager.emptyAttributes.button": "Перейдите в конструктор типов коллекций", - "content-manager.emptyAttributes.description": "Добавьте свое первое поле в тип коллекции", - "content-manager.emptyAttributes.title": "Пока нет полей", - "content-manager.error.attribute.key.taken": "Это значение уже существует", - "content-manager.error.attribute.sameKeyAndName": "Не может быть одинаковым", - "content-manager.error.attribute.taken": "Поле с таким названием уже существует", - "content-manager.error.contentTypeName.taken": "Это название уже существует", - "content-manager.error.model.fetch": "Произошла ошибка во время настройки конфигурации модели.", - "content-manager.error.record.create": "Произошла ошибка при создании записи.", - "content-manager.error.record.delete": "Произошла ошибка при удалении записи.", - "content-manager.error.record.fetch": "Произошла ошибка при извлечении записи.", - "content-manager.error.record.update": "Произошла ошибка при обновлении записи.", - "content-manager.error.records.count": "Произошла ошибка при подсчете количества записей.", - "content-manager.error.records.fetch": "Произошла ошибка при извлечении записей.", - "content-manager.error.schema.generation": "Возникла ошибка во время генерации структуры.", - "content-manager.error.validation.json": "Это не JSON", - "content-manager.error.validation.max": "Слишком большое.", - "content-manager.error.validation.maxLength": "Слишком длинное.", - "content-manager.error.validation.min": "Слишком маленькое.", - "content-manager.error.validation.minLength": "Слишком короткое.", - "content-manager.error.validation.minSupMax": "Не может быть выше", - "content-manager.error.validation.regex": "Значение не соответствует регулярному выражению.", - "content-manager.error.validation.required": "Обязательное значение.", - "content-manager.form.Input.bulkActions": "Включить массовые действия", - "content-manager.form.Input.defaultSort": "Сортировка по умолчанию", - "content-manager.form.Input.description": "Описание", - "content-manager.form.Input.description.placeholder": "Имя, отображаемое в профиле", - "content-manager.form.Input.editable": "Редактируемое поле", - "content-manager.form.Input.filters": "Включить фильтры", - "content-manager.form.Input.label": "Подпись", - "content-manager.form.Input.label.inputDescription": "Это значение переопределяет название, отображаемое в заголовке таблицы", - "content-manager.form.Input.pageEntries": "Записей на странице", - "content-manager.form.Input.pageEntries.inputDescription": "Примечание. Вы можете переопределить это значение на странице настроек типа коллекции.", - "content-manager.form.Input.placeholder": "Плейсхолдер", - "content-manager.form.Input.placeholder.placeholder": "Мое значение", - "content-manager.form.Input.search": "Включить поиск", - "content-manager.form.Input.search.field": "Включить поиск по этому полю", - "content-manager.form.Input.sort.field": "Включить сортировку по этому полю", - "content-manager.form.Input.wysiwyg": "Отображение в виде WYSIWYG", - "content-manager.global.displayedFields": "Отображение полей", - "content-manager.groups": "Группы", - "content-manager.groups.numbered": "Группы ({number})", - "content-manager.HeaderLayout.button.label-add-entry": "Создать новую запись", - "content-manager.models": "Типы коллекции", - "content-manager.models.numbered": "Типы коллекции ({number})", - "content-manager.notification.error.displayedFields": "Необходимо добавить хотя бы одно поле", - "content-manager.notification.error.relationship.fetch": "Возникла ошибка при получении связей.", - "content-manager.notification.info.SettingPage.disableSort": "У вас должен быть один атрибут с разрешенной сортировкой", - "content-manager.notification.info.minimumFields": "Вам нужно иметь хотя бы одно отображаемое поле", - "content-manager.notification.upload.error": "Произошла ошибка при загрузке ваших файлов", - "content-manager.pageNotFound": "Страница не найдена", - "content-manager.permissions.not-allowed.create": "У вас нет прав на создание документов", - "content-manager.permissions.not-allowed.update": "У вас нет прав на просмотр этого документа", - "content-manager.plugin.description.long": "Быстрый способ увидеть, отредактировать и удалить данные в вашей базе данных.", - "content-manager.plugin.description.short": "Быстрый способ увидеть, отредактировать и удалить данные в вашей базе данных.", - "content-manager.success.record.delete": "Удалено", - "content-manager.success.record.publish": "Опубликовано", - "content-manager.success.record.save": "Сохранено", - "content-manager.success.record.unpublish": "Не опубликовано", - "content-manager.popUpWarning.warning.publish-question": "Вы уверены, что хотите опубликовать запись?", - "content-manager.popUpwarning.warning.has-draft-relations.button-confirm": "Да, публиковать", - "form.button.done": "Выполнено", - "global.prompt.unsaved": "Вы уверены, что хотите покинуть эту страницу? Все ваши модификации будут потеряны", - "global.save": "Сохранить", - "global.details": "Подробности", - "global.documentation": "Документация", - "global.back": "Назад", - "global.settings": "Настройки", - "global.roles": "Роли", - "global.users": "Пользователи", - "global.disabled": "Отключено", - "global.enabled": "Включено", - "global.reset-password": "Сброс пароля", - "global.plugins": "Плагины", - "global.profile": "Профиль", - "global.marketplace": "Площадка плагинов", - "global.content-manager": "Редактор контента", - "notification.contentType.relations.conflict": "Тип контента имеет конфликтующие отношения", - "notification.error": "Произошла ошибка", - "notification.error.layout": "Не удалось получить макет", - "notification.form.error.fields": "Форма содержит некоторые ошибки", - "notification.form.success.fields": "Изменения сохранены", - "notification.link-copied": "Ссылка скопирована в буфер обмена", - "notification.permission.not-allowed-read": "Вам не разрешено просматривать этот документ", - "notification.success.delete": "Элемент удален", - "notification.success.saved": "Сохранено", - "notification.version.update.message": "Доступна новая версия Strapi!", - "or": "ИЛИ", - "request.error.model.unknown": "Модель данных не существует" + "Analytics": "Аналитика", + "anErrorOccurred": "Упс! Что-то пошло не так. Пожалуйста, попробуйте еще раз.", + "Auth.components.Oops.text": "Ваш аккаунт был заморожен", + "Auth.components.Oops.text.admin": "Если это ошибка, пожалуйста, обратитесь к администратору.", + "Auth.form.button.forgot-password": "Отправить письмо", + "Auth.form.button.go-home": "ВЕРНУТЬСЯ НА ГЛАВНУЮ", + "Auth.form.button.login": "Войти", + "Auth.form.button.login.providers.error": "Мы не можем подключить вас через выбранного провайдера.", + "Auth.form.button.login.strapi": "ВОЙТИ ЧЕРЕЗ STRAPI", + "Auth.form.button.password-recovery": "Восстановление пароля", + "Auth.form.button.register": "Давайте начнем", + "Auth.form.confirmPassword.label": "Подтверждение пароля", + "Auth.form.currentPassword.label": "Нынешний пароль", + "Auth.form.email.label": "Email", + "Auth.form.email.placeholder": "kai@doe.com", + "Auth.form.error.blocked": "Ваш аккаунт был заблокирован администратором.", + "Auth.form.error.code.provide": "Указан неверный код.", + "Auth.form.error.confirmed": "Ваш e-mail не подтвержден.", + "Auth.form.error.email.invalid": "Неправильный e-mail.", + "Auth.form.error.email.provide": "Укажите свое имя пользователя или e-mail.", + "Auth.form.error.email.taken": "Данный e-mail уже используется", + "Auth.form.error.invalid": "Неверный логин или пароль.", + "Auth.form.error.params.provide": "Предоставлены неверные параметры.", + "Auth.form.error.password.format": "Пароль не может содержать символ `$` больше трех раз.", + "Auth.form.error.password.local": "Этот пользователь никогда не задавал пароль, пожалуйста, войдите в систему через провайдера, используемого при создании учетной записи.", + "Auth.form.error.password.matching": "Пароли не совпадают.", + "Auth.form.error.password.provide": "Укажите свой пароль.", + "Auth.form.error.ratelimit": "Слишком много попыток, повторите через минуту", + "Auth.form.error.user.not-exist": "Этот e-mail не существует.", + "Auth.form.error.username.taken": "Имя пользователя уже используется", + "Auth.form.firstname.label": "Имя", + "Auth.form.firstname.placeholder": "Иван", + "Auth.form.forgot-password.email.label": "Введите ваш e-mail", + "Auth.form.forgot-password.email.label.success": "Письмо успешно отправлено e-mail", + "Auth.form.lastname.label": "Фамилия", + "Auth.form.lastname.placeholder": "Иванов", + "Auth.form.password.hide-password": "Скрыть пароль", + "Auth.form.password.hint": "Должно быть не менее 8 символов, 1 прописной, 1 строчный и 1 цифра", + "Auth.form.password.show-password": "Показать пароль", + "Auth.form.register.news.label": "Держите меня в курсе о новых функциях и предстоящих улучшениях (делая это, вы принимаете {terms} и {policy}).", + "Auth.form.register.subtitle": "Учетные данные используются только для аутентификации в Strapi. Все сохраненные данные будут храниться в вашей базе данных.", + "Auth.form.rememberMe.label": "Запомнить меня", + "Auth.form.username.label": "Имя пользователя", + "Auth.form.username.placeholder": "Иван Иванов", + "Auth.form.welcome.subtitle": "Войдите в свою учетную запись Strapi", + "Auth.form.welcome.title": "Добро пожаловать в Strapi!", + "Auth.link.forgot-password": "Забыли пароль?", + "Auth.link.ready": "Готовы войти?", + "Auth.link.signin": "Войти", + "Auth.link.signin.account": "Уже есть аккаунт?", + "Auth.login.sso.divider": "Или войдите в систему с помощью", + "Auth.login.sso.loading": "Загрузка провайдеров...", + "Auth.login.sso.subtitle": "Войдите в свою учетную запись через SSO", + "Auth.privacy-policy-agreement.policy": "Политика конфиденциальности", + "Auth.privacy-policy-agreement.terms": "Условия", + "Auth.reset-password.title": "Сброс пароля", + "clearLabel": "Очистить", + "coming.soon": "Этот контент находится в стадии разработки и будет возвращен через несколько недель!", + "Auth.components.Oops.title": "Упс...", + "Auth.form.active.label": "Активно", + "Content Manager": "Редактор контента", + "Content Type Builder": "Типы контента", + "Documentation": "Документация", + "Email": "E-mail", + "Files Upload": "Загрузка файлов", + "HomePage.helmet.title": "Домашняя страница", + "HomePage.roadmap": "Смотрите нашу дорожную карту", + "HomePage.welcome.congrats": "Поздравляем!", + "HomePage.welcome.congrats.content": "Вы вошли как первый администратор. Чтобы открыть для себя мощные функции, предоставляемые Strapi,", + "HomePage.welcome.congrats.content.bold": "мы рекомендуем вам создать свою первую коллекцию.", + "Media Library": "Медиа-библиотека", + "New entry": "Новая запись", + "Password": "Пароль", + "Provider": "Провайдер", + "ResetPasswordToken": "Сброс токена пароля", + "Role": "Роль", + "Roles & Permissions": "Роли и разрешения", + "Roles.ListPage.notification.delete-all-not-allowed": "Некоторые роли нельзя было удалить, так как они связаны с пользователями.", + "Roles.ListPage.notification.delete-not-allowed": "Невозможно удалить роль, если она связана с пользователями", + "Roles.RoleRow.select-all": "Выберите {name} для групповых действий", + "Roles.RoleRow.user-count": "{number, plural, =0 {# пользователей} one {# пользователь} other {# пользователей}}", + "Settings.apiTokens.addFirstToken": "Добавьте свой первый API-токен", + "Settings.apiTokens.addNewToken": "Добавить новый API-токен", + "Settings.apiTokens.Button.cancel": "Отмена", + "Settings.apiTokens.Button.regenerate": "Восстановить", + "Roles.components.List.empty.withSearch": "Нет роли, соответствующей поиску ({search})...", + "Settings.PageTitle": "Настройки - {name}", + "Settings.apiTokens.copy.editMessage": + "Из соображений безопасности вы можете увидеть свой токен только один раз.", + "Settings.apiTokens.copy.editTitle": "Этот токен больше не доступен", + "Settings.apiTokens.copy.lastWarning": "Обязательно скопируйте этот токен, вы больше не сможете его увидеть!", + "Settings.apiTokens.create": "Создайте новый API-токен", + "Settings.apiTokens.createPage.permissions.description": "Ниже перечислены только действия, связанные с маршрутом.", + "Settings.apiTokens.createPage.permissions.title": "Разрешения", + "Settings.apiTokens.types.full-access": "Полный доступ", + "Settings.apiTokens.types.read-only": "Только для чтения", + "Settings.apiTokens.title": "API Токены", + "Settings.apiTokens.description": + "Список сгенерированных токенов для использования API", + "Settings.apiTokens.duration.30-days": "30 дней", + "Settings.apiTokens.duration.7-days": "7 дней", + "Settings.apiTokens.duration.90-days": "90 дней", + "Settings.apiTokens.duration.expiration-date": "Срок действия", + "Settings.apiTokens.duration.unlimited": "Неограниченный", + "Settings.apiTokens.emptyStateLayout": "У вас еще нет контента...", + "Settings.apiTokens.form.duration": "Срок действия токена", + "Settings.apiTokens.form.type": "Тип токена", + "Settings.apiTokens.ListView.headers.createdAt": "Создан", + "Settings.apiTokens.ListView.headers.description": "Описание", + "Settings.apiTokens.ListView.headers.lastUsedAt": "Последнее использование", + "Settings.apiTokens.ListView.headers.name": "Название", + "Settings.apiTokens.ListView.headers.type": "Тип токена", + "Settings.apiTokens.notification.copied": "Токен скопирован в буфер обмена.", + "Settings.apiTokens.popUpWarning.message": "Вы уверены, что хотите восстановить этот токен?", + "Settings.apiTokens.RegenerateDialog.title": "Восстановить токен", + "Settings.application.customization": "Персонализация", + "Settings.application.customization.carousel-hint": "Изменить логотип панели администратора (Максимальный размер: {dimension}x{dimension}, Максимальный размер файла: {size}KB)", + "Settings.application.customization.carousel-slide.label": "Слайд с логотипом", + "Settings.application.customization.carousel.change-action": "Изменить логотип", + "Settings.application.customization.carousel.reset-action": "Сброс логотипа", + "Settings.application.customization.carousel.title": "Логотип", + "Settings.application.customization.modal.cancel": "Отмена", + "Settings.application.customization.modal.pending": "Ожидание логотипа", + "Settings.application.customization.modal.pending.card-badge": "изображение", + "Settings.application.customization.modal.pending.choose-another": "Выберите другой логотип", + "Settings.application.customization.modal.pending.subtitle": "Управление выбранным логотипом перед его загрузкой", + "Settings.application.customization.modal.pending.title": "Логотип готов к загрузке", + "Settings.application.customization.modal.pending.upload": "Загрузить логотип", + "Settings.application.customization.modal.tab.label": "Как вы хотите загрузить свои ассеты?", + "Settings.application.customization.modal.upload": "Загрузить логотип", + "Settings.application.customization.modal.upload.cta.browse": "Просмотр файлов", + "Settings.application.customization.modal.upload.drag-drop": "Перетащите сюда или", + "Settings.application.customization.modal.upload.error-format": "Загружен неправильный формат (принимаются только форматы: jpeg, jpg, png, svg).", + "Settings.application.customization.modal.upload.error-network": "Ошибка сети", + "Settings.application.customization.modal.upload.error-size": "Загруженный файл слишком велик (максимальный размер: {dimension}x{dimension}, максимальный размер файла: {size}KB)", + "Settings.application.customization.modal.upload.file-validation": "Максимальный размер: {dimension}x{dimension}, Максимальный размер файла: {size}KB", + "Settings.application.customization.modal.upload.from-computer": "С компьютера", + "Settings.application.customization.modal.upload.from-url": "По ссылке", + "Settings.application.customization.modal.upload.from-url.input-label": "URL", + "Settings.application.customization.modal.upload.next": "Далее", + "Settings.application.description": "Смотреть детали вашего проекта", + "Settings.application.edition-title": "ТЕКУЩИЙ ПЛАН", + "Settings.application.get-help": "Получить помощь", + "Settings.application.link-pricing": "Смотреть все тарифы", + "Settings.application.link-upgrade": "Обновить ваше приложение", + "Settings.application.node-version": "ВЕРСИЯ NODE", + "Settings.application.strapi-version": "ВЕРСИЯ STRAPI", + "Settings.application.strapiVersion": "ВЕРСИЯ STRAPI", + "Settings.application.title": "Приложение", + "Settings.error": "Ошибка", + "Settings.global": "Глобальные настройки", + "Settings.permissions": "Панель администратора", + "Settings.permissions.category": "Настройки разрешений для {category}", + "Settings.permissions.category.plugins": "Настройки разрешений для плагина {category}", + "Settings.permissions.conditions.anytime": "Всегда", + "Settings.permissions.conditions.apply": "Применить", + "Settings.permissions.conditions.can": "Можно", + "Settings.permissions.conditions.define-conditions": "Определить условия", + "Settings.permissions.conditions.links": "Ссылки", + "Settings.permissions.conditions.no-actions": "Нет действия", + "Settings.permissions.conditions.none-selected": "Любое время", + "Settings.permissions.conditions.or": "ИЛИ", + "Settings.permissions.conditions.when": "Когда", + "Settings.permissions.select-all-by-permission": "", + "Settings.permissions.select-by-permission": "Выберите все разрешения {label}", + "Settings.permissions.users.active": "Активен", + "Settings.permissions.users.create": "Создать нового пользователя", + "Settings.permissions.users.email": "Email", + "Settings.permissions.users.firstname": "Имя", + "Settings.permissions.users.lastname": "Фамилия", + "Settings.permissions.users.listview.header.subtitle": "Все пользователи, имеющие доступ к панели администратора Strapi", + "Settings.permissions.users.roles": "Роли", + "Settings.permissions.users.strapi-author": "Автор", + "Settings.permissions.users.strapi-editor": "Редактор", + "Settings.permissions.users.strapi-super-admin": "Супер-администратор", + "Settings.permissions.users.tabs.label": "Вкладки Разрешения", + "Settings.permissions.users.user-status": "Статус пользователя", + "Settings.permissions.users.username": "Имя пользователя", + "Settings.profile.form.notify.data.loaded": "Данные вашего профиля загружены", + "Settings.profile.form.section.experience.clear.select": "Очистить выбранный язык интерфейса", + "Settings.profile.form.section.experience.here": "здесь", + "Settings.permissions.users.form.sso": "Соединить с SSO", + "Settings.permissions.users.form.sso.description": "Когда включено (ВКЛЮЧЕНО), пользователи смогут входить через SSO", + "Settings.permissions.users.inactive": "Неактивен", + "Settings.profile.form.section.experience.interfaceLanguage": "Язык интерфейса", + "Settings.profile.form.section.experience.interfaceLanguage.hint": "Только ваш интерфейс будет отображаться на выбранном языке.", + "Settings.profile.form.section.experience.interfaceLanguageHelp": "Изменения предпочтений будут касаться только вас. Дополнительная информация доступна {here}.", + "Settings.profile.form.section.experience.mode.hint": "Отображает ваш интерфейс в выбранной теме.", + "Settings.profile.form.section.experience.mode.label": "Тема интерфейса", + "Settings.profile.form.section.experience.mode.option-label": "{name} тема", + "Settings.profile.form.section.experience.title": "Опыт", + "Settings.profile.form.section.helmet.title": "Профиль пользователя", + "Settings.profile.form.section.profile.page.title": "Страница профиля", + "light": "Светлая", + "dark": "Тёмная", + "Settings.roles.create.description": "Определите права, предоставленные ролью", + "Settings.roles.create.title": "Создать роль", + "Settings.roles.created": "Роль создана", + "Settings.roles.edit.title": "Изменить роль", + "Settings.roles.form.button.users-with-role": "Пользователи с этой ролью", + "Settings.roles.form.created": "Создано", + "Settings.roles.form.description": "Название и описание роли", + "Settings.roles.form.permission.property-label": "{label} разрешения", + "Settings.roles.form.permissions.attributesPermissions": "Разрешения полей", + "Settings.roles.form.permissions.create": "Создать", + "Settings.roles.form.permissions.delete": "Удалить", + "Settings.roles.form.permissions.publish": "Опубликовать", + "Settings.roles.form.permissions.read": "Прочесть", + "Settings.roles.form.permissions.update": "Обновить", + "Settings.roles.list.button.add": "Добавить новую роль", + "Settings.roles.list.description": "Список ролей", + "Settings.roles.title.singular": "роль", + "Settings.sso.description": "Настройте параметры для функции единого входа.", + "Settings.sso.form.defaultRole.description": "Присоединит нового аутентифицированного пользователя к выбранной роли", + "Settings.sso.form.defaultRole.description-not-allowed": "У вас должно быть разрешение на чтение ролей администратора", + "Settings.sso.form.defaultRole.label": "Роль по умолчанию", + "Settings.sso.form.registration.description": "Создать нового пользователя при входе через SSO, если учетной записи нет", + "Settings.sso.form.registration.label": "Авто-регистрация", + "Settings.sso.title": "Функция единого входа", + "Settings.webhooks.create": "Создание webhook", + "Settings.webhooks.create.header": "Создание нового заголовка", + "Settings.webhooks.created": "Webhook создан", + "Settings.webhooks.event.publish-tooltip": "Это событие существует только для содержимого с включенной системой черновиков/публикаций.", + "Settings.webhooks.events.create": "Создание", + "Settings.webhooks.events.update": "Обновление", + "Settings.webhooks.form.events": "События", + "Settings.webhooks.form.headers": "Заголовки", + "Settings.webhooks.form.url": "Url", + "Settings.webhooks.headers.remove": "Удалить строку заголовка {number}", + "Settings.webhooks.key": "Ключ", + "Settings.webhooks.list.button.add": "Добавить новый webhook", + "Settings.webhooks.list.description": "Уведомления с помощью POST событий.", + "Settings.webhooks.list.empty.description": "Добавить первый в этот список.", + "Settings.webhooks.list.empty.link": "Просмотреть документацию", + "Settings.webhooks.list.empty.title": "Пока еще нет webhooks", + "Settings.webhooks.list.th.actions": "действия", + "Settings.webhooks.list.th.status": "статус", + "Settings.webhooks.singular": "webhook", + "Settings.webhooks.title": "Webhooks", + "Settings.webhooks.to.delete": "{webhooksToDeleteLength, plural, one {# ассет} other {# ассеты}} выбраны", + "Settings.webhooks.trigger": "Триггер", + "Settings.webhooks.trigger.cancel": "Отмена триггера", + "Settings.webhooks.trigger.pending": "Ожидание…", + "Settings.webhooks.trigger.save": "Пожалуйста сохраните триггер", + "Settings.webhooks.trigger.success": "Успех!", + "Settings.webhooks.trigger.success.label": "Триггер выполнен", + "Settings.webhooks.trigger.test": "Тест триггер", + "Settings.webhooks.trigger.title": "Сохранить перед триггером", + "Settings.webhooks.value": "Значение", + "skipToContent": "Перейти к содержимому", + "submit": "Отправить", + "Usecase.back-end": "Back-end разработчик", + "Usecase.button.skip": "Пропустить этот вопрос", + "Usecase.content-creator": "Создатель контента", + "Usecase.front-end": "Front-end разработчик", + "Usecase.full-stack": "Full-stack разработчик", + "Usecase.input.work-type": "Какой тип работы вы выполняете?", + "Usecase.notification.success.project-created": "Проект успешно создан", + "Usecase.other": "Другое", + "Usecase.title": "Расскажите нам немного больше о себе", + "Username": "Имя пользователя", + "Users": "Пользователи", + "Users & Permissions": "Пользователи и разрешения", + "Users.components.List.empty": "Нет пользователей...", + "Users.components.List.empty.withFilters": "Нет пользователей с примененными фильтрами...", + "Users.components.List.empty.withSearch": "Нет пользователей, соответствующих запросу ({search})...", + "app.component.CopyToClipboard.label": "Копировать в буфер обмена", + "app.component.search.label": "Искать {target}", + "app.component.table.duplicate": "Дубликат {target}", + "app.component.table.edit": "Редактировать {target}", + "app.component.table.select.one-entry": "Выбрать {target}", + "app.components.BlockLink.blog": "Блог", + "app.components.BlockLink.blog.content": "Читайте последние новости о Strapi и экосистеме.", + "app.components.BlockLink.code": "Примеры кода", + "app.components.BlockLink.code.content": "Учитесь, тестируя реальные проекты, разработанные сообществом.", + "app.components.BlockLink.documentation.content": "Откройте для себя основные понятия, руководства и инструкции.", + "app.components.BlockLink.tutorial": "Учебные материалы", + "app.components.BlockLink.tutorial.content": "Следуйте пошаговым инструкциям по использованию и настройке Strapi.", + "app.components.Button.cancel": "Отменить", + "app.components.Button.confirm": "Подтвердить", + "app.components.Button.reset": "Сброс", + "app.components.ComingSoonPage.comingSoon": "Скоро", + "app.components.ConfirmDialog.title": "Подтверждение", + "app.components.DownloadInfo.download": "Выполняется загрузка...", + "app.components.DownloadInfo.text": "Это может занять около минуты. Спасибо за ваше терпение.", + "app.components.EmptyStateLayout.content-document": "Данные не найдены", + "app.components.EmptyAttributes.title": "Пока нет полей", + "app.components.EmptyStateLayout.content-permissions": "У вас нет прав доступа к этому содержимому", + "app.components.GuidedTour.apiTokens.create.content": "

Сгенерируйте здесь токен аутентификации и получите только что созданный контент.

", + "app.components.GuidedTour.apiTokens.create.cta.title": "Сгенерируйте API-токен", + "app.components.GuidedTour.apiTokens.create.title": "🚀 Смотрите контент в действии", + "app.components.GuidedTour.apiTokens.success.content": "

Смотрите содержимое в действии, сделав HTTP-запрос:

  • По этому URL: https://'<'YOUR_DOMAIN'>'/api/'<'YOUR_CT'>'

  • С заголовком: Authorization: bearer '<'YOUR_API_TOKEN'>'

О других способах взаимодействия с содержимым взгляните на документацию.

", + "app.components.GuidedTour.apiTokens.success.cta.title": "Вернуться на главную страницу", + "app.components.GuidedTour.apiTokens.success.title": "Шаг 3: Завершено ✅", + "app.components.GuidedTour.CM.create.content": "

Создавайте и управляйте всем содержимым здесь, в Редакторе контента.

Например, если взять пример с сайтом-блогом, можно написать статью, сохранить и опубликовать ее по своему усмотрению.

💡 Quick tip - Don't forget to hit publish on the content you create.

", + "app.components.GuidedTour.CM.create.title": "⚡️ Создавайте контент", + "app.components.GuidedTour.CM.success.content": "

Потрясающе, остался последний шаг!

🚀 Смотрите контент в действии", + "app.components.GuidedTour.CM.success.cta.title": "Протестируйте API", + "app.components.GuidedTour.CM.success.title": "Шаг 2: Завершено ✅", + "app.components.GuidedTour.create-content": "Создавайте контент", + "app.components.GuidedTour.CTB.create.content": "

Типы Collection помогают управлять несколькими записями, типы Single подходят для управления только одной записью.

Например: Для сайта-блога статьи будут типом Collection, а домашняя страница - типом Single.

", + "app.components.GuidedTour.CTB.create.cta.title": "Постройте тип Collection", + "app.components.GuidedTour.CTB.create.title": "🧠 Создайте первый тип Collection", + "app.components.GuidedTour.CTB.success.content": "

Так держать!

⚡️ Чем бы вы хотели поделиться с миром?", + "app.components.GuidedTour.CTB.success.title": "Шаг 1: Завершено ✅", + "app.components.GuidedTour.home.apiTokens.cta.title": "Протестируйте API", + "app.components.GuidedTour.home.CM.title": "⚡️ Чем бы вы хотели поделиться с миром?", + "app.components.GuidedTour.home.CTB.cta.title": "Перейти к Content type Builder", + "app.components.GuidedTour.home.CTB.title": "🧠 Постройте структуру контента", + "app.components.GuidedTour.skip": "Пропустить тур", + "app.components.GuidedTour.title": "3 шага для начала работы", + "app.components.HomePage.button.blog": "СМОТРИТЕ БОЛЬШЕ В БЛОГЕ", + "app.components.HomePage.community": "Найдите сообщество в интернете", + "app.components.HomePage.community.content": "Обсуждайте с членами команды и разработчиками в разных каналах.", + "app.components.HomePage.create": "Создайте свой первый тип контента", + "app.components.HomePage.roadmap": "Ознакомьтесь с нашей дорожной картой", + "app.components.HomePage.welcome": "Добро пожаловать на борт!", + "app.components.HomePage.welcome.again": "Добро пожаловать ", + "app.components.HomePage.welcomeBlock.content": "Мы рады, что вы присоединились к сообществу. Нам необходима обратная связь для развития проекта, поэтому не стесняйтесь писать нам в ", + "app.components.HomePage.welcomeBlock.content.again": "Надеемся, что вы делаете успехи в вашем проекте... Следите за последними новостями Strapi. Мы стараемся изо всех сил, чтобы улучшить продукт, основываясь на ваших пожеланиях.", + "app.components.HomePage.welcomeBlock.content.issues": "проблемах.", + "app.components.HomePage.welcomeBlock.content.raise": " или сообщать о ", + "app.components.ImgPreview.hint": "Перетащите файл в эту область или {browse} файл для загрузки", + "app.components.ImgPreview.hint.browse": "выберите", + "app.components.InputFile.newFile": "Добавить новый файл", + "app.components.InputFileDetails.open": "Открыть в новой вкладке", + "app.components.InputFileDetails.originalName": "Оригинальное название:", + "app.components.InputFileDetails.remove": "Удалить этот файл", + "app.components.InputFileDetails.size": "Размер:", + "app.components.InstallPluginPage.Download.description": "Для загрузки и установки плагина может потребоваться несколько секунд.", + "app.components.InstallPluginPage.Download.title": "Загрузка...", + "app.components.InstallPluginPage.description": "Расширяйте ваше приложение без особых усилий.", + "app.components.LeftMenu.collapse": "Свернуть панель навигации", + "app.components.LeftMenu.expand": "Развернуть панель навигации", + "app.components.LeftMenu.general": "Общее", + "app.components.LeftMenu.logo.alt": "Логотип приложения", + "app.components.LeftMenu.logout": "Выйти", + "app.components.LeftMenu.plugins": "Плагины", + "app.components.LeftMenu.navbrand.title": "Strapi Панель", + "app.components.LeftMenu.navbrand.workplace": "Рабочая область", + "app.components.LeftMenuFooter.help": "Помощь", + "app.components.LeftMenuFooter.poweredBy": "Работает на ", + "app.components.LeftMenuLinkContainer.collectionTypes": "Типы коллекций", + "app.components.LeftMenuLinkContainer.configuration": "Настройки", + "app.components.LeftMenuLinkContainer.general": "Общие", + "app.components.LeftMenuLinkContainer.noPluginsInstalled": "Нет установленных плагинов", + "app.components.LeftMenuLinkContainer.plugins": "Плагины", + "app.components.LeftMenuLinkContainer.singleTypes": "Страницы", + "app.components.ListPluginsPage.deletePlugin.description": "Удаление плагина может занять несколько секунд.", + "app.components.ListPluginsPage.deletePlugin.title": "Удаление", + "app.components.ListPluginsPage.description": "Список установленных плагинов в проекте.", + "app.components.ListPluginsPage.helmet.title": "Список плагинов", + "app.components.Logout.logout": "Выйти", + "app.components.Logout.profile": "Профиль", + "app.components.MarketplaceBanner": "На Strapi Awesome вы найдете плагины, созданные сообществом, и множество других удивительных вещей для запуска вашего проекта.", + "app.components.MarketplaceBanner.image.alt": "a strapi rocket logo", + "app.components.MarketplaceBanner.link": "Проверьте это сейчас", + "app.components.NotFoundPage.back": "Вернуться на главную", + "app.components.NotFoundPage.description": "Не найдено", + "app.components.Official": "Официальный", + "app.components.Onboarding.help.button": "Кнопка Помощь", + "app.components.Onboarding.label.completed": "% завершено", + "app.components.Onboarding.title": "Смотреть вводные видео", + "app.components.PluginCard.Button.label.download": "Скачать", + "app.components.PluginCard.Button.label.install": "Уже установлено", + "app.components.PluginCard.PopUpWarning.install.impossible.autoReload.needed": "Функция autoReload (автоматической перезагрузки) должна быть включена. Пожалуйста, запустите ваше приложение с помощью `yarn develop`.", + "app.components.PluginCard.PopUpWarning.install.impossible.confirm": "Я понимаю!", + "app.components.PluginCard.PopUpWarning.install.impossible.environment": "В целях безопасности плагин может быть загружен только в среде разработки.", + "app.components.PluginCard.PopUpWarning.install.impossible.title": "Загрузка невозможна", + "app.components.PluginCard.compatible": "Совместимо с вашим приложением", + "app.components.PluginCard.compatibleCommunity": "Совместимо с сообществом", + "app.components.PluginCard.more-details": "Больше деталей", + "app.components.ToggleCheckbox.off-label": "Нет", + "app.components.ToggleCheckbox.on-label": "Да", + "app.components.UpgradePlanModal.button": "УЗНАТЬ БОЛЬШЕ", + "app.components.UpgradePlanModal.limit-reached": "Вы достигли предела", + "app.components.UpgradePlanModal.text-ce": "Community Edition", + "app.components.UpgradePlanModal.text-ee": "Enterprise Edition", + "app.components.UpgradePlanModal.text-power": "Разблокируйте всю мощь", + "app.components.UpgradePlanModal.text-strapi": "Strapi, обновив свой план до", + "app.components.Users.MagicLink.connect": "Отправьте эту ссылку пользователю, чтобы он подключился.", + "app.components.Users.MagicLink.connect.sso": "Отправьте эту ссылку пользователю, первый вход может быть осуществлен через провайдера SSO", + "app.components.Users.ModalCreateBody.block-title.details": "Детали", + "app.components.Users.ModalCreateBody.block-title.roles": "Роли пользователя", + "app.components.Users.ModalCreateBody.block-title.roles.description": "Пользователь может иметь одну или несколько ролей", + "app.components.Users.SortPicker.button-label": "Сортировать по", + "app.components.Users.SortPicker.sortby.email_asc": "Электронная почта (от А до Я)", + "app.components.Users.SortPicker.sortby.email_desc": "Электронная почта (от Я до А)", + "app.components.Users.SortPicker.sortby.firstname_asc": "Имя (от А до Я)", + "app.components.Users.SortPicker.sortby.firstname_desc": "Имя (от Я до А)", + "app.components.Users.SortPicker.sortby.lastname_asc": "Фамилия (от А до Я)", + "app.components.Users.SortPicker.sortby.lastname_desc": "Фамилия (от Я до А)", + "app.components.Users.SortPicker.sortby.username_asc": "Имя пользователя (от А до Я)", + "app.components.Users.SortPicker.sortby.username_desc": "Имя пользователя (от Я до А)", + "app.components.listPlugins.button": "Добавить новый плагин", + "app.components.listPlugins.title.none": "Нет установленных плагинов", + "app.components.listPluginsPage.deletePlugin.error": "Произошла ошибка при удалении плагина", + "app.containers.App.notification.error.init": "Произошла ошибка при запросе к API", + "app.containers.AuthPage.ForgotPasswordSuccess.text.contact-admin": "Если вы не получили эту ссылку, обратитесь к администратору.", + "app.containers.AuthPage.ForgotPasswordSuccess.text.email": "Получение ссылки для восстановления пароля может занять несколько минут..", + "app.containers.AuthPage.ForgotPasswordSuccess.title": "Письмо отправлено", + "app.containers.Users.EditPage.form.active.label": "Активный", + "app.containers.Users.EditPage.header.label": "Редактировать {name}", + "app.containers.Users.EditPage.header.label-loading": "Редактировать user", + "app.containers.Users.EditPage.roles-bloc-title": "Атрибуты ролей", + "app.containers.Users.ModalForm.footer.button-success": "Создать пользователя", + "app.links.configure-view": "Настройка представления", + "app.page.not.found": "Упс! Мы не можем найти страницу, которую вы ищете...", + "app.static.links.cheatsheet": "Шпаргалка", + "app.utils.SelectOption.defaultMessage": " ", + "app.utils.add-filter": "Добавить фильтр", + "app.utils.close-label": "Закрыть", + "app.utils.defaultMessage": " ", + "app.utils.delete": "Удалить", + "app.utils.duplicate": "Дубликат", + "app.utils.edit": "Редактировать", + "app.utils.errors.file-too-big.message": "Файл слишком большой", + "app.utils.filter-value": "Значение фильтра", + "app.utils.filters": "Фильтры", + "app.utils.notify.data-loaded": "{target} загружена", + "app.utils.placeholder.defaultMessage": " ", + "app.utils.publish": "Опубликовать", + "app.utils.select-all": "Выбрать все", + "app.utils.select-field": "Выберите поле", + "app.utils.select-filter": "Выберите фильтр", + "app.utils.unpublish": "Отменить публикацию", + "admin.pages.MarketPlacePage.helmet": "Площадка плагинов - Плагины", + "admin.pages.MarketPlacePage.missingPlugin.description": "Расскажите нам, какой плагин вы ищете, и мы сообщим об этом разработчикам плагинов нашего сообщества на случай, если они ищут вдохновение!", + "admin.pages.MarketPlacePage.missingPlugin.title": "Вам не хватает плагина?", + "admin.pages.MarketPlacePage.offline.subtitle": "Для доступа к Strapi Market необходимо подключение к Интернету.", + "admin.pages.MarketPlacePage.offline.title": "Вы не в сети", + "admin.pages.MarketPlacePage.plugin.copy": "Скопируйте команду установки", + "admin.pages.MarketPlacePage.plugin.copy.success": "Команда установки готова к вставке в терминал", + "admin.pages.MarketPlacePage.plugin.info": "Узнать больше", + "admin.pages.MarketPlacePage.plugin.info.label": "Узнать больше про {pluginName}", + "admin.pages.MarketPlacePage.plugin.info.text": "Узнать больше", + "admin.pages.MarketPlacePage.plugin.installed": "Установлено", + "admin.pages.MarketPlacePage.plugin.tooltip.madeByStrapi": "Сделано Strapi", + "admin.pages.MarketPlacePage.plugin.tooltip.verified": "Плагин проверен Strapi", + "admin.pages.MarketPlacePage.plugin.version": "Обновите версию Strapi: \"{strapiAppVersion}\" до: \"{versionRange}\"", + "admin.pages.MarketPlacePage.plugin.version.null": "Невозможно проверить совместимость с вашей версией Strapi: \"{strapiAppVersion}\"", + "admin.pages.MarketPlacePage.plugins": "Плагины", + "admin.pages.MarketPlacePage.providers": "Провайдеры", + "admin.pages.MarketPlacePage.search.clear": "Очистить поиск", + "admin.pages.MarketPlacePage.search.empty": "Нет результатов для \"{target}\"", + "admin.pages.MarketPlacePage.subtitle": "Получите больше от Strapi", + "admin.pages.MarketPlacePage.search.placeholder": "Найти плагин", + "admin.pages.MarketPlacePage.submit.plugin.link": "Отправить плагин", + "admin.pages.MarketPlacePage.submit.provider.link": "Отправить провайдера", + "admin.pages.MarketPlacePage.tab-group.label": "Плагины и провайдеры для Strapi", + "component.Input.error.validation.integer": "Значение должно быть целочисленным", + "components.AutoReloadBlocker.description": "Запустите Strapi с помощью одной из следующих команд:", + "components.AutoReloadBlocker.header": "Функционал перезапуска необходим для этого плагина.", + "components.ErrorBoundary.title": "Что-то пошло не так...", + "components.FilterOptions.FILTER_TYPES.$contains": "содержит (с учетом регистра)", + "components.FilterOptions.FILTER_TYPES.$endsWith": "заканчивается на", + "components.FilterOptions.FILTER_TYPES.$eq": "равно", + "components.FilterOptions.FILTER_TYPES.$gt": "больше, чем", + "components.FilterOptions.FILTER_TYPES.$gte": "больше или равно", + "components.FilterOptions.FILTER_TYPES.$lt": "меньше, чем", + "components.FilterOptions.FILTER_TYPES.$lte": "меньше или равно", + "components.FilterOptions.FILTER_TYPES.$ne": "не", + "components.FilterOptions.FILTER_TYPES.$notContains": "не содержит (с учетом регистра)", + "components.FilterOptions.FILTER_TYPES.$notNull": "не равно null", + "components.FilterOptions.FILTER_TYPES.$null": "равно null", + "components.FilterOptions.FILTER_TYPES.$startsWith": "начинается с", + "components.Input.error.attribute.key.taken": "Это значение уже существует", + "components.Input.error.attribute.sameKeyAndName": "Не может быть одинаковым", + "components.Input.error.attribute.taken": "Поле с таким названием уже существует", + "components.Input.error.contain.lowercase": "Пароль должен содержать хотя бы один символ нижнего регистра.", + "components.Input.error.contain.number": "пароль должен содержать как минимум одну цифру", + "components.Input.error.contain.uppercase": "Пароль должен содержать хотя бы один символ верхнего регистра.", + "components.Input.error.contentTypeName.taken": "Это название уже существует", + "components.Input.error.custom-error": "{errorMessage} ", + "components.Input.error.password.noMatch": "Пароль не совпадает", + "components.Input.error.validation.email": "Это не адрес электронной почты", + "components.Input.error.validation.json": "Не соответствует JSON формату", + "components.Input.error.validation.lowercase": "Значение должно быть строкой в нижнем регистре", + "components.Input.error.validation.max": "Значение слишком большое.", + "components.Input.error.validation.maxLength": "Значение слишком длинное.", + "components.Input.error.validation.min": "Значение слишком маленькое.", + "components.Input.error.validation.minLength": "Значение слишком короткое.", + "components.Input.error.validation.minSupMax": "Не может быть больше", + "components.Input.error.validation.regex": "Значение не соответствует регулярному выражению.", + "components.Input.error.validation.required": "Обязательное значение.", + "components.Input.error.validation.unique": "Это значение уже используется.", + "components.InputSelect.option.placeholder": "Выберите здесь", + "components.ListRow.empty": "Нет данных для отображения.", + "components.NotAllowedInput.text": "Нет прав на просмотр этого поля", + "components.OverlayBlocker.description": "Вы воспользовались функционалом, который требует перезапуска сервера. Пожалуйста, подождите, пока сервер не будет запущен.", + "components.OverlayBlocker.description.serverError": "Сервер должен был перезагрузиться, пожалуйста, проверьте ваши логи в терминале.", + "components.OverlayBlocker.title": "Ожидание перезапуска...", + "components.OverlayBlocker.title.serverError": "Перезапуск занимает больше времени, чем ожидалось", + "components.PageFooter.select": "записей на странице", + "components.pagination.go-to": "Перейти на страницу {page}", + "components.pagination.go-to-next": "Перейти на следующую страницу", + "components.pagination.go-to-previous": "Перейти на предыдущую страницу", + "components.pagination.remaining-links": "И {number} других ссылок", + "components.ProductionBlocker.description": "В целях безопасности мы должны отключить этот плагин в других средах.", + "components.ProductionBlocker.header": "Этот плагин доступен только на стадии разработки.", + "components.Search.placeholder": "Поиск...", + "components.TableHeader.sort": "Сортировать по {label}", + "components.Wysiwyg.collapse": "Свернуть", + "components.Wysiwyg.selectOptions.H1": "Заголовок H1", + "components.Wysiwyg.selectOptions.H2": "Заголовок H2", + "components.Wysiwyg.selectOptions.H3": "Заголовок H3", + "components.Wysiwyg.selectOptions.H4": "Заголовок H4", + "components.Wysiwyg.selectOptions.H5": "Заголовок H5", + "components.Wysiwyg.selectOptions.H6": "Заголовок H6", + "components.Wysiwyg.selectOptions.title": "Добавить заголовок", + "components.Wysiwyg.ToggleMode.markdown-mode": "Режим разметки", + "components.Wysiwyg.ToggleMode.preview-mode": "Режим предпросмотра", + "components.WysiwygBottomControls.charactersIndicators": "символов", + "components.WysiwygBottomControls.fullscreen": "Развернуть", + "components.WysiwygBottomControls.uploadFiles": "Перетащите файлы в эту область, вставьте из буфера обмена или {browse}.", + "components.WysiwygBottomControls.uploadFiles.browse": "выберите их", + "components.popUpWarning.button.cancel": "Нет, отменить", + "components.popUpWarning.button.confirm": "Да подтверждаю", + "components.popUpWarning.message": "Вы уверены, что хотите удалить это?", + "components.popUpWarning.title": "Пожалуйста, подтвердите", + "content-manager.EditRelations.title": "Связанные данные", + "content-manager.api.id": "API ID", + "content-manager.apiError.This attribute must be unique": "{field} должно быть уникальным", + "content-manager.App.schemas.data-loaded": "Схемы были успешно загружены", + "content-manager.components.AddFilterCTA.add": "Фильтры", + "content-manager.components.AddFilterCTA.hide": "Фильтры", + "content-manager.components.DraggableAttr.edit": "Нажмите чтобы редактировать", + "content-manager.components.DraggableCard.delete.field": "Удалить {item}", + "content-manager.components.DraggableCard.edit.field": "Редактировать {item}", + "content-manager.components.DraggableCard.move.field": "Переместить {item}", + "content-manager.components.DragHandle-label": "Перетащить", + "content-manager.components.DynamicTable.row-line": "строка {number}", + "content-manager.components.DynamicZone.add-component": "Добавить компонент в {componentName}", + "content-manager.components.DynamicZone.ComponentPicker-label": "Выберите один компонент", + "content-manager.components.DynamicZone.delete-label": "Удалить {name}", + "content-manager.components.DynamicZone.error-message": "Компонент содержит ошибку(-и)", + "content-manager.components.DynamicZone.missing-components": "{number, plural, =0 { # отсутствующих компонентов} one {is # отсутствующий компонент} other {are # отсутствующих компонентов}}", + "content-manager.components.DynamicZone.move-down-label": "Переместить компонент вниз", + "content-manager.components.DynamicZone.move-up-label": "Переместить компонент вверх", + "content-manager.components.DynamicZone.pick-compo": "Выберите компонент", + "content-manager.components.DynamicZone.required": "Обязательный компонент", + "content-manager.components.EmptyAttributesBlock.button": "Перейти в настройки", + "content-manager.components.EmptyAttributesBlock.description": "Вы можете изменить текущие настройки", + "content-manager.components.FieldItem.linkToComponentLayout": "Установить компоновку компонентов", + "content-manager.components.FieldSelect.label": "Добавить поле", + "content-manager.components.FilterOptions.button.apply": "Применить", + "content-manager.components.FiltersPickWrapper.PluginHeader.actions.apply": "Применить", + "content-manager.components.FiltersPickWrapper.PluginHeader.actions.clearAll": "Очистить все", + "content-manager.components.FiltersPickWrapper.PluginHeader.description": "Укажите условия для фильтрации записей", + "content-manager.components.FiltersPickWrapper.PluginHeader.title.filter": "Фильтры", + "content-manager.components.FiltersPickWrapper.hide": "Скрыть", + "content-manager.components.LeftMenu.single-types": "Одиночные типы", + "content-manager.components.LeftMenu.collection-types": + "Типы коллекций", + "content-manager.components.LeftMenu.Search.label": "Поиск по типу содержимого", + "content-manager.components.LimitSelect.itemsPerPage": "Элементов на странице", + "content-manager.components.NotAllowedInput.text": "Нет разрешений на просмотр этого поля", + "content-manager.components.Search.placeholder": "Поиск записей...", + "content-manager.components.Select.draft-info-title": "Состояние: Черновик", + "content-manager.components.Select.publish-info-title": "Состояние: Опубликовано", + "content-manager.components.SettingsViewWrapper.pluginHeader.description.edit-settings": "Настройте, как будет выглядеть вид редактирования.", + "content-manager.components.SettingsViewWrapper.pluginHeader.description.list-settings": "Определите параметры представления списка.", + "content-manager.components.SettingsViewWrapper.pluginHeader.title": "Настройка представления - {name}", + "content-manager.components.TableDelete.delete": "Удалить все", + "content-manager.components.TableDelete.deleteSelected": "Удалить выбранное", + "content-manager.components.TableDelete.label": "{number, plural, one {# entry} other {# entries}} выбрано", + "content-manager.components.TableEmpty.withFilters": "Нет {contentType} с примененными фильтрами...", + "content-manager.components.TableEmpty.withSearch": "Нет {contentType} согласно поиску ({search})", + "content-manager.components.TableEmpty.withoutFilter": "Нет {contentType}...", + "content-manager.components.empty-repeatable": "Еще нет записей. Нажмите кнопку ниже, чтобы добавить одну.", + "content-manager.components.notification.info.maximum-requirement": "Вы уже достигли максимального количества полей", + "content-manager.components.notification.info.minimum-requirement": "Добавлено поле, соответствующее минимальным требованиям", + "content-manager.components.repeatable.reorder.error": "Произошла ошибка при изменении порядка полей вашего компонента. Попробуйте еще раз.", + "content-manager.components.RepeatableComponent.error-message": "Компонент(-ы) содержит(-ат) ошибку(-и)", + "content-manager.components.reset-entry": "Сбросить запись", + "content-manager.components.uid.apply": "Применить", + "content-manager.components.uid.available": "Доступный", + "content-manager.components.uid.regenerate": "Восстановить", + "content-manager.components.uid.suggested": "Предложенный", + "content-manager.components.uid.unavailable": "Недоступный", + "content-manager.containers.Edit.Link.Layout": "Настройка макета", + "content-manager.containers.Edit.Link.Model": "Измените тип коллекции", + "content-manager.containers.Edit.addAnItem": "Добавить элемент", + "content-manager.containers.Edit.clickToJump": "Нажмите для перехода к записи", + "content-manager.containers.Edit.delete": "Удалить", + "content-manager.containers.Edit.delete-entry": "Удалить эту запись", + "content-manager.containers.Edit.editing": "Редактирование...", + "content-manager.containers.Edit.information": "Информация", + "content-manager.containers.Edit.information.by": "по", + "content-manager.containers.Edit.information.created": "Создано", + "content-manager.containers.Edit.information.draftVersion": "Черновая версия", + "content-manager.containers.Edit.information.editing": "Редактирование", + "content-manager.containers.Edit.information.lastUpdate": "Последнее обновление", + "content-manager.containers.Edit.information.publishedVersion": "Опубликованная версия", + "content-manager.containers.Edit.pluginHeader.title.new": "Создать запись", + "content-manager.containers.Edit.reset": "Сбросить", + "content-manager.containers.Edit.returnList": "Вернуться к списку", + "content-manager.containers.Edit.seeDetails": "Подробнее", + "content-manager.containers.Edit.submit": "Сохранить", + "content-manager.containers.EditSettingsView.modal-form.edit-field": "Отредактируйте это поле", + "content-manager.containers.EditView.add.new-entry": "Добавить запись", + "content-manager.containers.EditView.notification.errors": "Форма содержит некоторые ошибки", + "content-manager.containers.Home.introduction": "Для того чтобы отредактировать ваши записи используйте соответствующую ссылку в меню слева. У плагина отсутствует полноценная возможность редактировать настройки и он все еще находится в стадии активной разработки.", + "content-manager.containers.Home.pluginHeaderDescription": "Управляйте своими записями с помощью мощного и красивого интерфейса.", + "content-manager.containers.Home.pluginHeaderTitle": "Редактор контента", + "content-manager.containers.List.draft": "Черновик", + "content-manager.containers.List.errorFetchRecords": "Ошибка", + "content-manager.containers.List.published": "Опубликован", + "content-manager.containers.ListPage.displayedFields": "Отображаемые поля", + "content-manager.containers.ListPage.items": "{number, plural, =0 {элементов} one {элемент} other {элементов}}", + "content-manager.containers.ListPage.table-headers.publishedAt": "Состояние", + "content-manager.containers.ListSettingsView.modal-form.edit-label": "Отредактируйте ярлык", + "content-manager.containers.SettingPage.add.field": "Добавить еще одно поле", + "content-manager.containers.SettingPage.add.relational-field": "Добавить еще одно связанное поле", + "content-manager.containers.SettingPage.attributes": "Поля атрибутов", + "content-manager.containers.SettingPage.attributes.description": "Определить порядок атрибутов", + "content-manager.containers.SettingPage.editSettings.description": "Перетащите поля, чтобы определить макет", + "content-manager.containers.SettingPage.editSettings.entry.title": "Заголовок записи", + "content-manager.containers.SettingPage.editSettings.entry.title.description": "Установите отображаемое поле вашей записи", + "content-manager.containers.SettingPage.editSettings.relation-field.description": "Установите поле, которое будет отображаться как в режиме редактирования, так и в списке.", + "content-manager.containers.SettingPage.editSettings.title": "Редактирование — Настройки", + "content-manager.containers.SettingPage.layout": "Макет", + "content-manager.containers.SettingPage.listSettings.description": "Настройте параметры для этого типа коллекции", + "content-manager.containers.SettingPage.listSettings.title": "Просмотр списка (настройки)", + "content-manager.containers.SettingPage.pluginHeaderDescription": "Настройте конкретные параметры для этого типа коллекции", + "content-manager.containers.SettingPage.relations": "Связанные поля", + "content-manager.containers.SettingPage.settings": "Настройки", + "content-manager.containers.SettingPage.view": "Вид", + "content-manager.containers.SettingViewModel.pluginHeader.title": "Контент менеджер - {name}", + "content-manager.DynamicTable.relation-loaded": "Отношения были загружены", + "content-manager.DynamicTable.relation-loading": "Отношения загружаются", + "content-manager.DynamicTable.relation-more": "Это отношение содержит больше сущностей, чем отображается", + "content-manager.edit-settings-view.link-to-ctb.components": "Редактировать компонент", + "content-manager.edit-settings-view.link-to-ctb.content-types": "Редактирование типа содержимого", + "content-manager.containers.SettingsPage.Block.contentType.description": "Настроить отдельные параметры", + "content-manager.containers.SettingsPage.Block.contentType.title": "Типы коллекций", + "content-manager.containers.SettingsPage.Block.generalSettings.description": "Настройте параметры по умолчанию для ваших типов коллекций", + "content-manager.containers.SettingsPage.Block.generalSettings.title": "Общее", + "content-manager.containers.SettingsPage.pluginHeaderDescription": "Настройте параметры для всех ваших типов коллекций и групп.", + "content-manager.containers.SettingsView.list.subtitle": "Настройте макет и отображение ваших типов и групп Коллекции", + "content-manager.containers.SettingsView.list.title": "Конфигурация отображения", + "content-manager.emptyAttributes.button": "Перейдите в конструктор типов коллекций", + "content-manager.emptyAttributes.description": "Добавьте свое первое поле в тип коллекции", + "content-manager.emptyAttributes.title": "Пока нет полей", + "content-manager.error.attribute.key.taken": "Это значение уже существует", + "content-manager.error.attribute.sameKeyAndName": "Не может быть одинаковым", + "content-manager.error.attribute.taken": "Поле с таким названием уже существует", + "content-manager.error.contentTypeName.taken": "Это название уже существует", + "content-manager.error.model.fetch": "Произошла ошибка во время настройки конфигурации модели.", + "content-manager.error.record.create": "Произошла ошибка при создании записи.", + "content-manager.error.record.delete": "Произошла ошибка при удалении записи.", + "content-manager.error.record.fetch": "Произошла ошибка при извлечении записи.", + "content-manager.error.record.update": "Произошла ошибка при обновлении записи.", + "content-manager.error.records.count": "Произошла ошибка при подсчете количества записей.", + "content-manager.error.records.fetch": "Произошла ошибка при извлечении записей.", + "content-manager.error.schema.generation": "Возникла ошибка во время генерации структуры.", + "content-manager.error.validation.json": "Это не JSON", + "content-manager.error.validation.max": "Слишком большое.", + "content-manager.error.validation.maxLength": "Слишком длинное.", + "content-manager.error.validation.min": "Слишком маленькое.", + "content-manager.error.validation.minLength": "Слишком короткое.", + "content-manager.error.validation.minSupMax": "Не может быть выше", + "content-manager.error.validation.regex": "Значение не соответствует регулярному выражению.", + "content-manager.error.validation.required": "Обязательное значение.", + "content-manager.form.Input.bulkActions": "Включить массовые действия", + "content-manager.form.Input.defaultSort": "Сортировка по умолчанию", + "content-manager.form.Input.description": "Описание", + "content-manager.form.Input.description.placeholder": "Имя, отображаемое в профиле", + "content-manager.form.Input.editable": "Редактируемое поле", + "content-manager.form.Input.filters": "Включить фильтры", + "content-manager.form.Input.label": "Подпись", + "content-manager.form.Input.label.inputDescription": "Это значение переопределяет название, отображаемое в заголовке таблицы", + "content-manager.form.Input.pageEntries": "Записей на странице", + "content-manager.form.Input.pageEntries.inputDescription": "Примечание. Вы можете переопределить это значение на странице настроек типа коллекции.", + "content-manager.form.Input.placeholder": "Плейсхолдер", + "content-manager.form.Input.placeholder.placeholder": "Мое значение", + "content-manager.form.Input.search": "Включить поиск", + "content-manager.form.Input.search.field": "Включить поиск по этому полю", + "content-manager.form.Input.sort.field": "Включить сортировку по этому полю", + "content-manager.form.Input.sort.order": "Сортировка по умолчанию", + "content-manager.form.Input.wysiwyg": "Отображение в виде WYSIWYG", + "content-manager.global.displayedFields": "Отображение полей", + "content-manager.groups": "Группы", + "content-manager.groups.numbered": "Группы ({number})", + "content-manager.header.name": "Контент", + "content-manager.HeaderLayout.button.label-add-entry": + "Создать новую запись", + "content-manager.link-to-ctb": "Редактировать модель", + "content-manager.models": "Типы коллекции", + "content-manager.models.numbered": "Типы коллекции ({number})", + "content-manager.notification.error.displayedFields": "Необходимо добавить хотя бы одно поле", + "content-manager.notification.error.relationship.fetch": "Возникла ошибка при получении связей.", + "content-manager.notification.info.SettingPage.disableSort": "У вас должен быть один атрибут с разрешенной сортировкой", + "content-manager.notification.info.minimumFields": "Вам нужно иметь хотя бы одно отображаемое поле", + "content-manager.notification.upload.error": "Произошла ошибка при загрузке ваших файлов", + "content-manager.pageNotFound": "Страница не найдена", + "content-manager.pages.ListView.header-subtitle": "{number, plural, =0 {# объектов} one {# объект} other {# объектов}} найдено", + "content-manager.pages.NoContentType.button": "Создайте свой первый Content-Type", + "content-manager.pages.NoContentType.text": "У вас еще нет никакого контента, мы рекомендуем вам создать свой первый Content-Type.", + "content-manager.permissions.not-allowed.create": "У вас нет прав на создание документов", + "content-manager.permissions.not-allowed.update": "У вас нет прав на просмотр этого документа", + "content-manager.plugin.description.long": "Быстрый способ увидеть, отредактировать и удалить данные в вашей базе данных.", + "content-manager.plugin.description.short": "Быстрый способ увидеть, отредактировать и удалить данные в вашей базе данных.", + "content-manager.popover.display-relations.label": "Показать отношения", + "content-manager.popUpWarning.bodyMessage.contentType.delete": "Вы уверены, что хотите удалить эту запись?", + "content-manager.popUpWarning.bodyMessage.contentType.delete.all": "Вы уверенны, что хотите удалить эти записи?", + "content-manager.popUpWarning.warning.cancelAllSettings": "Вы уверенны, что хотите отменить ваши изменения?", + "content-manager.popUpWarning.warning.publish-question": "Вы уверены, что хотите опубликовать запись?", + "content-manager.popUpWarning.warning.unpublish": "Если вы не опубликуете этот контент, он автоматически превратится в черновик.", + "content-manager.popUpWarning.warning.unpublish-question": "Вы уверены, что хотите ее не публиковать?", + "content-manager.popUpWarning.warning.updateAllSettings": "Это изменит все ваши настройки", + "content-manager.popUpwarning.warning.has-draft-relations.button-confirm": "Да, публиковать", + "content-manager.popUpwarning.warning.has-draft-relations.message": "{count, plural, =0 { of your content relations is} one { of your content relations is} other { of your content relations are}} еще не опубликованы.

Это может привести к появлению неработающих ссылок и ошибок в вашем проекте.", + "content-manager.select.currently.selected": "{count} выбрано", + "content-manager.success.record.delete": "Удалено", + "content-manager.success.record.publish": "Опубликовано", + "content-manager.success.record.save": "Сохранено", + "content-manager.success.record.unpublish": "Не опубликовано", + "content-manager.utils.data-loaded": "{number, plural, =1 {запись} other {записи}} успешно загружено", + "form.button.done": "Выполнено", + "form.button.continue": "Продолжить", + "global.actions": "Действия", + "global.prompt.unsaved": "Вы уверены, что хотите покинуть эту страницу? Все ваши модификации будут потеряны", + "global.save": "Сохранить", + "global.search": "Поиск", + "global.see-more": "Подробнее", + "global.select": "Выбрать", + "global.select-all-entries": "Выбрать все записи", + "global.details": "Подробности", + "global.documentation": "Документация", + "global.back": "Назад", + "global.cancel": "Отмена", + "global.continue": "Продолжить", + "global.delete": "Удалить", + "global.delete-target": "Удалить {target}", + "global.description": "Описание", + "global.change-password": "Сменить пароль", + "global.settings": "Настройки", + "global.type": "Тип", + "global.roles": "Роли", + "global.users": "Пользователи", + "global.disabled": "Отключено", + "global.enabled": "Включено", + "global.finish": "Готово", + "global.reset-password": "Сброс пароля", + "global.plugins": "Плагины", + "global.plugins.content-manager": "Редактор контента", + "global.plugins.content-manager.description": "Быстрый способ просмотра, редактирования и удаления данных в вашей базе данных.", + "global.plugins.content-type-builder": "Конструктор типов содержимого", + "global.plugins.content-type-builder.description": "Моделируйте структуру данных вашего API. Создавайте новые поля и отношения всего за минуту. Файлы автоматически создаются и обновляются в вашем проекте.", + "global.plugins.documentation": "Документация", + "global.plugins.documentation.description": "Создайте документ OpenAPI и визуализируйте свой API с помощью пользовательского интерфейса SWAGGER.", + "global.plugins.email": "Email", + "global.plugins.email.description": "Настройте свое приложение для отправки электронной почты.", + "global.plugins.graphql": "GraphQL", + "global.plugins.graphql.description": "Добавить конечную точку GraphQL с методами API по умолчанию.", + "global.plugins.i18n": "Интернационализация", + "global.plugins.i18n.description": "Этот плагин позволяет создавать, читать и обновлять контент на разных языках, как из панели администратора, так и с помощью API.", + "global.plugins.sentry": "Sentry", + "global.plugins.sentry.description": "Отправка событий об ошибках Strapi в Sentry.", + "global.plugins.upload": "Медиа-библиотека", + "global.plugins.upload.description": "Управление медиафайлами.", + "global.plugins.users-permissions": "Роли и разрешения", + "global.plugins.users-permissions.description": "Защитите свой API с помощью полного процесса аутентификации на основе JWT. Этот плагин также поставляется со стратегией ACL, которая позволяет вам управлять разрешениями между группами пользователей.", + "global.profile": "Профиль", + "global.marketplace": "Площадка плагинов", + "global.name": "Имя", + "global.none": "Нет", + "global.password": "Пароль", + "global.content-manager": "Редактор контента", + "notification.contentType.relations.conflict": "Тип контента имеет конфликтующие отношения", + "notification.default.title": "Информация:", + "notification.error": "Произошла ошибка", + "notification.error.layout": "Не удалось получить макет", + "notification.error.tokennamenotunique": "Имя уже присвоено другому токену", + "notification.form.error.fields": "Форма содержит некоторые ошибки", + "notification.form.success.fields": "Изменения сохранены", + "notification.link-copied": "Ссылка скопирована в буфер обмена", + "notification.permission.not-allowed-read": "Вам не разрешено просматривать этот документ", + "notification.success.delete": "Элемент удален", + "notification.success.saved": "Сохранено", + "notification.success.title": "Успех:", + "notification.success.tokencreated": "Токен API успешно создан", + "notification.success.tokenedited": "Токен API успешно отредактирован", + "notification.version.update.message": "Доступна новая версия Strapi!", + "notification.warning.404": "404 - Не найдено", + "notification.warning.title": "Внимание:", + "or": "ИЛИ", + "request.error.model.unknown": "Модель данных не существует" } From 5ec28f30fdfc4d4d05f0f75db9414cf0a000005e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Raphael=20M=C3=BC=C3=9Feler?= Date: Tue, 15 Nov 2022 22:22:25 +0100 Subject: [PATCH 10/27] fix: added query parameter for locale (API Documentation Plugin) --- .../server/services/helpers/utils/query-params.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/plugins/documentation/server/services/helpers/utils/query-params.js b/packages/plugins/documentation/server/services/helpers/utils/query-params.js index 13d46792e7..f6adb51cd8 100644 --- a/packages/plugins/documentation/server/services/helpers/utils/query-params.js +++ b/packages/plugins/documentation/server/services/helpers/utils/query-params.js @@ -14,7 +14,7 @@ module.exports = [ { name: 'pagination[withCount]', in: 'query', - description: 'Retun page/pageSize (default: true)', + description: 'Return page/pageSize (default: true)', deprecated: false, required: false, schema: { @@ -92,4 +92,14 @@ module.exports = [ }, style: 'deepObject', }, + { + name: 'locale', + in: 'query', + description: 'Locale to apply', + deprecated: false, + required: false, + schema: { + type: 'string', + }, + }, ]; From 36c5072059915e6343a902b041595585b0ff7565 Mon Sep 17 00:00:00 2001 From: nathan-pichon Date: Wed, 26 Oct 2022 16:39:13 +0200 Subject: [PATCH 11/27] fix(upload-files): do file upload on components too --- .../lib/services/entity-service/index.js | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/index.js b/packages/core/strapi/lib/services/entity-service/index.js index ec6cda794e..36e85a788f 100644 --- a/packages/core/strapi/lib/services/entity-service/index.js +++ b/packages/core/strapi/lib/services/entity-service/index.js @@ -134,17 +134,20 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) // TODO: wrap into transaction const componentData = await createComponents(uid, validData); + const entityData = creationPipeline( + Object.assign(omitComponentData(model, validData), componentData), + { + contentType: model, + } + ); let entity = await db.query(uid).create({ ...query, - data: creationPipeline(Object.assign(omitComponentData(model, validData), componentData), { - contentType: model, - }), + data: entityData, }); // TODO: upload the files then set the links in the entity like with compo to avoid making too many queries - // FIXME: upload in components if (files && Object.keys(files).length > 0) { - await this.uploadFiles(uid, entity, files); + await this.uploadFiles(uid, Object.assign(entityData, entity), files); entity = await this.findOne(uid, entity.id, wrappedParams); } @@ -180,19 +183,22 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator }) // TODO: wrap in transaction const componentData = await updateComponents(uid, entityToUpdate, validData); + const entityData = updatePipeline( + Object.assign(omitComponentData(model, validData), componentData), + { + contentType: model, + } + ); let entity = await db.query(uid).update({ ...query, where: { id: entityId }, - data: updatePipeline(Object.assign(omitComponentData(model, validData), componentData), { - contentType: model, - }), + data: entityData, }); // TODO: upload the files then set the links in the entity like with compo to avoid making too many queries - // FIXME: upload in components if (files && Object.keys(files).length > 0) { - await this.uploadFiles(uid, entity, files); + await this.uploadFiles(uid, Object.assign(entityData, entity), files); entity = await this.findOne(uid, entity.id, wrappedParams); } From dd9ab7faa1f49bc50a313081a02bf57d569fc463 Mon Sep 17 00:00:00 2001 From: nathan-pichon Date: Wed, 2 Nov 2022 15:35:27 +0100 Subject: [PATCH 12/27] test(entity-service): add create tests using upload files --- .../__tests__/entity-service.test.js | 236 +++++++++++++----- 1 file changed, 176 insertions(+), 60 deletions(-) diff --git a/packages/core/strapi/lib/services/entity-service/__tests__/entity-service.test.js b/packages/core/strapi/lib/services/entity-service/__tests__/entity-service.test.js index 3d713e2778..8fe2060aa2 100644 --- a/packages/core/strapi/lib/services/entity-service/__tests__/entity-service.test.js +++ b/packages/core/strapi/lib/services/entity-service/__tests__/entity-service.test.js @@ -7,6 +7,8 @@ const { ValidationError } = require('@strapi/utils').errors; const createEntityService = require('..'); const entityValidator = require('../../entity-validator'); +jest.mock('../../utils/upload-files', () => jest.fn(() => Promise.resolve())); + describe('Entity service', () => { global.strapi = { getModel: jest.fn(() => ({})), @@ -15,6 +17,7 @@ describe('Entity service', () => { return []; }, }, + query: jest.fn(() => ({})), }; describe('Decorator', () => { @@ -80,6 +83,26 @@ describe('Entity service', () => { }); describe('Create', () => { + const fakeQuery = { + count: jest.fn(() => 0), + create: jest.fn(({ data }) => ({ + id: 1, + ...data, + })), + findOne: jest.fn(), + }; + const fakeModels = {}; + + beforeAll(() => { + global.strapi.getModel.mockImplementation((modelName) => fakeModels[modelName]); + global.strapi.query.mockImplementation(() => fakeQuery); + }); + beforeEach(() => { + jest.clearAllMocks(); + }); + afterAll(() => { + global.strapi.getModel.mockImplementation(() => ({})); + }); describe('assign default values', () => { let instance; const entityUID = 'api::entity.entity'; @@ -105,67 +128,59 @@ describe('Entity service', () => { }, }; - const fakeModels = { - [entityUID]: { - uid: entityUID, - kind: 'contentType', - modelName: 'test-model', - privateAttributes: [], - options: {}, - attributes: { - attrStringDefaultRequired: { - type: 'string', - default: 'default value', - required: true, - }, - attrStringDefault: { type: 'string', default: 'default value' }, - attrBoolDefaultRequired: { type: 'boolean', default: true, required: true }, - attrBoolDefault: { type: 'boolean', default: true }, - attrIntDefaultRequired: { type: 'integer', default: 1, required: true }, - attrIntDefault: { type: 'integer', default: 1 }, - attrEnumDefaultRequired: { - type: 'enumeration', - enum: ['a', 'b', 'c'], - default: 'a', - required: true, - }, - attrEnumDefault: { - type: 'enumeration', - enum: ['a', 'b', 'c'], - default: 'b', - }, - attrPassword: { type: 'password' }, - attrRelation: { - type: 'relation', - relation: 'oneToMany', - target: relationUID, - mappedBy: 'entity', - }, + fakeModels[entityUID] = { + uid: entityUID, + kind: 'contentType', + modelName: 'test-model', + privateAttributes: [], + options: {}, + attributes: { + attrStringDefaultRequired: { + type: 'string', + default: 'default value', + required: true, + }, + attrStringDefault: { type: 'string', default: 'default value' }, + attrBoolDefaultRequired: { type: 'boolean', default: true, required: true }, + attrBoolDefault: { type: 'boolean', default: true }, + attrIntDefaultRequired: { type: 'integer', default: 1, required: true }, + attrIntDefault: { type: 'integer', default: 1 }, + attrEnumDefaultRequired: { + type: 'enumeration', + enum: ['a', 'b', 'c'], + default: 'a', + required: true, + }, + attrEnumDefault: { + type: 'enumeration', + enum: ['a', 'b', 'c'], + default: 'b', + }, + attrPassword: { type: 'password' }, + attrRelation: { + type: 'relation', + relation: 'oneToMany', + target: relationUID, + mappedBy: 'entity', }, }, - [relationUID]: { - uid: relationUID, - kind: 'contentType', - modelName: 'relation', - attributes: { - Name: { - type: 'string', - default: 'default value', - required: true, - }, + }; + fakeModels[relationUID] = { + uid: relationUID, + kind: 'contentType', + modelName: 'relation', + attributes: { + Name: { + type: 'string', + default: 'default value', + required: true, }, }, }; const fakeQuery = (uid) => ({ create: jest.fn(({ data }) => data), count: jest.fn(({ where }) => { - let ret = 0; - where.id.$in.forEach((id) => { - const entity = fakeEntities[uid][id]; - if (!entity) return; - ret += 1; - }); - return ret; + return where.id.$in.filter((id) => Boolean(fakeEntities[uid][id])).length; }), }); @@ -173,12 +188,7 @@ describe('Entity service', () => { query: jest.fn((uid) => fakeQuery(uid)), }; - global.strapi = { - getModel: jest.fn((uid) => { - return fakeModels[uid]; - }), - db: fakeDB, - }; + global.strapi.db = fakeDB; instance = createEntityService({ strapi: global.strapi, @@ -187,7 +197,11 @@ describe('Entity service', () => { entityValidator, }); }); - + afterAll(() => { + global.strapi.db = { + query: jest.fn(() => fakeQuery), + }; + }); test('should create record with all default attributes', async () => { const data = {}; @@ -298,6 +312,108 @@ describe('Entity service', () => { ); }); }); + + describe('with files', () => { + let instance; + beforeAll(() => { + fakeModels['test-model'] = { + uid: 'test-model', + kind: 'collectionType', + collectionName: 'test-model', + options: {}, + attributes: { + name: { + type: 'string', + }, + activity: { + displayName: 'activity', + type: 'component', + repeatable: true, + component: 'basic.activity', + }, + }, + modelType: 'contentType', + modelName: 'test-model', + }; + fakeModels['basic.activity'] = { + collectionName: 'components_basic_activities', + info: { + displayName: 'activity', + }, + options: {}, + attributes: { + docs: { + allowedTypes: ['images', 'files', 'videos', 'audios'], + type: 'media', + multiple: true, + }, + name: { + type: 'string', + }, + }, + uid: 'basic.activity', + category: 'basic', + modelType: 'component', + modelName: 'activity', + globalId: 'ComponentBasicActivity', + }; + + const fakeDB = { + query: jest.fn(() => fakeQuery), + }; + + const fakeStrapi = { + getModel: jest.fn((modelName) => fakeModels[modelName]), + }; + instance = createEntityService({ + strapi: fakeStrapi, + db: fakeDB, + eventHub: new EventEmitter(), + entityValidator, + }); + }); + test('should create record with attached files', async () => { + const uploadFiles = require('../../utils/upload-files'); + const data = { + name: 'demoEvent', + activity: [{ name: 'Powering the Aviation of the Future' }], + }; + const files = { + 'activity.0.docs': { + size: 381924, + path: '/tmp/upload_4cab76a3a443b584a1fd3aa52e045130', + name: 'thisisajpeg.jpeg', + type: 'image/jpeg', + mtime: '2022-11-03T13:36:51.764Z', + }, + }; + + fakeQuery.findOne.mockResolvedValue({ id: 1, ...data }); + + await instance.create('test-model', { data, files }); + + expect(global.strapi.getModel).toBeCalled(); + expect(uploadFiles).toBeCalled(); + expect(uploadFiles).toBeCalledTimes(1); + expect(uploadFiles).toBeCalledWith( + 'test-model', + { + id: 1, + name: 'demoEvent', + activity: [ + { + id: 1, + __pivot: { + field: 'activity', + component_type: 'basic.activity', + }, + }, + ], + }, + files + ); + }); + }); }); describe('Update', () => { From 3c1de7565efb383e8b01a9384b406eff374fbac8 Mon Sep 17 00:00:00 2001 From: nathan-pichon Date: Mon, 7 Nov 2022 17:59:59 +0100 Subject: [PATCH 13/27] test(upload): add test on file inside components --- .../tests/content-api/upload.test.api.js | 95 ++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/packages/core/upload/tests/content-api/upload.test.api.js b/packages/core/upload/tests/content-api/upload.test.api.js index 5bbf81f5b9..6919c8db92 100644 --- a/packages/core/upload/tests/content-api/upload.test.api.js +++ b/packages/core/upload/tests/content-api/upload.test.api.js @@ -25,9 +25,45 @@ const dogModel = { }, }; +const todoListModel = { + displayName: 'TodoList', + singularName: 'todolist', + pluralName: 'todolists', + kind: 'collectionType', + attributes: { + title: { + type: 'string', + }, + todo: { + displayName: 'todo', + type: 'component', + repeatable: true, + component: 'default.todo', + }, + }, +}; + +const todoComponent = { + displayName: 'Todo', + attributes: { + docs: { + allowedTypes: ['images', 'files', 'videos', 'audios'], + type: 'media', + multiple: true, + }, + task: { + type: 'string', + }, + }, +}; + describe('Upload plugin', () => { beforeAll(async () => { - await builder.addContentType(dogModel).build(); + await builder + .addContentType(dogModel) + .addComponent(todoComponent) + .addContentType(todoListModel) + .build(); strapi = await createStrapiInstance(); rq = await createContentAPIRequest({ strapi }); }); @@ -190,6 +226,63 @@ describe('Upload plugin', () => { }); }); + describe('Create an entity with a component with a file', () => { + test('With an image', async () => { + const res = await rq({ + method: 'POST', + url: '/todolists', + formData: { + data: '{"title":"Test todolist title","todo":[{"task":"First todo"},{"task":"Second todo"}]}', + 'files.todo.0.docs': fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ + data: { + attributes: { + title: 'Test todolist title', + }, + id: expect.anything(), + }, + }); + const newlyCreatedTodolist = await rq({ + method: 'GET', + url: `/todolists/${res.body.data.id}`, + qs: { + populate: ['todo', 'todo.docs'], + }, + }); + + expect(newlyCreatedTodolist.body).toBeDefined(); + expect(newlyCreatedTodolist.body).toMatchObject({ + data: { + attributes: { + title: 'Test todolist title', + todo: [ + { + id: expect.anything(), + task: 'First todo', + docs: { + data: [ + { + id: expect.anything(), + attributes: { + mime: 'image/jpeg', + name: 'rec.jpg', + }, + }, + ], + }, + }, + expect.any(Object), + ], + }, + }, + }); + }); + }); + // see https://github.com/strapi/strapi/issues/14125 describe('File relations are correctly removed', () => { test('Update an entity with a file correctly removes the relation between the entity and its old file', async () => { From 53166af4fe19a4463f9476563872b1a641f55858 Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Mon, 21 Nov 2022 11:18:31 +0100 Subject: [PATCH 14/27] Rename prp grid => columns --- .../src/content-manager/pages/EditView/GridRow/index.js | 6 +++--- .../admin/admin/src/content-manager/pages/EditView/index.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/GridRow/index.js b/packages/core/admin/admin/src/content-manager/pages/EditView/GridRow/index.js index 0f3064012b..8cd5088d31 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/GridRow/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/GridRow/index.js @@ -4,10 +4,10 @@ import { Grid, GridItem } from '@strapi/design-system/Grid'; import Inputs from '../../../components/Inputs'; import FieldComponent from '../../../components/FieldComponent'; -const GridRow = ({ grid }) => { +const GridRow = ({ columns }) => { return ( - {grid.map(({ fieldSchema, labelAction, metadatas, name, size, queryInfos }) => { + {columns.map(({ fieldSchema, labelAction, metadatas, name, size, queryInfos }) => { const isComponent = fieldSchema.type === 'component'; if (isComponent) { @@ -50,7 +50,7 @@ const GridRow = ({ grid }) => { }; GridRow.propTypes = { - grid: PropTypes.array.isRequired, + columns: PropTypes.array.isRequired, }; export default GridRow; diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js index 57aac3fe9e..aad4a9a463 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js @@ -156,7 +156,7 @@ const EditView = ({ > {row.map((grid, gridRowIndex) => ( - + ))} From 780c3fe35430d9b0c6357ee85f50fb146741aaef Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 31 Oct 2022 11:17:04 +0200 Subject: [PATCH 15/27] build: harden addToProject.yml permissions Signed-off-by: Alex --- .github/workflows/addToProject.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/addToProject.yml b/.github/workflows/addToProject.yml index ed97e2a30a..c3a1a705fe 100644 --- a/.github/workflows/addToProject.yml +++ b/.github/workflows/addToProject.yml @@ -6,6 +6,7 @@ on: - opened - transferred +permissions: {} jobs: add-to-project: name: Add issue to Support Team project From 754e36f7e2572320df573fa0d9dd930e58e1c194 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 31 Oct 2022 11:17:22 +0200 Subject: [PATCH 16/27] build: harden pages.yml permissions Signed-off-by: Alex --- .github/workflows/contributor-doc.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/contributor-doc.yml b/.github/workflows/contributor-doc.yml index f74978e447..f0f191db13 100644 --- a/.github/workflows/contributor-doc.yml +++ b/.github/workflows/contributor-doc.yml @@ -17,8 +17,12 @@ defaults: run: working-directory: docs +permissions: {} jobs: deploy: + permissions: + contents: write # to push pages branch (peaceiris/actions-gh-pages) + environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} From 3dcacb5c106a5fb695c6d77055dfdf886917182d Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 31 Oct 2022 11:19:17 +0200 Subject: [PATCH 17/27] build: harden nightly.yml permissions Signed-off-by: Alex --- .github/workflows/nightly.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index ec869697bb..9944e2f659 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -5,6 +5,9 @@ on: - cron: '0 0 * * 2-6' workflow_dispatch: +permissions: + contents: read # to fetch code (actions/checkout) + jobs: publish: name: 'Publish' From e80ac505f2b2cb5f893f30baea0fe3e769fca61b Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 31 Oct 2022 11:20:47 +0200 Subject: [PATCH 18/27] build: harden tests.yml permissions Signed-off-by: Alex --- .github/workflows/tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0ab790d4a1..700b05de26 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,6 +13,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true +permissions: + contents: read # to fetch code (actions/checkout) + jobs: lint: name: 'lint (node: ${{ matrix.node }})' From 90975c5d93226319887e048fa1dbfa1eb471cf17 Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Mon, 21 Nov 2022 14:31:20 +0100 Subject: [PATCH 19/27] Remove layout prop in favor of useSelector --- .../content-manager/pages/EditView/index.js | 35 ++++++------------- .../pages/EditViewLayoutManager/index.js | 2 +- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js index aad4a9a463..d4ad16246f 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js @@ -1,6 +1,6 @@ import React, { Suspense, memo } from 'react'; import PropTypes from 'prop-types'; -import get from 'lodash/get'; +import { useSelector } from 'react-redux'; import { CheckPermissions, LoadingIndicatorPage, @@ -34,21 +34,21 @@ const cmPermissions = permissions.contentManager; const ctbPermissions = [{ action: 'plugin::content-type-builder.read', subject: null }]; /* eslint-disable react/no-array-index-key */ -const EditView = ({ - allowedActions, - isSingleType, - goBack, - layout, - slug, - id, - origin, - userPermissions, -}) => { +const EditView = ({ allowedActions, isSingleType, goBack, slug, id, origin, userPermissions }) => { const { trackUsage } = useTracking(); const { formatMessage } = useIntl(); const { createActionAllowedFields, readActionAllowedFields, updateActionAllowedFields } = getFieldsActionMatchingPermissions(userPermissions, slug); + const { layout, formattedContentTypeLayout } = useSelector((state) => { + const layout = state['content-manager_editViewLayoutManager'].currentLayout; + + return { + layout, + formattedContentTypeLayout: createAttributesLayout(layout?.contentType ?? {}), + }; + }); + const configurationPermissions = isSingleType ? cmPermissions.singleTypesConfigurations : cmPermissions.collectionTypesConfigurations; @@ -57,7 +57,6 @@ const EditView = ({ const configurationsURL = `/content-manager/${ isSingleType ? 'singleType' : 'collectionType' }/${slug}/configurations/edit`; - const currentContentTypeLayoutData = get(layout, ['contentType'], {}); const DataManagementWrapper = isSingleType ? SingleTypeFormWrapper : CollectionTypeFormWrapper; @@ -68,8 +67,6 @@ const EditView = ({ }); }; - const formattedContentTypeLayout = createAttributesLayout(currentContentTypeLayoutData); - return ( {({ @@ -256,16 +253,6 @@ EditView.propTypes = { canCreate: PropTypes.bool.isRequired, canDelete: PropTypes.bool.isRequired, }).isRequired, - layout: PropTypes.shape({ - components: PropTypes.object.isRequired, - contentType: PropTypes.shape({ - uid: PropTypes.string.isRequired, - settings: PropTypes.object.isRequired, - metadatas: PropTypes.object.isRequired, - options: PropTypes.object.isRequired, - attributes: PropTypes.object.isRequired, - }).isRequired, - }).isRequired, id: PropTypes.string, isSingleType: PropTypes.bool, goBack: PropTypes.func.isRequired, diff --git a/packages/core/admin/admin/src/content-manager/pages/EditViewLayoutManager/index.js b/packages/core/admin/admin/src/content-manager/pages/EditViewLayoutManager/index.js index 586bef6d47..89bfe81446 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditViewLayoutManager/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditViewLayoutManager/index.js @@ -30,7 +30,7 @@ const EditViewLayoutManager = ({ layout, ...rest }) => { return ; } - return ; + return ; }; EditViewLayoutManager.propTypes = { From ef8291dabeec1ef5c9b945bc1b6b43b7a91fd348 Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Tue, 22 Nov 2022 14:03:14 +0100 Subject: [PATCH 20/27] Restructure createAttributesList --- .../pages/EditView/utils/createAttributesLayout.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js index 2172ec8c3a..b46faaf7a3 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js @@ -1,17 +1,18 @@ import { get, isEmpty } from 'lodash'; const createAttributesLayout = (currentContentTypeLayoutData) => { - const getType = (name) => get(attributes, [name, 'type'], ''); - let currentRowIndex = 0; - const newLayout = []; - if (!currentContentTypeLayoutData.layouts) { - return newLayout; + return []; } const currentLayout = currentContentTypeLayoutData.layouts.edit; const attributes = currentContentTypeLayoutData.attributes; + const getType = (name) => get(attributes, [name, 'type'], ''); + + let currentRowIndex = 0; + const newLayout = []; + currentLayout.forEach((row) => { const hasDynamicZone = row.some(({ name }) => getType(name) === 'dynamiczone'); From eabeef47902eaee80b48f44c5713135386e74038 Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Tue, 22 Nov 2022 15:16:30 +0100 Subject: [PATCH 21/27] Use reselect for createAttributesLayout --- .../src/content-manager/pages/EditView/index.js | 15 ++++++--------- .../content-manager/pages/EditView/selectors.js | 10 ++++++++++ 2 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 packages/core/admin/admin/src/content-manager/pages/EditView/selectors.js diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js index d4ad16246f..162f6a1323 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js @@ -26,9 +26,10 @@ import { getTrad } from '../../utils'; import DraftAndPublishBadge from './DraftAndPublishBadge'; import Informations from './Informations'; import Header from './Header'; -import { createAttributesLayout, getFieldsActionMatchingPermissions } from './utils'; +import { getFieldsActionMatchingPermissions } from './utils'; import DeleteLink from './DeleteLink'; import GridRow from './GridRow'; +import { selectCurrentLayout, selectAttributesLayout } from './selectors'; const cmPermissions = permissions.contentManager; const ctbPermissions = [{ action: 'plugin::content-type-builder.read', subject: null }]; @@ -40,14 +41,10 @@ const EditView = ({ allowedActions, isSingleType, goBack, slug, id, origin, user const { createActionAllowedFields, readActionAllowedFields, updateActionAllowedFields } = getFieldsActionMatchingPermissions(userPermissions, slug); - const { layout, formattedContentTypeLayout } = useSelector((state) => { - const layout = state['content-manager_editViewLayoutManager'].currentLayout; - - return { - layout, - formattedContentTypeLayout: createAttributesLayout(layout?.contentType ?? {}), - }; - }); + const { layout, formattedContentTypeLayout } = useSelector((state) => ({ + layout: selectCurrentLayout(state), + formattedContentTypeLayout: selectAttributesLayout(state), + })); const configurationPermissions = isSingleType ? cmPermissions.singleTypesConfigurations diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/selectors.js b/packages/core/admin/admin/src/content-manager/pages/EditView/selectors.js new file mode 100644 index 0000000000..90185c81d3 --- /dev/null +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/selectors.js @@ -0,0 +1,10 @@ +import { createSelector } from 'reselect'; +import { createAttributesLayout } from './utils'; + +const selectCurrentLayout = (state) => state['content-manager_editViewLayoutManager'].currentLayout; + +const selectAttributesLayout = createSelector(selectCurrentLayout, (layout) => + createAttributesLayout(layout?.contentType ?? {}) +); + +export { selectCurrentLayout, selectAttributesLayout }; From c16f5b9ebb45eed7fa3d6da50b218309bc0f3205 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Nov 2022 17:04:47 +0000 Subject: [PATCH 22/27] chore(deps): bump commander from 8.2.0 to 8.3.0 Bumps [commander](https://github.com/tj/commander.js) from 8.2.0 to 8.3.0. - [Release notes](https://github.com/tj/commander.js/releases) - [Changelog](https://github.com/tj/commander.js/blob/master/CHANGELOG.md) - [Commits](https://github.com/tj/commander.js/compare/v8.2.0...v8.3.0) --- updated-dependencies: - dependency-name: commander dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/cli/create-strapi-app/package.json | 2 +- .../cli/create-strapi-starter/package.json | 2 +- packages/core/strapi/package.json | 2 +- yarn.lock | 30 ++++--------------- 4 files changed, 8 insertions(+), 28 deletions(-) diff --git a/packages/cli/create-strapi-app/package.json b/packages/cli/create-strapi-app/package.json index 7a88cd201b..06817de25e 100644 --- a/packages/cli/create-strapi-app/package.json +++ b/packages/cli/create-strapi-app/package.json @@ -4,7 +4,7 @@ "description": "Generate a new Strapi application.", "dependencies": { "@strapi/generate-new": "4.5.2", - "commander": "6.1.0", + "commander": "7.2.0", "inquirer": "8.2.4" }, "keywords": [ diff --git a/packages/cli/create-strapi-starter/package.json b/packages/cli/create-strapi-starter/package.json index 5b61057d91..ec6df25efb 100644 --- a/packages/cli/create-strapi-starter/package.json +++ b/packages/cli/create-strapi-starter/package.json @@ -41,7 +41,7 @@ "@strapi/generate-new": "4.5.2", "chalk": "4.1.1", "ci-info": "3.5.0", - "commander": "7.1.0", + "commander": "7.2.0", "execa": "5.1.1", "fs-extra": "10.0.0", "inquirer": "8.2.4", diff --git a/packages/core/strapi/package.json b/packages/core/strapi/package.json index ff1f6e2530..7ea56089a0 100644 --- a/packages/core/strapi/package.json +++ b/packages/core/strapi/package.json @@ -98,7 +98,7 @@ "chokidar": "3.5.2", "ci-info": "3.5.0", "cli-table3": "0.6.2", - "commander": "8.2.0", + "commander": "7.2.0", "configstore": "5.0.1", "debug": "4.3.2", "delegates": "1.0.0", diff --git a/yarn.lock b/yarn.lock index 765f9d96ad..59c6766fd5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9398,20 +9398,10 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== -commander@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.1.0.tgz#f8d722b78103141006b66f4c7ba1e97315ba75bc" - integrity sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA== - -commander@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.1.0.tgz#f2eaecf131f10e36e07d894698226e36ae0eb5ff" - integrity sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg== - -commander@8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-8.2.0.tgz#37fe2bde301d87d47a53adeff8b5915db1381ca8" - integrity sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA== +commander@7.2.0, commander@^7.0.0, commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== commander@^2.19.0, commander@^2.20.0, commander@^2.20.3: version "2.20.3" @@ -9428,22 +9418,12 @@ commander@^6.2.1: resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== -commander@^7.0.0, commander@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - commander@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== -commander@^9.1.0: - version "9.4.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.0.tgz#bc4a40918fefe52e22450c111ecd6b7acce6f11c" - integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw== - -commander@^9.3.0: +commander@^9.1.0, commander@^9.3.0: version "9.4.1" resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" integrity sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw== From a80bef5f5c975f23c65cbe7ee4d2533085767f11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Nov 2022 10:27:01 +0000 Subject: [PATCH 23/27] Bump @graphql-tools/schema from 8.1.2 to 8.5.1 Bumps [@graphql-tools/schema](https://github.com/ardatan/graphql-tools/tree/HEAD/packages/schema) from 8.1.2 to 8.5.1. - [Release notes](https://github.com/ardatan/graphql-tools/releases) - [Changelog](https://github.com/ardatan/graphql-tools/blob/master/packages/schema/CHANGELOG.md) - [Commits](https://github.com/ardatan/graphql-tools/commits/@graphql-tools/schema@8.5.1/packages/schema) --- updated-dependencies: - dependency-name: "@graphql-tools/schema" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/plugins/graphql/package.json | 2 +- yarn.lock | 19 ++----------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/packages/plugins/graphql/package.json b/packages/plugins/graphql/package.json index f856b6b107..2d157fd1ef 100644 --- a/packages/plugins/graphql/package.json +++ b/packages/plugins/graphql/package.json @@ -27,7 +27,7 @@ "test:front:watch:ce": "cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll" }, "dependencies": { - "@graphql-tools/schema": "8.1.2", + "@graphql-tools/schema": "8.5.1", "@graphql-tools/utils": "^8.12.0", "@strapi/utils": "4.5.2", "apollo-server-core": "3.1.2", diff --git a/yarn.lock b/yarn.lock index 765f9d96ad..3daf8ca401 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2178,7 +2178,7 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== -"@graphql-tools/merge@8.3.1", "@graphql-tools/merge@^8.0.2": +"@graphql-tools/merge@8.3.1": version "8.3.1" resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.1.tgz#06121942ad28982a14635dbc87b5d488a041d722" integrity sha512-BMm99mqdNZbEYeTPK3it9r9S6rsZsQKtlqJsSBknAclXq2pGEfOxjcIZi+kBSkHZKPKCRrYDd5vY0+rUmIHVLg== @@ -2196,16 +2196,6 @@ fast-json-stable-stringify "^2.1.0" tslib "^2.4.0" -"@graphql-tools/schema@8.1.2": - version "8.1.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.1.2.tgz#913879da1a7889a9488e9b7dc189e7c83eff74be" - integrity sha512-rX2pg42a0w7JLVYT+f/yeEKpnoZL5PpLq68TxC3iZ8slnNBNjfVfvzzOn8Q8Q6Xw3t17KP9QespmJEDfuQe4Rg== - dependencies: - "@graphql-tools/merge" "^8.0.2" - "@graphql-tools/utils" "^8.1.1" - tslib "~2.3.0" - value-or-promise "1.0.10" - "@graphql-tools/schema@8.5.1", "@graphql-tools/schema@^8.0.0": version "8.5.1" resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.5.1.tgz#c2f2ff1448380919a330312399c9471db2580b58" @@ -2223,7 +2213,7 @@ dependencies: tslib "^2.4.0" -"@graphql-tools/utils@^8.0.0", "@graphql-tools/utils@^8.1.1", "@graphql-tools/utils@^8.12.0": +"@graphql-tools/utils@^8.0.0", "@graphql-tools/utils@^8.12.0": version "8.12.0" resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.12.0.tgz#243bc4f5fc2edbc9e8fd1038189e57d837cbe31f" integrity sha512-TeO+MJWGXjUTS52qfK4R8HiPoF/R7X+qmgtOYd8DTH0l6b+5Y/tlg5aGeUJefqImRq7nvi93Ms40k/Uz4D5CWw== @@ -22654,11 +22644,6 @@ value-equal@^1.0.1: resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== -value-or-promise@1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.10.tgz#5bf041f1e9a8e7043911875547636768a836e446" - integrity sha512-1OwTzvcfXkAfabk60UVr5NdjtjJ0Fg0T5+B1bhxtrOEwSH2fe8y4DnLgoksfCyd8yZCOQQHB0qLMQnwgCjbXLQ== - value-or-promise@1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" From df8feafa4bed7aad4b2761859ba810e4ef89365c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Nov 2022 11:30:19 +0000 Subject: [PATCH 24/27] chore(deps): bump aws-sdk from 2.1215.0 to 2.1260.0 Bumps [aws-sdk](https://github.com/aws/aws-sdk-js) from 2.1215.0 to 2.1260.0. - [Release notes](https://github.com/aws/aws-sdk-js/releases) - [Changelog](https://github.com/aws/aws-sdk-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js/compare/v2.1215.0...v2.1260.0) --- updated-dependencies: - dependency-name: aws-sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- packages/providers/upload-aws-s3/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/providers/upload-aws-s3/package.json b/packages/providers/upload-aws-s3/package.json index 4e24188eeb..cb2f141810 100644 --- a/packages/providers/upload-aws-s3/package.json +++ b/packages/providers/upload-aws-s3/package.json @@ -37,7 +37,7 @@ "test": "echo \"no tests yet\"" }, "dependencies": { - "aws-sdk": "2.1215.0", + "aws-sdk": "2.1260.0", "lodash": "4.17.21" }, "engines": { diff --git a/yarn.lock b/yarn.lock index 59c6766fd5..81ecca2e52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7872,10 +7872,10 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -aws-sdk@2.1215.0: - version "2.1215.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1215.0.tgz#dafc339c2f9039a8f9de30d863a8665716df2ec0" - integrity sha512-btOexIY0O2F+HhjytToaYuub2HEdLqccZSM8rbT3nrbXo7U4k4Gqi6SbMGi2a+vEpj8lY8dAuMR2lvvVs4Ib9Q== +aws-sdk@2.1260.0: + version "2.1260.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1260.0.tgz#3dc18f49dd4aaa18e4e9787c62f1ad02e5aaac4c" + integrity sha512-iciXVukPbhmh44xcF+5/CO15jtESqRkXuEH54XaU8IpCzbYkAcPBaS29vLRN2SRuN1Dy2S3X7SaZZxFJWLAHrg== dependencies: buffer "4.9.2" events "1.1.1" From e63b41b73a41cfc9c01def79b53db07e5902237f Mon Sep 17 00:00:00 2001 From: Mark Kaylor Date: Wed, 23 Nov 2022 14:01:41 +0100 Subject: [PATCH 25/27] Remove comment and named export --- .../admin/admin/src/content-manager/pages/EditView/index.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js index 162f6a1323..2e3ca4749b 100644 --- a/packages/core/admin/admin/src/content-manager/pages/EditView/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/EditView/index.js @@ -258,7 +258,4 @@ EditView.propTypes = { userPermissions: PropTypes.array, }; -export { EditView }; export default memo(EditView); - -// export default () => 'TODO Edit view'; From d526d80a18ab6812e86fc3733282f6daad058e0d Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Wed, 23 Nov 2022 16:39:16 +0100 Subject: [PATCH 26/27] PoC cache actions --- .github/workflows/checks.yml | 6 +++++- .github/workflows/tests.yml | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 6671ef0b56..0c8199e6cb 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -17,8 +17,12 @@ jobs: steps: - uses: actions/checkout@v3 - uses: ./.github/actions/check-pr-status + security-lockfile-analysis: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + cache: yarn - uses: ./.github/actions/security/lockfile diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 35b4b38363..18b00fa6d7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,6 +26,11 @@ jobs: with: node-version: ${{ matrix.node }} cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} + - run: yarn install --frozen-lockfile - name: Run lint run: yarn run -s lint @@ -43,6 +48,11 @@ jobs: with: node-version: ${{ matrix.node }} cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} + - run: yarn install --frozen-lockfile - name: Run tests run: yarn run -s test:unit --coverage @@ -66,6 +76,11 @@ jobs: with: node-version: ${{ matrix.node }} cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} + - run: yarn install --frozen-lockfile - name: Build run: yarn build From 66580184c1d75c87296e7c6cd0cd3c00c630826a Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Wed, 23 Nov 2022 16:53:44 +0100 Subject: [PATCH 27/27] Add caching to all tests --- .github/workflows/tests.yml | 38 +++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 18b00fa6d7..2e90a277c8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,7 +25,6 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn - uses: actions/cache@v3 with: path: '**/node_modules' @@ -47,7 +46,6 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn - uses: actions/cache@v3 with: path: '**/node_modules' @@ -75,7 +73,6 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn - uses: actions/cache@v3 with: path: '**/node_modules' @@ -124,7 +121,10 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - uses: ./.github/actions/run-api-tests with: @@ -159,7 +159,10 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - uses: ./.github/actions/run-api-tests with: @@ -194,7 +197,10 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - uses: ./.github/actions/run-api-tests with: @@ -213,7 +219,10 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - uses: ./.github/actions/run-api-tests env: @@ -255,7 +264,10 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - uses: ./.github/actions/run-api-tests with: @@ -293,7 +305,10 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - uses: ./.github/actions/run-api-tests with: @@ -316,7 +331,10 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - cache: yarn + - uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - uses: ./.github/actions/run-api-tests env: