diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md index bc6da3ab2e..f636716eb4 100644 --- a/.github/ISSUE_TEMPLATE/BUG_REPORT.md +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md @@ -10,6 +10,10 @@ Before you start, please make sure your issue is understandable and reproducible To make your issue readable make sure you use valid Markdown syntax. https://guides.github.com/features/mastering-markdown/ + +Please ensure you have also read and understand the contributing guide. + +https://github.com/strapi/strapi/blob/master/CONTRIBUTING.md#reporting-an-issue --> **Describe the bug** @@ -35,7 +39,7 @@ If applicable, add code samples to help explain your problem. - Node.js version: - NPM version: -- Strapi version: +- Strapi version: - Database: - Operating system: diff --git a/docs/v3.x/cli/CLI.md b/docs/v3.x/cli/CLI.md index 9218e3fc83..4bd06ec74f 100644 --- a/docs/v3.x/cli/CLI.md +++ b/docs/v3.x/cli/CLI.md @@ -100,7 +100,7 @@ Options: All these examples are equivalent. ::: warning -When configuring your application you often enter credentials for thrid party services (e.g authentication providers). Be aware that those credentials will also be dumped into the output of this command. +When configuring your application you often enter credentials for third party services (e.g authentication providers). Be aware that those credentials will also be dumped into the output of this command. In case of doubt, you should avoid committing the dump file into a versioning system. Here are some methods you can explore: - Copy the file directly to the environment you want and run the restore command there. @@ -137,7 +137,7 @@ All these examples are equivalent. When running the restore command, you can choose from three different strategies: - **replace**: Will create missing keys and replace existing ones. -- **merge**: Will create missing keys and merge existing keys whith there new value. +- **merge**: Will create missing keys and merge existing keys with their new value. - **keep**: Will create missing keys and keep existing keys as is. ## strapi generate:api diff --git a/docs/v3.x/concepts/configurations.md b/docs/v3.x/concepts/configurations.md index bba20b3e90..35e7f5ddf1 100644 --- a/docs/v3.x/concepts/configurations.md +++ b/docs/v3.x/concepts/configurations.md @@ -23,7 +23,7 @@ strapi.config.get('server.host', 'defaultValueIfUndefined'); Nested keys are accessible with `dot-notation`. :::tip NOTE -You can notice the filename is used as prefix to access the configurations. +Notice that the filename is used as a prefix to access the configurations. ::: ## Formats @@ -50,7 +50,7 @@ module.exports = ({ env }) => { ## Environment variables -In most usecases you will have different configurations between your environments. For example: your database credentials. +In most use cases you will have different configurations between your environments. For example: your database credentials. Instead of writting those credentials into your configuration files, you can define those variables in a `.env` file at the root of your application. @@ -111,9 +111,9 @@ env.date('VAR', new Date()); ## Environments -What if you need to specific static configurations for specific environments and using environement variables becomes tedious ? +What if you need to specific static configurations for specific environments and using environment variables becomes tedious? -Strapi configurations can also be created per environment in `./config/env/{env}/{filename}`. These configurations will be merged into the base ones defined in the `./config` folder. +Strapi configurations can also be created per environment in `./config/env/{env}/{filename}`. These configurations will be merged into the base configurations defined in the `./config` folder. The environment is based on the `NODE_ENV` environment variable (defaults to `development`). When starting strapi with `NODE_ENV=production` it will load the configuration from `./config/*` and `./config/env/production/*`. Everything defined in the production config will override the default config. @@ -179,7 +179,7 @@ module.exports = ({ env }) => ({ | `admin` | Admin panel configuration | Object | | | `admin.url` | Url of your admin panel. Default value: `/admin`. Note: If the url is relative, it will be concatenated with `url`. | string | `/admin` | | `admin.autoOpen` | Enable or disabled administration opening on start. | boolean | `true` | -| `admin.watchIgnoreFiles` | Add custom files that should not be watched during development. See more [here](https://github.com/paulmillr/chokidar#path-filtering) (property `ignored`). | Array(string) | `[]`. | +| `admin.watchIgnoreFiles` | Add custom files that should not be watched during development. See more [here](https://github.com/paulmillr/chokidar#path-filtering) (property `ignored`). | Array(string) | `[]` | ## Functions diff --git a/docs/v3.x/guides/error-catching.md b/docs/v3.x/guides/error-catching.md index fbf211d62e..e4198e3c46 100644 --- a/docs/v3.x/guides/error-catching.md +++ b/docs/v3.x/guides/error-catching.md @@ -65,14 +65,15 @@ It's important to call `throw(error);` to avoid stopping the middleware stack. I ## Configure the middleware -Make sure your middleware is added at the end of the middleware stack. +Make sure your middleware is added at the beginning of the middleware stack. **Path —** `./config/middleware.js` ```js module.exports = { load: { - after: ['parser', 'router', 'sentry'], + before: ['sentry', 'responseTime', 'logger', ...], + ... }, }; ``` diff --git a/docs/v3.x/guides/is-owner.md b/docs/v3.x/guides/is-owner.md index 687f8cdb88..1f6006cca5 100644 --- a/docs/v3.x/guides/is-owner.md +++ b/docs/v3.x/guides/is-owner.md @@ -1,12 +1,12 @@ # Create is owner policy -This guide will explain how to restrict content edition to content authors only. +This guide will explain how to restrict content editing to content authors only. ## Introduction It is often required that the author of an entry is the only user allowed to edit or delete the entry. -This is a feature that is requested a lot and in this guide we will see how to implement it. +This is a feature that is requested a lot and in this guide we will show how to implement it. ## Example diff --git a/docs/v3.x/installation/digitalocean-one-click.md b/docs/v3.x/installation/digitalocean-one-click.md index 3d7f06fadc..91a09effda 100644 --- a/docs/v3.x/installation/digitalocean-one-click.md +++ b/docs/v3.x/installation/digitalocean-one-click.md @@ -127,14 +127,14 @@ Please note that by default the `strapi` user **cannot run sudo commands** this Once you are in the Strapi service account you can now use [PM2](https://pm2.keymetrics.io/docs/usage/quick-start/#managing-processes) to manage the Strapi process and view the logs. -The default service is called `strapi-develop` and should be running with an ID of `0`. Below are some example commands for PM2: +The default service is called `strapi-development` and should be running with an ID of `0`. Below are some example commands for PM2: ```bash pm2 list # Will show you a list of all running processes -pm2 restart strapi-develop # Restart the Strapi process manually -pm2 stop strapi-develop # Stop the Strapi process -pm2 start strapi-develop # Start the Strapi process -pm2 logs strapi-develop # Show the logs in real time (to exit use ctrl +c) +pm2 restart strapi-development # Restart the Strapi process manually +pm2 stop strapi-development # Stop the Strapi process +pm2 start strapi-development # Start the Strapi process +pm2 logs strapi-development # Show the logs in real time (to exit use ctrl +c) ``` Strapi will automatically start if the virtual machine is rebooted, you can also manually view the log files under `/srv/strapi/.pm2/logs` if you encounter any errors during the bootup. @@ -147,7 +147,7 @@ Use the following steps to change the PostgreSQL password and update Strapi's co - Stop the current strapi process and change the password for the `strapi` database user ```bash -pm2 stop strapi-develop +pm2 stop strapi-development psql -c "ALTER USER strapi with password 'your-new-password';" ``` @@ -160,6 +160,6 @@ DATABASE_PASSWORD=your-new-password - Restart Strapi and confirm the password change was successful ```bash -pm2 start strapi-develop -pm2 logs strapi-develop +pm2 start strapi-development +pm2 logs strapi-development ``` diff --git a/docs/v3.x/migration-guide/migration-guide-beta.20-to-3.0.0.md b/docs/v3.x/migration-guide/migration-guide-beta.20-to-3.0.0.md index 261288a46b..0aa5952b3f 100644 --- a/docs/v3.x/migration-guide/migration-guide-beta.20-to-3.0.0.md +++ b/docs/v3.x/migration-guide/migration-guide-beta.20-to-3.0.0.md @@ -1,6 +1,6 @@ # Migration guide from 3.0.0-beta.20 to 3.0.0 -Upgrading your strapi application to `3.0.0`. +Upgrading your Strapi application to `3.0.0`. **Make sure your server is not running until the end of the migration** @@ -32,7 +32,7 @@ Then run either `yarn install` or `npm install`. ## New configuration loader -We have reworked the way a strapi project is configured to make it simpler yet more powerfull. +We have reworked the way a strapi project is configured to make it simpler yet more powerful. Some of the improvements are: @@ -44,19 +44,19 @@ Before migrating, you should first read the new [configuration documentation](.. ### Migrating -**Server** +#### Server Your server configuration can move from `./config/environments/{env}/server.json` to `./config/server.js` like shown [here](../concepts/configurations.md#server). -**Database configuration** +#### Database configuration Your database configuration can move from `./config/environments/{env}/database.json` to `./config/database.js` like shown [here](../concepts/configurations.md#database). -**Middlewares** +#### Middlewares We have moved all the middleware related configurations into one place: `./config/middleware.js`. -The middlewares were configured in mutliple files: +The middlewares were configured in multiple files: - `./config/middleware.json` - `./config/application.json` @@ -94,7 +94,7 @@ You can review all possible options the [middleware documentation](../concepts/m If you never configured any middlewares you can delete the file all together. You can also only set the configurations you want to customize and leave the others out. ::: -**Hook** +#### Hook We applied the same logic from the `middleware` configuration to the `hook` configuration. @@ -104,19 +104,19 @@ First you can create a file `./config/hook.js`, and you can move the content of If you never configured any hook you can delete the file all together. You can also only set the configurations you want to customize and leave the others out. ::: -**Functions** +#### Functions You can leave your functions as is, we didn't change how they work. -**Policies** +#### Policies You can leave your policies as is, we didn't change how they work. -**Custom** +#### Custom Any custom configuration you have can still be used. You can read the [configuration documentation](../concepts/configurations.md) to know more. -**Plugin** +#### Plugin From now on, you can set your plugin configurations in `./config/plugins.js` or `./config/env/{env}/plugin.js`. @@ -130,9 +130,9 @@ module.exports = { }; ``` -### Final strucutre +### Final structure -Here is an example of the strucuture you could have after migrating: +Here is an example of the structure you could have after migrating: **Before** @@ -217,9 +217,9 @@ Once you have setup your configuration, you can cleanup your database by deletin If you are using the graphql `register` mutation, the input and response types have changed. You can check the code [here](https://github.com/strapi/strapi/pull/6047). -The `changePassword` mutation got renamed to `resetPassword` to reflect what it does. You can check the code [here](https://github.com/strapi/strapi/pull/5655. +The `changePassword` mutation got renamed to `resetPassword` to reflect what it does. You can check the code [here](https://github.com/strapi/strapi/pull/5655). -## Remove `idAttribute` and `idAttributeType` options. +## Remove `idAttribute` and `idAttributeType` options Currently using the idAttribute and idAttributeType options can break strapi in many ways. Fixing this is going to require a lot of work on the database and content management layer. @@ -235,7 +235,7 @@ We replaced the `proxy` option found in `./config/server.json` by the `url` opti This option also makes the `admin.build.backend` option obsolete. -This option tells strapi where it is hosted and is usefull for generating links or telling the admin panel where the API is available. +This option tells strapi where it is hosted and is useful for generating links or telling the admin panel where the API is available. **Before** diff --git a/packages/strapi-admin/admin/src/translations/ru.json b/packages/strapi-admin/admin/src/translations/ru.json index 21f7873af2..04b5fa0e7b 100644 --- a/packages/strapi-admin/admin/src/translations/ru.json +++ b/packages/strapi-admin/admin/src/translations/ru.json @@ -1,6 +1,7 @@ { "Analytics": "Аналитика", "Content Manager": "Редактор контента", + "Content Type Builder": "Типы контента", "Documentation": "Документация", "Email": "E-mail", "Files Upload": "Загрузка файлов", @@ -31,6 +32,7 @@ "app.components.HomePage.button.quickStart": "ОЗНАКОМИТЬСЯ С РУКОВОДСТВОМ ПО БЫСТРОМУ СТАРТУ", "app.components.HomePage.community": "Найдите сообщество в интернете", "app.components.HomePage.community.content": "Обсуждайте с членами команды и разработчиками в разных каналах.", + "app.components.HomePage.create": "Создайте свой первый тип контента", "app.components.HomePage.createBlock.content.first": " ", "app.components.HomePage.createBlock.content.second": " — плагин, который поможет вам определить структуру ваших моделей данных. Если вы новичок, мы настоятельно рекомендуем вам изучить наше ", "app.components.HomePage.createBlock.content.tutorial": " руководство.", @@ -74,7 +76,8 @@ "app.components.LeftMenuLinkContainer.general": "Общие", "app.components.LeftMenuLinkContainer.installNewPlugin": "Магазин", "app.components.LeftMenuLinkContainer.listPlugins": "Плагины", - "app.components.LeftMenuLinkContainer.contentTypes": "Типы контента", + "app.components.LeftMenuLinkContainer.collectionTypes": "Коллекции", + "app.components.LeftMenuLinkContainer.singleTypes": "Страницы", "app.components.LeftMenuLinkContainer.noPluginsInstalled": "Нет установленных плагинов", "app.components.LeftMenuLinkContainer.plugins": "Плагины", "app.components.LeftMenuLinkContainer.settings": "Настройки", @@ -121,6 +124,9 @@ "components.FilterOptions.FILTER_TYPES._lt": "меньше чем", "components.FilterOptions.FILTER_TYPES._lte": "меньше или равно", "components.FilterOptions.FILTER_TYPES._ne": "не равно", + "components.FilterOptions.FILTER_TYPES._ncontains": "не содержит", + "components.FilterOptions.FILTER_TYPES._in": "соответствует одному из значений массива", + "components.FilterOptions.FILTER_TYPES._nin": "не соответствует ни одному из значений массива", "components.Input.error.attribute.key.taken": "Это значение уже существует", "components.Input.error.attribute.sameKeyAndName": "Не может быть одинаковым", "components.Input.error.attribute.taken": "Поле с таким названием уже существует", @@ -146,6 +152,7 @@ "components.PageFooter.select": "записей на странице", "components.ProductionBlocker.description": "В целях безопасности мы должны отключить этот плагин в других средах.", "components.ProductionBlocker.header": "Этот плагин доступен только на стадии разработки.", + "components.Search.placeholder": "Поиск...", "components.Wysiwyg.ToggleMode.markdown": "Переключиться в режим markdown", "components.Wysiwyg.ToggleMode.preview": "Переключиться в режим предпросмотра", "components.Wysiwyg.collapse": "Свернуть", @@ -168,12 +175,14 @@ "notification.error.layout": "Не удалось получить макет", "request.error.model.unknown": "Модель данных не существует", "app.utils.delete": "Удалить", + "app.utils.filters": "Фильтры", "HomePage.helmet.title": "Домашняя страница", "HomePage.welcome.congrats": "Поздравляем!", "HomePage.welcome.congrats.content": "Вы вошли как первый администратор. Чтобы открыть для себя мощные функции, предоставляемые Strapi,", + "HomePage.welcome.congrats.content.bold": "мы рекомендуем вам создать свою первую коллекцию.", "HomePage.community": "Присоединяйтесь к сообществу", "HomePage.roadmap": "Смотрите нашу дорожную карту", - "HomePage.greetings": "Привет {name}!", + "HomePage.greetings": "Привет, {name}!", "Auth.advanced.allow_register": "", "Auth.privacy-policy-agreement.terms": "условия", "Auth.privacy-policy-agreement.policy": "политика конфиденциальности", @@ -209,16 +218,16 @@ "Auth.form.login.password.label": "Пароль", "Auth.form.login.rememberMe.label": "Запомнить меня", "Auth.form.login.username.label": "Имя пользователя", - "Auth.form.login.username.placeholder": "John Doe", + "Auth.form.login.username.placeholder": "Иван Иванов", "Auth.form.register-success.email.label": "Письмо успешно отправлено e-mail", "Auth.form.register-success.email.placeholder": "mysuperemail@gmail.com", "Auth.form.register.confirmPassword.label": "Подтверждение пароля", "Auth.form.register.email.label": "E-mail", - "Auth.form.register.email.placeholder": "johndoe@gmail.com", + "Auth.form.register.email.placeholder": "ivanivanov@gmail.com", "Auth.form.register.news.label": "Держите меня в курсе о новых функциях и предстоящих улучшениях (делая это, вы принимаете {terms} и {policy}).", "Auth.form.register.password.label": "Пароль", "Auth.form.register.username.label": "Имя пользователя", - "Auth.form.register.username.placeholder": "John Doe", + "Auth.form.register.username.placeholder": "Иван Иванов", "Auth.header.register.description": "Для завершения установки и обеспечения безопасности приложения, создайте вашего первого пользователя (root admin), заполнив форму ниже.", "Auth.link.forgot-password": "Забыли пароль?", "Auth.link.ready": "Готовы войти?", @@ -258,7 +267,9 @@ "components.Input.error.password.noMatch": "Пароль не совпадает", "form.button.done": "Выполнено", "form.button.finish": "Финиш", + "notification.contentType.relations.conflict": "Некоторые элементы ссылаются на данный тип контента", "notification.form.error.fields": "Форма содержит некоторые ошибки", "notification.form.success.fields": "Изменения сохранены", + "notification.success.delete": "Элемент удален", "global.prompt.unsaved": "Вы действительно хотите покинуть эту страницу? Все Ваши изменения будут потеряны" } diff --git a/packages/strapi-generate-api/templates/model.template b/packages/strapi-generate-api/templates/model.template index 4133599f61..319ea80a1d 100644 --- a/packages/strapi-generate-api/templates/model.template +++ b/packages/strapi-generate-api/templates/model.template @@ -1,7 +1,7 @@ 'use strict'; /** - * Read the documentation (https://strapi.io/documentation/v3.x/concepts/models.html#life-cycle-callbacks) + * Read the documentation (https://strapi.io/documentation/v3.x/concepts/models.html#lifecycle-hooks) * to customize this model */ diff --git a/packages/strapi-plugin-content-type-builder/admin/src/translations/nl.json b/packages/strapi-plugin-content-type-builder/admin/src/translations/nl.json index e722bc1901..100d244ff7 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/translations/nl.json +++ b/packages/strapi-plugin-content-type-builder/admin/src/translations/nl.json @@ -160,11 +160,11 @@ "popUpWarning.bodyMessage.contentType.delete": "Weet je zeker dat je dit collectie type wilt verwijderen?", "prompt.unsaved": "Weet je zeker dat je wilt stoppen? Al uw wijzigingen gaan verloren.", "relation.attributeName.placeholder": "Bijv.: auteur, categorie, tag", - "relation.manyToMany": "heeft en behoord tot veel", - "relation.manyToOne": "heeft veel en behoord tot één", + "relation.manyToMany": "heeft en behoort tot veel", + "relation.manyToOne": "heeft veel en behoort tot één", "relation.manyWay": "heeft veel", - "relation.oneToMany": "behoord tot vele", - "relation.oneToOne": "heeft en behoord tot één", + "relation.oneToMany": "behoort tot vele", + "relation.oneToOne": "heeft en behoort tot één", "relation.oneWay": "heeft één", "table.attributes.title.plural": "{number} velden", "table.attributes.title.singular": "{number} veld" diff --git a/packages/strapi-plugin-upload/admin/src/components/InputMedia/ErrorMessage.js b/packages/strapi-plugin-upload/admin/src/components/InputMedia/ErrorMessage.js new file mode 100644 index 0000000000..75e707834f --- /dev/null +++ b/packages/strapi-plugin-upload/admin/src/components/InputMedia/ErrorMessage.js @@ -0,0 +1,12 @@ +import styled from 'styled-components'; + +import { colors } from '@buffetjs/styles'; + +const ErrorMessage = styled.p` + font-size: 1.3rem !important; + padding-top: 5px; + margin: 0; + color: ${colors.darkOrange}; +`; + +export default ErrorMessage; diff --git a/packages/strapi-plugin-upload/admin/src/components/InputMedia/Wrapper.js b/packages/strapi-plugin-upload/admin/src/components/InputMedia/Wrapper.js index 919b7e874a..9f791d28a7 100644 --- a/packages/strapi-plugin-upload/admin/src/components/InputMedia/Wrapper.js +++ b/packages/strapi-plugin-upload/admin/src/components/InputMedia/Wrapper.js @@ -1,7 +1,11 @@ import styled from 'styled-components'; const Wrapper = styled.div` - margin-bottom: 2.3rem; + margin-bottom: ${({ hasError }) => (hasError ? '1.7rem' : '2.3rem')}; `; +Wrapper.defaultProps = { + hasError: false, +}; + export default Wrapper; diff --git a/packages/strapi-plugin-upload/admin/src/components/InputMedia/index.js b/packages/strapi-plugin-upload/admin/src/components/InputMedia/index.js index 214f88c16e..56abf09de8 100644 --- a/packages/strapi-plugin-upload/admin/src/components/InputMedia/index.js +++ b/packages/strapi-plugin-upload/admin/src/components/InputMedia/index.js @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { CopyToClipboard } from 'react-copy-to-clipboard'; -import { get } from 'lodash'; +import { get, isEmpty } from 'lodash'; import { prefixFileUrlWithBackendUrl } from 'strapi-helper-plugin'; import { getTrad, formatFileForEditing } from '../../utils'; @@ -16,8 +16,9 @@ import InputModalStepper from '../../containers/InputModalStepper'; import Name from './Name'; import Wrapper from './Wrapper'; import Input from '../Input'; +import ErrorMessage from './ErrorMessage'; -const InputMedia = ({ label, onChange, name, attribute, value, type }) => { +const InputMedia = ({ label, onChange, name, attribute, value, type, id, error }) => { const [modal, setModal] = useState({ isOpen: false, step: 'list', @@ -31,6 +32,8 @@ const InputMedia = ({ label, onChange, name, attribute, value, type }) => { const prefixedFileURL = fileURL ? prefixFileUrlWithBackendUrl(fileURL) : null; const displaySlidePagination = attribute.multiple && value.length > 1 ? ` (${fileToDisplay + 1}/${value.length})` : ''; + const inputId = id || name; + const errorId = `error-${inputId}`; useEffect(() => { setFileToDisplay(0); @@ -104,7 +107,7 @@ const InputMedia = ({ label, onChange, name, attribute, value, type }) => { }; return ( - + {`${label}${displaySlidePagination}`} @@ -166,6 +169,7 @@ const InputMedia = ({ label, onChange, name, attribute, value, type }) => { allowedTypes={attribute.allowedTypes} /> )} + {error && {error}} ); }; @@ -177,6 +181,8 @@ InputMedia.propTypes = { required: PropTypes.bool, type: PropTypes.string, }).isRequired, + error: PropTypes.string, + id: PropTypes.string, label: PropTypes.string, name: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, @@ -184,6 +190,8 @@ InputMedia.propTypes = { value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), }; InputMedia.defaultProps = { + id: null, + error: null, label: '', value: null, };