Merge branch 'master' into admin-russian-locale-fixes

This commit is contained in:
Jim LAURIE 2019-01-15 20:29:21 +01:00 committed by GitHub
commit 712e997c54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 220 additions and 75 deletions

View File

@ -2,18 +2,26 @@
<!-- Uncomment the correct contribution type. !--> <!-- Uncomment the correct contribution type. !-->
My PR is a: **My PR is a:**
- [ ] 💥 Breaking change - [ ] 💥 Breaking change
- [ ] 🐛 Bug fix #issueNumber - [ ] 🐛 Bug fix #issueNumber
- [ ] 💅 Enhancement - [ ] 💅 Enhancement
- [ ] 🚀 New feature - [ ] 🚀 New feature
Main update on the: **Main update on the:**
- [ ] Admin - [ ] Admin
- [ ] Documentation - [ ] Documentation
- [ ] Framework - [ ] Framework
- [ ] Plugin - [ ] Plugin
<!-- Please note that all databases should be tested and confirmed to be working prior to the PR being merged. -->
**Manual testing done on the follow databases:**
- [ ] Not applicable
- [ ] MongoDB
- [ ] MySQL
- [ ] Postgres
<!-- Write a short description of what your PR does and link the concerned issues of your update. --> <!-- Write a short description of what your PR does and link the concerned issues of your update. -->
**Description:**
<!-- ⚠️ Please link issue(s) you close / fix by using GitHub keywords https://help.github.com/articles/closing-issues-using-keywords/ !--> <!-- ⚠️ Please link issue(s) you close / fix by using GitHub keywords https://help.github.com/articles/closing-issues-using-keywords/ !-->

View File

@ -57,7 +57,7 @@ Node:
* NodeJS >= 10.x * NodeJS >= 10.x
* NPM >= 6.x * NPM >= 6.x
**Please note that right now Node 11 is not Officially supported, and the current Node LTS (v10) should be used.** **Please note that right now Node 11 is not supported, and the current Node LTS (v10) should be used.**
Database: Database:
* MongoDB >= 3.x * MongoDB >= 3.x
@ -71,8 +71,8 @@ Database:
npm install strapi@alpha -g npm install strapi@alpha -g
```` ````
**We recommend to use the latest version of Strapi to start your new project**. **We recommend always using the latest version of Strapi to start your new project**.
Some breaking changes might happen, new releases are shipped every two weeks to fix/enhance the product. As this project is currently in Alpha, some breaking changes may occur. New releases are shipped every two weeks to fix/enhance the project.
#### 🏗 Create a new project #### 🏗 Create a new project
@ -80,7 +80,7 @@ Some breaking changes might happen, new releases are shipped every two weeks to
strapi new my-project strapi new my-project
``` ```
It will generate a brand new project with the default features (authentication, permissions, content management, content type builder & file upload). This command will generate a brand new project with the default features (authentication, permissions, content management, content type builder & file upload).
#### 🚀 Start your project #### 🚀 Start your project
@ -109,8 +109,7 @@ Be aware that one of the content type builder won't work due to the writing file
## Features ## Features
- **Modern Admin Panel:** - **Modern Admin Panel:** Elegant, entirely customizable and fully extensible admin panel.
Elegant, entirely customizable and fully extensible admin panel.
- **Secure by default:** Reusable policies, CSRF, CORS, P3P, Xframe, XSS, and more. - **Secure by default:** Reusable policies, CSRF, CORS, P3P, Xframe, XSS, and more.
- **Plugins Oriented:** Install auth system, content management, custom plugins, and more, in seconds. - **Plugins Oriented:** Install auth system, content management, custom plugins, and more, in seconds.
- **Blazing Fast:** Built on top of Node.js, Strapi delivers amazing performances. - **Blazing Fast:** Built on top of Node.js, Strapi delivers amazing performances.
@ -133,7 +132,7 @@ For more information on the upcoming version, please take a look to our [ROADMAP
For general help using Strapi, please refer to [the official Strapi documentation](https://strapi.io/documentation/). For additional help, you can use one of this channel to ask question: For general help using Strapi, please refer to [the official Strapi documentation](https://strapi.io/documentation/). For additional help, you can use one of this channel to ask question:
- [StackOverflow](http://stackoverflow.com/questions/tagged/strapi) - [StackOverflow](http://stackoverflow.com/questions/tagged/strapi)
- [Slack](http://slack.strapi.io) (highly recommended for realtime support) - [Slack](http://slack.strapi.io) (highly recommended for faster support)
- [GitHub](https://github.com/strapi/strapi) - [GitHub](https://github.com/strapi/strapi)
- [Twitter](https://twitter.com/strapijs) - [Twitter](https://twitter.com/strapijs)
- [Facebook](https://www.facebook.com/Strapi-616063331867161). - [Facebook](https://www.facebook.com/Strapi-616063331867161).

View File

@ -28,9 +28,9 @@ npm install strapi@alpha -g
If you encounter npm permissions issues, [change the permissions to npm default directory](https://docs.npmjs.com/getting-started/fixing-npm-permissions#option-1-change-the-permission-to-npms-default-directory). If you encounter npm permissions issues, [change the permissions to npm default directory](https://docs.npmjs.com/getting-started/fixing-npm-permissions#option-1-change-the-permission-to-npms-default-directory).
::: :::
It takes about 20 seconds with a good Internet connection. You can take a coffee ☕️ if you have a slow one. It takes about 20 seconds with a good Internet connection. You can take a coffee ☕️ break if your internet is slow.
Having troubles during the installation? Check if someone already had the [same issue](https://github.com/strapi/strapi/issues). If not, please [post one](https://github.com/strapi/strapi/issues/new). Having troubles during the installation? Check if someone already had the [same issue](https://github.com/strapi/strapi/issues). If not, please [submit an issue](https://github.com/strapi/strapi/issues/new).
## Check installation ## Check installation

View File

@ -21,6 +21,22 @@ Update the `production` settings with the IP and domain name where the project w
In case your database is not running on the same server, make sure that the environment of your production In case your database is not running on the same server, make sure that the environment of your production
database (`./config/environments/production/database.json`) is set properly. database (`./config/environments/production/database.json`) is set properly.
If you are passing a number of configuration item values via environment variables which is always encouraged for production environment to keep application stateless, checkout the section for [Dynamic Configuration](../configurations/configurations.md#dynamic-configurations). Here is a hint on how to do it for production, for the configuration mentioned above:
**Path —** `./config/environments/production/server.json`.
```js
{
"host": "${process.env.APP_HOST || '127.0.0.1'}"
"port": "${process.env.NODE_PORT || 1337}",
"autoReload": {
"enabled": false
},
"admin": {
"path": "/dashboard" // We highly recommend to change the default `/admin` path for security reasons.
}
}
```
**⚠️ If you changed the path to access to the administration, the step #2 is required.** **⚠️ If you changed the path to access to the administration, the step #2 is required.**
#### #2 - Setup (optional) #### #2 - Setup (optional)

View File

@ -82,7 +82,7 @@ Requests system can be implemented in custom code sections.
### Extracting requests filters ### Extracting requests filters
To extract the filters from an JavaScript object or a request, you need to call the [`strapi.utils.models.convertParams` helper](../api-reference/reference.md#strapiutils). To extract the filters from a JavaScript object or a request, you need to call the [`strapi.utils.models.convertParams` helper](../api-reference/reference.md#strapiutils).
::: note ::: note
The returned objects are formatted according to the ORM used by the model. The returned objects are formatted according to the ORM used by the model.

View File

@ -194,7 +194,7 @@ You can also apply different parameters to the query to make more complex querie
- `<field>_lt`: Lower than. - `<field>_lt`: Lower than.
- `<field>_lte`: Lower than or equal to. - `<field>_lte`: Lower than or equal to.
- `<field>_gt`: Greater than. - `<field>_gt`: Greater than.
- `<field>_gte`: Lower than or equal to. - `<field>_gte`: Greater than or equal to.
- `<field>_contains`: Contains. - `<field>_contains`: Contains.
- `<field>_containss`: Contains sensitive. - `<field>_containss`: Contains sensitive.

View File

@ -27,6 +27,7 @@ The info key on the model-json states information about the model. This informat
The options key on the model-json states. The options key on the model-json states.
- `idAttribute`: This tells the model which attribute to expect as the unique identifier for each database row (typically an auto-incrementing primary key named 'id'). _Only valid for strapi-hook-bookshelf_ - `idAttribute`: This tells the model which attribute to expect as the unique identifier for each database row (typically an auto-incrementing primary key named 'id'). _Only valid for strapi-hook-bookshelf_
- `idAttributeType`: Data type of `idAttribute`, accepted list of value bellow. _Only valid for strapi-hook-bookshelf_ - `idAttributeType`: Data type of `idAttribute`, accepted list of value bellow. _Only valid for strapi-hook-bookshelf_
- `timestamps`: This tells the model which attributes to use for timestamps. Accepts either `boolean` or `Array` of strings where frist element is create data and second elemtent is update date. Default value when set to `true` for Bookshelf is `["created_at", "updated_at"]` and for MongoDB is `["createdAt", "updatedAt"]`.
## Define the attributes ## Define the attributes
@ -56,6 +57,7 @@ If you're using SQL databases, you should use the native SQL constraints to appl
- `required` (boolean) — if true adds a required validator for this property. - `required` (boolean) — if true adds a required validator for this property.
- `unique` (boolean) — whether to define a unique index on this property. - `unique` (boolean) — whether to define a unique index on this property.
- `index` (boolean) — adds an index on this property, this will create a [single field index](https://docs.mongodb.com/manual/indexes/#single-field) that will run in the background (*only supported by MongoDB*).
- `max` (integer) — checks if the value is greater than or equal to the given minimum. - `max` (integer) — checks if the value is greater than or equal to the given minimum.
- `min` (integer) — checks if the value is less than or equal to the given maximum. - `min` (integer) — checks if the value is less than or equal to the given maximum.
@ -100,7 +102,8 @@ To improve the Developer eXperience when developing or using the administration
"age": { "age": {
"type": "integer", "type": "integer",
"min": 18, "min": 18,
"max": 99 "max": 99,
"index": true
}, },
"birthday": { "birthday": {
"type": "date" "type": "date"

View File

@ -8,6 +8,8 @@ import React from 'react';
import { defineMessages, FormattedMessage } from 'react-intl'; import { defineMessages, FormattedMessage } from 'react-intl';
import { PropTypes } from 'prop-types'; import { PropTypes } from 'prop-types';
import LeftMenuLink from 'components/LeftMenuLink';
import styles from './styles.scss'; import styles from './styles.scss';
import messages from './messages.json'; import messages from './messages.json';
defineMessages(messages); defineMessages(messages);
@ -15,8 +17,22 @@ defineMessages(messages);
function LeftMenuFooter({ version }) { // eslint-disable-line react/prefer-stateless-function function LeftMenuFooter({ version }) { // eslint-disable-line react/prefer-stateless-function
return ( return (
<div className={styles.leftMenuFooter}> <div className={styles.leftMenuFooter}>
<FormattedMessage {...messages.poweredBy} /> <ul className={styles.list}>
<a href={`https://github.com/strapi/strapi/releases/tag/v${version}`} target="_blank">v{version}</a> <LeftMenuLink
icon="book"
label={messages.documentation.id}
destination="https://strapi.io/documentation"
/>
<LeftMenuLink
icon="question-circle"
label={messages.help.id}
destination="https://strapi.io/help"
/>
</ul>
<div className={styles.poweredBy}>
<FormattedMessage {...messages.poweredBy} />
<a href="https://strapi.io" target="_blank">Strapi</a> <a href={`https://github.com/strapi/strapi/releases/tag/v${version}`} target="_blank">v{version}</a>
</div>
</div> </div>
); );
} }

View File

@ -1,4 +1,12 @@
{ {
"documentation": {
"id": "app.components.LeftMenuFooter.documentation",
"defaultMessage": "Documentation"
},
"help": {
"id": "app.components.LeftMenuFooter.help",
"defaultMessage": "Help"
},
"poweredBy": { "poweredBy": {
"id": "app.components.LeftMenuFooter.poweredBy", "id": "app.components.LeftMenuFooter.poweredBy",
"defaultMessage": "Proudly powered by " "defaultMessage": "Proudly powered by "

View File

@ -4,26 +4,27 @@
.leftMenuFooter { /* stylelint-disable */ .leftMenuFooter { /* stylelint-disable */
position: absolute; position: absolute;
width: 100%; width: 100%;
display: flex; background: $left-menu-bg;
justify-content: space-between; bottom: 0;
}
.list {
list-style: none;
padding: 0;
margin-bottom: 0;
}
.poweredBy {
width: 100%;
bottom: 0; bottom: 0;
height: 3rem; height: 3rem;
padding-left: 15px; padding-left: 15px;
padding-right: 15px; padding-right: 15px;
line-height: 3rem; line-height: 3rem;
font-family: 'Lato';
background-color: rgba(255, 255, 255, .02); background-color: rgba(255, 255, 255, .02);
font-size: 1rem; font-size: 1rem;
font-weight: 400; font-weight: 400;
letter-spacing: 0.05rem; letter-spacing: 0.05rem;
vertical-align: middle; vertical-align: middle;
color: $strapi-gray-light; color: $strapi-gray-light;
a {
color: #0097f7;
}
select{
outline: none;
}
} }

View File

@ -47,8 +47,22 @@ class LeftMenuLink extends React.Component {
<span className={styles.linkLabel}>{this.props.label}</span> <span className={styles.linkLabel}>{this.props.label}</span>
); );
return ( // Icon.
<li className={styles.item}> const icon = <i className={`${styles.linkIcon} fa-${this.props.icon} fa`} />;
// Create external or internal link.
const link = this.props.destination.includes('http')
? (
<a
className={`${styles.link} ${isLinkActive ? styles.linkActive : ''}`}
href={this.props.destination}
target="_blank"
>
{icon}
{content}
</a>
)
: (
<Link <Link
className={`${styles.link} ${isLinkActive ? styles.linkActive : ''}`} className={`${styles.link} ${isLinkActive ? styles.linkActive : ''}`}
to={{ to={{
@ -56,9 +70,14 @@ class LeftMenuLink extends React.Component {
search: this.props.source ? `?source=${this.props.source}` : '', search: this.props.source ? `?source=${this.props.source}` : '',
}} }}
> >
<i className={`${styles.linkIcon} fa-${this.props.icon} fa`} /> {icon}
{content} {content}
</Link> </Link>
);
return (
<li className={styles.item}>
{link}
{plugin} {plugin}
</li> </li>
); );

View File

@ -3,6 +3,7 @@
.leftMenuLinkContainer { /* stylelint-ignore */ .leftMenuLinkContainer { /* stylelint-ignore */
padding-top: .6rem; padding-top: .6rem;
padding-bottom: 10.2rem; // LeftMenuFooter height
position: absolute; position: absolute;
top: 60px; top: 60px;
right: 0; right: 0;

View File

@ -5,6 +5,7 @@
*/ */
import React from 'react'; import React from 'react';
import { FormattedMessage } from 'react-intl';
import { get } from 'lodash'; import { get } from 'lodash';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { ButtonDropdown, DropdownItem, DropdownMenu, DropdownToggle } from 'reactstrap'; import { ButtonDropdown, DropdownItem, DropdownMenu, DropdownToggle } from 'reactstrap';
@ -40,10 +41,10 @@ class Logout extends React.Component { // eslint-disable-line react/prefer-state
</DropdownToggle> </DropdownToggle>
<DropdownMenu className={styles.dropDownContent}> <DropdownMenu className={styles.dropDownContent}>
<DropdownItem onClick={this.handleGoTo} className={styles.item}> <DropdownItem onClick={this.handleGoTo} className={styles.item}>
Profile <FormattedMessage id="app.components.Logout.profile" />
</DropdownItem> </DropdownItem>
<DropdownItem onClick={this.handleLogout}> <DropdownItem onClick={this.handleLogout}>
Logout <FormattedMessage id="app.components.Logout.logout" />
<i className="fa fa-sign-out" /> <i className="fa fa-sign-out" />
</DropdownItem> </DropdownItem>
</DropdownMenu> </DropdownMenu>

View File

@ -256,6 +256,7 @@ AdminPage.propTypes = {
blockApp: PropTypes.bool.isRequired, blockApp: PropTypes.bool.isRequired,
disableGlobalOverlayBlocker: PropTypes.func.isRequired, disableGlobalOverlayBlocker: PropTypes.func.isRequired,
enableGlobalOverlayBlocker: PropTypes.func.isRequired, enableGlobalOverlayBlocker: PropTypes.func.isRequired,
getAdminData: PropTypes.func.isRequired,
hasUserPlugin: PropTypes.bool, hasUserPlugin: PropTypes.bool,
history: PropTypes.object.isRequired, history: PropTypes.object.isRequired,
isAppLoading: PropTypes.bool, isAppLoading: PropTypes.bool,

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "قائمة الإضافيات المثبتة في المشروع.", "app.components.ListPluginsPage.description": "قائمة الإضافيات المثبتة في المشروع.",
"app.components.ListPluginsPage.helmet.title": "قائمة الإضافات", "app.components.ListPluginsPage.helmet.title": "قائمة الإضافات",
"app.components.ListPluginsPage.title": "الإضافات", "app.components.ListPluginsPage.title": "الإضافات",
"app.components.Logout.profile": "الملف الشخصي",
"app.components.Logout.logout": "الخروج",
"app.components.NotFoundPage.back": "العودة للرئيسية", "app.components.NotFoundPage.back": "العودة للرئيسية",
"app.components.NotFoundPage.description": "لا يوجد", "app.components.NotFoundPage.description": "لا يوجد",
"app.components.Official": "الرسمية", "app.components.Official": "الرسمية",

View File

@ -75,6 +75,8 @@
"app.components.LeftMenuLinkContainer.plugins": "Plugins", "app.components.LeftMenuLinkContainer.plugins": "Plugins",
"app.components.ListPluginsPage.description": "Liste aller im Projekt installierten Plugins.", "app.components.ListPluginsPage.description": "Liste aller im Projekt installierten Plugins.",
"app.components.ListPluginsPage.helmet.title": "Plugins anzeigen", "app.components.ListPluginsPage.helmet.title": "Plugins anzeigen",
"app.components.Logout.profile": "Profil",
"app.components.Logout.logout": "Ausloggen",
"app.components.ListPluginsPage.title": "Plugins", "app.components.ListPluginsPage.title": "Plugins",
"app.components.NotFoundPage.back": "Zurück zur Homepage", "app.components.NotFoundPage.back": "Zurück zur Homepage",
"app.components.NotFoundPage.description": "Nicht gefunden", "app.components.NotFoundPage.description": "Nicht gefunden",

View File

@ -65,6 +65,8 @@
"app.components.InstallPluginPopup.navLink.faq": "faq", "app.components.InstallPluginPopup.navLink.faq": "faq",
"app.components.InstallPluginPopup.navLink.screenshots": "Screenshots", "app.components.InstallPluginPopup.navLink.screenshots": "Screenshots",
"app.components.InstallPluginPopup.noDescription": "No description available", "app.components.InstallPluginPopup.noDescription": "No description available",
"app.components.LeftMenuFooter.documentation": "Documentation",
"app.components.LeftMenuFooter.help": "Help",
"app.components.LeftMenuFooter.poweredBy": "Powered by ", "app.components.LeftMenuFooter.poweredBy": "Powered by ",
"app.components.LeftMenuLinkContainer.configuration": "Configurations", "app.components.LeftMenuLinkContainer.configuration": "Configurations",
"app.components.LeftMenuLinkContainer.general": "General", "app.components.LeftMenuLinkContainer.general": "General",
@ -75,6 +77,8 @@
"app.components.ListPluginsPage.description": "List of the installed plugins in the project.", "app.components.ListPluginsPage.description": "List of the installed plugins in the project.",
"app.components.ListPluginsPage.helmet.title": "List plugins", "app.components.ListPluginsPage.helmet.title": "List plugins",
"app.components.ListPluginsPage.title": "Plugins", "app.components.ListPluginsPage.title": "Plugins",
"app.components.Logout.profile": "Profile",
"app.components.Logout.logout": "Logout",
"app.components.NotFoundPage.back": "Back to homepage", "app.components.NotFoundPage.back": "Back to homepage",
"app.components.NotFoundPage.description": "Not Found", "app.components.NotFoundPage.description": "Not Found",
"app.components.Official": "Official", "app.components.Official": "Official",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "Lista de los plugins instalados en el proyecto.", "app.components.ListPluginsPage.description": "Lista de los plugins instalados en el proyecto.",
"app.components.ListPluginsPage.helmet.title": "Lista de plugins", "app.components.ListPluginsPage.helmet.title": "Lista de plugins",
"app.components.ListPluginsPage.title": "Plugins", "app.components.ListPluginsPage.title": "Plugins",
"app.components.Logout.profile": "Perfil",
"app.components.Logout.logout": "Cerrar sesión",
"app.components.NotFoundPage.back": "Volver a la página de inicio", "app.components.NotFoundPage.back": "Volver a la página de inicio",
"app.components.NotFoundPage.description": "No encontrado", "app.components.NotFoundPage.description": "No encontrado",
"app.components.Official": "Oficial", "app.components.Official": "Oficial",

View File

@ -66,6 +66,8 @@
"app.components.InstallPluginPopup.navLink.faq": "FAQ", "app.components.InstallPluginPopup.navLink.faq": "FAQ",
"app.components.InstallPluginPopup.navLink.screenshots": "Captures d'écran", "app.components.InstallPluginPopup.navLink.screenshots": "Captures d'écran",
"app.components.InstallPluginPopup.noDescription": "Aucune description disponible", "app.components.InstallPluginPopup.noDescription": "Aucune description disponible",
"app.components.LeftMenuFooter.documentation": "Documentation",
"app.components.LeftMenuFooter.help": "Aide",
"app.components.LeftMenuFooter.poweredBy": "Propulsé par ", "app.components.LeftMenuFooter.poweredBy": "Propulsé par ",
"app.components.LeftMenuLinkContainer.configuration": "Configurations", "app.components.LeftMenuLinkContainer.configuration": "Configurations",
"app.components.LeftMenuLinkContainer.general": "Général", "app.components.LeftMenuLinkContainer.general": "Général",
@ -75,6 +77,8 @@
"app.components.LeftMenuLinkContainer.plugins": "Plugins", "app.components.LeftMenuLinkContainer.plugins": "Plugins",
"app.components.ListPluginsPage.description": "Liste des plugins installés dans le projet.", "app.components.ListPluginsPage.description": "Liste des plugins installés dans le projet.",
"app.components.ListPluginsPage.helmet.title": "List plugins", "app.components.ListPluginsPage.helmet.title": "List plugins",
"app.components.Logout.profile": "Profil",
"app.components.Logout.logout": "Connectez - Out",
"app.components.ListPluginsPage.title": "Plugins", "app.components.ListPluginsPage.title": "Plugins",
"app.components.NotFoundPage.back": "Retourner à la page d'accueil", "app.components.NotFoundPage.back": "Retourner à la page d'accueil",
"app.components.NotFoundPage.description": "Page introuvable", "app.components.NotFoundPage.description": "Page introuvable",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "Lista dei plugin installati nel progetto.", "app.components.ListPluginsPage.description": "Lista dei plugin installati nel progetto.",
"app.components.ListPluginsPage.helmet.title": "Lista plugin", "app.components.ListPluginsPage.helmet.title": "Lista plugin",
"app.components.ListPluginsPage.title": "Plugins", "app.components.ListPluginsPage.title": "Plugins",
"app.components.Logout.profile": "Profilo",
"app.components.Logout.logout": "Disconnettersi",
"app.components.NotFoundPage.back": "Torna alla home", "app.components.NotFoundPage.back": "Torna alla home",
"app.components.NotFoundPage.description": "Non trovato", "app.components.NotFoundPage.description": "Non trovato",
"app.components.Official": "Ufficiale", "app.components.Official": "Ufficiale",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "このプロジェクトでインストールされたプラグイン一覧", "app.components.ListPluginsPage.description": "このプロジェクトでインストールされたプラグイン一覧",
"app.components.ListPluginsPage.helmet.title": "プラグイン一覧", "app.components.ListPluginsPage.helmet.title": "プラグイン一覧",
"app.components.ListPluginsPage.title": "プラグイン", "app.components.ListPluginsPage.title": "プラグイン",
"app.components.Logout.profile": "プロフィール",
"app.components.Logout.logout": "ログアウト",
"app.components.NotFoundPage.back": "ホームページに戻る", "app.components.NotFoundPage.back": "ホームページに戻る",
"app.components.NotFoundPage.description": "見つかりません", "app.components.NotFoundPage.description": "見つかりません",
"app.components.Official": "オフィシャル", "app.components.Official": "オフィシャル",

View File

@ -74,6 +74,8 @@
"app.components.ListPluginsPage.description": "이 프로젝트에 설치된 플러그인 목록입니다.", "app.components.ListPluginsPage.description": "이 프로젝트에 설치된 플러그인 목록입니다.",
"app.components.ListPluginsPage.helmet.title": "플러그인 목록", "app.components.ListPluginsPage.helmet.title": "플러그인 목록",
"app.components.ListPluginsPage.title": "플러그인", "app.components.ListPluginsPage.title": "플러그인",
"app.components.Logout.profile": "옆모습",
"app.components.Logout.logout": "로그 아웃",
"app.components.NotFoundPage.back": "홈으로 돌아가기", "app.components.NotFoundPage.back": "홈으로 돌아가기",
"app.components.NotFoundPage.description": "찾을 수 없는 페이지입니다.", "app.components.NotFoundPage.description": "찾을 수 없는 페이지입니다.",
"app.components.Official": "공식", "app.components.Official": "공식",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "Lijst van alle plugins voor dit project", "app.components.ListPluginsPage.description": "Lijst van alle plugins voor dit project",
"app.components.ListPluginsPage.helmet.title": "Alle extensies", "app.components.ListPluginsPage.helmet.title": "Alle extensies",
"app.components.ListPluginsPage.title": "Extensies", "app.components.ListPluginsPage.title": "Extensies",
"app.components.Logout.profile": "Profil",
"app.components.Logout.logout": "Log ud",
"app.components.NotFoundPage.back": "Terug naar home pagina", "app.components.NotFoundPage.back": "Terug naar home pagina",
"app.components.NotFoundPage.description": "Niets gevonden", "app.components.NotFoundPage.description": "Niets gevonden",
"app.components.Official": "Officieel", "app.components.Official": "Officieel",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "Lista zainstalowanych wtyczek w projekcie.", "app.components.ListPluginsPage.description": "Lista zainstalowanych wtyczek w projekcie.",
"app.components.ListPluginsPage.helmet.title": "Lista wtyczek", "app.components.ListPluginsPage.helmet.title": "Lista wtyczek",
"app.components.ListPluginsPage.title": "Wtyczki", "app.components.ListPluginsPage.title": "Wtyczki",
"app.components.Logout.profile": "Profil",
"app.components.Logout.logout": "Wyloguj",
"app.components.NotFoundPage.back": "Powrót do strony głównej", "app.components.NotFoundPage.back": "Powrót do strony głównej",
"app.components.NotFoundPage.description": "Nie znaleziono", "app.components.NotFoundPage.description": "Nie znaleziono",
"app.components.Official": "Oficjalna", "app.components.Official": "Oficjalna",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "Lista de extensões instaladas no projeto.", "app.components.ListPluginsPage.description": "Lista de extensões instaladas no projeto.",
"app.components.ListPluginsPage.helmet.title": "Lista de extensões", "app.components.ListPluginsPage.helmet.title": "Lista de extensões",
"app.components.ListPluginsPage.title": "Extensões", "app.components.ListPluginsPage.title": "Extensões",
"app.components.Logout.profile": "Perfil",
"app.components.Logout.logout": "Sair",
"app.components.NotFoundPage.back": "Voltar à página inicial", "app.components.NotFoundPage.back": "Voltar à página inicial",
"app.components.NotFoundPage.description": "Não encontrado", "app.components.NotFoundPage.description": "Não encontrado",
"app.components.Official": "Oficial", "app.components.Official": "Oficial",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "Lista de extensões instaladas no projecto.", "app.components.ListPluginsPage.description": "Lista de extensões instaladas no projecto.",
"app.components.ListPluginsPage.helmet.title": "Lista de extensões", "app.components.ListPluginsPage.helmet.title": "Lista de extensões",
"app.components.ListPluginsPage.title": "Extensões", "app.components.ListPluginsPage.title": "Extensões",
"app.components.Logout.profile": "Perfil",
"app.components.Logout.logout": "Sair",
"app.components.NotFoundPage.back": "Voltar à página inicial", "app.components.NotFoundPage.back": "Voltar à página inicial",
"app.components.NotFoundPage.description": "Não encontrado", "app.components.NotFoundPage.description": "Não encontrado",
"app.components.Official": "Oficial", "app.components.Official": "Oficial",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "Список установленных плагинов.", "app.components.ListPluginsPage.description": "Список установленных плагинов.",
"app.components.ListPluginsPage.helmet.title": "Список плагинов", "app.components.ListPluginsPage.helmet.title": "Список плагинов",
"app.components.ListPluginsPage.title": "Плагины", "app.components.ListPluginsPage.title": "Плагины",
"app.components.Logout.profile": "Профиль",
"app.components.Logout.logout": "Выйти",
"app.components.NotFoundPage.back": "Вернуться на главную", "app.components.NotFoundPage.back": "Вернуться на главную",
"app.components.NotFoundPage.description": "Не найдено", "app.components.NotFoundPage.description": "Не найдено",
"app.components.Official": "Официальный", "app.components.Official": "Официальный",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "Projedeki yüklenen eklentiler.", "app.components.ListPluginsPage.description": "Projedeki yüklenen eklentiler.",
"app.components.ListPluginsPage.helmet.title": "Eklenti Listesi", "app.components.ListPluginsPage.helmet.title": "Eklenti Listesi",
"app.components.ListPluginsPage.title": "Etklentiler", "app.components.ListPluginsPage.title": "Etklentiler",
"app.components.Logout.profile": "Profil",
"app.components.Logout.logout": ıkış Yap",
"app.components.NotFoundPage.back": "Anasayfaya geri dön", "app.components.NotFoundPage.back": "Anasayfaya geri dön",
"app.components.NotFoundPage.description": "Bulunamadı", "app.components.NotFoundPage.description": "Bulunamadı",
"app.components.Official": "Resmi", "app.components.Official": "Resmi",

View File

@ -72,6 +72,8 @@
"app.components.ListPluginsPage.description": "项目中已安装的插件列表", "app.components.ListPluginsPage.description": "项目中已安装的插件列表",
"app.components.ListPluginsPage.helmet.title": "插件列表", "app.components.ListPluginsPage.helmet.title": "插件列表",
"app.components.ListPluginsPage.title": "插件", "app.components.ListPluginsPage.title": "插件",
"app.components.Logout.profile": "轮廓",
"app.components.Logout.logout": "登出",
"app.components.NotFoundPage.back": "返回主页", "app.components.NotFoundPage.back": "返回主页",
"app.components.NotFoundPage.description": "没有找到", "app.components.NotFoundPage.description": "没有找到",
"app.components.Official": "官方", "app.components.Official": "官方",

View File

@ -75,6 +75,8 @@
"app.components.ListPluginsPage.description": "這個專案安裝的擴充功能列表", "app.components.ListPluginsPage.description": "這個專案安裝的擴充功能列表",
"app.components.ListPluginsPage.helmet.title": "擴充功能列表", "app.components.ListPluginsPage.helmet.title": "擴充功能列表",
"app.components.ListPluginsPage.title": "擴充功能", "app.components.ListPluginsPage.title": "擴充功能",
"app.components.Logout.profile": "輪廓",
"app.components.Logout.logout": "登出",
"app.components.NotFoundPage.back": "回到主頁", "app.components.NotFoundPage.back": "回到主頁",
"app.components.NotFoundPage.description": "找不到此頁面", "app.components.NotFoundPage.description": "找不到此頁面",
"app.components.Official": "官方", "app.components.Official": "官方",

View File

@ -1,6 +1,7 @@
{ {
"host": "localhost", "host": "localhost",
"port": "${process.env.PORT || 1337}", "port": "${process.env.PORT || 1337}",
"production": true,
"proxy": { "proxy": {
"enabled": false "enabled": false
}, },

View File

@ -1,6 +1,7 @@
{ {
"host": "localhost", "host": "localhost",
"port": "${process.env.PORT || 1337}", "port": "${process.env.PORT || 1337}",
"production": true,
"proxy": { "proxy": {
"enabled": false "enabled": false
}, },

View File

@ -190,7 +190,7 @@ module.exports = (scope, cb) => {
default: _.get(scope.database, 'authenticationDatabase', undefined) default: _.get(scope.database, 'authenticationDatabase', undefined)
}, },
{ {
when: !hasDatabaseConfig && scope.client.database === 'mongo', when: !hasDatabaseConfig,
type: 'boolean', type: 'boolean',
name: 'ssl', name: 'ssl',
message: 'Enable SSL connection:', message: 'Enable SSL connection:',
@ -209,7 +209,11 @@ module.exports = (scope, cb) => {
scope.database.settings.username = answers.username; scope.database.settings.username = answers.username;
scope.database.settings.password = answers.password; scope.database.settings.password = answers.password;
scope.database.options.authenticationDatabase = answers.authenticationDatabase; scope.database.options.authenticationDatabase = answers.authenticationDatabase;
scope.database.options.ssl = _.toString(answers.ssl) === 'true'; if (scope.client.database === 'mongo') {
scope.database.options.ssl = _.toString(answers.ssl) === 'true';
} else {
scope.database.settings.ssl = _.toString(answers.ssl) === 'true';
}
console.log(); console.log();
console.log('⏳ Testing database connection...'); console.log('⏳ Testing database connection...');

View File

@ -15,7 +15,7 @@
"dependencies": { "dependencies": {
"enpeem": "^2.2.0", "enpeem": "^2.2.0",
"fs-extra": "^4.0.0", "fs-extra": "^4.0.0",
"inquirer": "^4.0.2", "inquirer": "^6.2.1",
"listr": "^0.14.1", "listr": "^0.14.1",
"lodash": "^4.17.5", "lodash": "^4.17.5",
"ora": "^2.1.0", "ora": "^2.1.0",

View File

@ -89,7 +89,7 @@ module.exports = function(strapi) {
// Register the final model for Bookshelf. // Register the final model for Bookshelf.
const loadedModel = _.assign({ const loadedModel = _.assign({
tableName: definition.collectionName, tableName: definition.collectionName,
hasTimestamps: _.get(definition, 'options.timestamps') === true, hasTimestamps: _.get(definition, 'options.timestamps', false),
idAttribute: _.get(definition, 'options.idAttribute', 'id'), idAttribute: _.get(definition, 'options.idAttribute', 'id'),
associations: [], associations: [],
defaults: Object.keys(definition.attributes).reduce((acc, current) => { defaults: Object.keys(definition.attributes).reduce((acc, current) => {
@ -100,7 +100,14 @@ module.exports = function(strapi) {
return acc; return acc;
}, {}) }, {})
}, definition.options); }, definition.options);
// Use default timestamp column names if value is `true`
if (_.get(loadedModel, 'hasTimestamps') === true) {
_.set(loadedModel, 'hasTimestamps', ['created_at', 'updated_at']);
}
// Use false for values other than `Boolean` or `Array`
if (!_.isArray(_.get(loadedModel, 'hasTimestamps')) && !_.isBoolean(_.get(loadedModel, 'hasTimestamps'))) {
_.set(loadedModel, 'hasTimestamps', false);
}
if (_.isString(_.get(connection, 'options.pivot_prefix'))) { if (_.isString(_.get(connection, 'options.pivot_prefix'))) {
loadedModel.toJSON = function(options = {}) { loadedModel.toJSON = function(options = {}) {
const { shallow = false, omitPivot = false } = options; const { shallow = false, omitPivot = false } = options;
@ -619,10 +626,10 @@ module.exports = function(strapi) {
// Add created_at and updated_at field if timestamp option is true // Add created_at and updated_at field if timestamp option is true
if (loadedModel.hasTimestamps) { if (loadedModel.hasTimestamps) {
definition.attributes['created_at'] = { definition.attributes[_.isString(loadedModel.hasTimestamps[0]) ? loadedModel.hasTimestamps[0] : 'created_at'] = {
type: 'timestamp' type: 'timestamp'
}; };
definition.attributes['updated_at'] = { definition.attributes[_.isString(loadedModel.hasTimestamps[1]) ? loadedModel.hasTimestamps[1] : 'updated_at'] = {
type: 'timestampUpdate' type: 'timestampUpdate'
}; };
} }
@ -701,8 +708,8 @@ module.exports = function(strapi) {
// Remove from attributes (auto handled by bookshlef and not displayed on ctb) // Remove from attributes (auto handled by bookshlef and not displayed on ctb)
if (loadedModel.hasTimestamps) { if (loadedModel.hasTimestamps) {
delete definition.attributes['created_at']; delete definition.attributes[_.isString(loadedModel.hasTimestamps[0]) ? loadedModel.hasTimestamps[0] : 'created_at'];
delete definition.attributes['updated_at']; delete definition.attributes[_.isString(loadedModel.hasTimestamps[1]) ? loadedModel.hasTimestamps[1] : 'updated_at'];
} }
resolve(); resolve();

View File

@ -17,7 +17,7 @@
"main": "./lib", "main": "./lib",
"dependencies": { "dependencies": {
"bookshelf": "^0.12.1", "bookshelf": "^0.12.1",
"inquirer": "^5.2.0", "inquirer": "^6.2.1",
"lodash": "^4.17.5", "lodash": "^4.17.5",
"pluralize": "^6.0.0", "pluralize": "^6.0.0",
"rimraf": "^2.6.2", "rimraf": "^2.6.2",

View File

@ -207,7 +207,16 @@ module.exports = function (strapi) {
}); });
}); });
collection.schema.set('timestamps', _.get(definition, 'options.timestamps') === true); // Use provided timestamps if the elemnets in the array are string else use default.
if (_.isArray(_.get(definition, 'options.timestamps'))) {
const timestamps = {
createdAt: _.isString(_.get(definition, 'options.timestamps[0]')) ? _.get(definition, 'options.timestamps[0]') : 'createdAt',
updatedAt: _.isString(_.get(definition, 'options.timestamps[1]')) ? _.get(definition, 'options.timestamps[1]') : 'updatedAt'
};
collection.schema.set('timestamps', timestamps);
} else {
collection.schema.set('timestamps', _.get(definition, 'options.timestamps') === true);
}
collection.schema.set('minimize', _.get(definition, 'options.minimize', false) === true); collection.schema.set('minimize', _.get(definition, 'options.minimize', false) === true);
collection.schema.options.toObject = collection.schema.options.toJSON = { collection.schema.options.toObject = collection.schema.options.toJSON = {

View File

@ -77,15 +77,10 @@ export function* submit() {
let shouldAddTranslationSuffix = false; let shouldAddTranslationSuffix = false;
// Remove the updated_at & created_at fields so it is updated correctly when using Postgres or MySQL db // Remove the updated_at & created_at fields so it is updated correctly when using Postgres or MySQL db
if (record.updated_at) { const timestamps = get(schema, ['models', currentModelName, 'options', 'timestamps'], null);
delete record.created_at; if (timestamps) {
delete record.updated_at; delete record[timestamps[0]];
} delete record[timestamps[1]];
// Remove the updatedAt & createdAt fields so it is updated correctly when using MongoDB
if (record.updatedAt) {
delete record.createdAt;
delete record.updatedAt;
} }
try { try {

View File

@ -17,6 +17,7 @@ const pickData = (model) => _.pick(model, [
'globalId', 'globalId',
'globalName', 'globalName',
'orm', 'orm',
'options.timestamps',
'loadedModel', 'loadedModel',
'primaryKey', 'primaryKey',
'associations' 'associations'
@ -84,6 +85,7 @@ module.exports = async cb => {
pageEntries: 10, pageEntries: 10,
defaultSort: model.primaryKey, defaultSort: model.primaryKey,
sort: 'ASC', sort: 'ASC',
options: model.options,
editDisplay: { editDisplay: {
availableFields: {}, availableFields: {},
fields: [], fields: [],
@ -330,8 +332,9 @@ module.exports = async cb => {
// Here we just need to add the data from the current schema Object // Here we just need to add the data from the current schema Object
apisToAdd.map(apiPath => { apisToAdd.map(apiPath => {
const api = _.get(schema.models, apiPath); const api = _.get(schema.models, apiPath);
const { search, filters, bulkActions, pageEntries } = _.get(prevSchema, 'generalSettings'); const { search, filters, bulkActions, pageEntries, options } = _.get(prevSchema, 'generalSettings');
_.set(api, 'options', options);
_.set(api, 'filters', filters); _.set(api, 'filters', filters);
_.set(api, 'search', search); _.set(api, 'search', search);
_.set(api, 'bulkActions', bulkActions); _.set(api, 'bulkActions', bulkActions);

View File

@ -266,8 +266,10 @@ module.exports = {
resolvers, resolvers,
}); });
// Write schema. if (!strapi.config.currentEnvironment.server.production) {
this.writeGenerateSchema(graphql.printSchema(schema)); // Write schema.
this.writeGenerateSchema(graphql.printSchema(schema));
}
// Remove custom scaler (like Upload); // Remove custom scaler (like Upload);
typeDefs = Types.removeCustomScalar(typeDefs, resolvers); typeDefs = Types.removeCustomScalar(typeDefs, resolvers);

View File

@ -111,6 +111,14 @@
"policies": [] "policies": []
} }
}, },
{
"method": "GET",
"path": "/permissions",
"handler": "UsersPermissions.getPermissions",
"config": {
"policies": []
}
},
{ {
"method": "GET", "method": "GET",
"path": "/providers", "path": "/providers",

View File

@ -45,11 +45,9 @@ exports.connect = (provider, query) => {
} }
try { try {
const users = await strapi.query('user', 'users-permissions').find({ const users = await strapi.query('user', 'users-permissions').find(strapi.utils.models.convertParams('user', {
where: { email: profile.email
email: profile.email }));
}
});
const advanced = await strapi.store({ const advanced = await strapi.store({
environment: '', environment: '',

View File

@ -438,8 +438,10 @@ module.exports = {
try { try {
// Disable auto-reload. // Disable auto-reload.
strapi.reload.isWatching = false; strapi.reload.isWatching = false;
// Rewrite actions.json file. if (!strapi.config.currentEnvironment.server.production) {
fs.writeFileSync(actionsPath, JSON.stringify({ actions: data }), 'utf8'); // Rewrite actions.json file.
fs.writeFileSync(actionsPath, JSON.stringify({ actions: data }), 'utf8');
}
// Set value to AST to avoid restart. // Set value to AST to avoid restart.
_.set(strapi.plugins['users-permissions'], 'config.actions', data); _.set(strapi.plugins['users-permissions'], 'config.actions', data);
// Disable auto-reload. // Disable auto-reload.

View File

@ -88,12 +88,18 @@ module.exports = async function() {
return; return;
} }
const existBuildPath = await fs.pathExists(buildPath);
if (strapi.config.currentEnvironment.server.production && existBuildPath) {
return;
} else if (strapi.config.currentEnvironment.server.production && !existBuildPath) {
console.log('The plugins.json file is missing and the front-end cannot work without it. Please, create it first at development environment.');
}
// arrange system directories // arrange system directories
await Promise.all([ await Promise.all([
fs.remove(sourcePath), fs.remove(sourcePath),
(async () => { (async () => {
const existBuildPath = await fs.pathExists(buildPath);
if (existBuildPath) { if (existBuildPath) {
await fs.remove(buildPath); await fs.remove(buildPath);
} else { } else {

View File

@ -37,7 +37,7 @@ module.exports = strapi => {
ctx.status = error.status || 500; ctx.status = error.status || 500;
ctx.body = _.get(ctx.body, 'isBoom') ctx.body = _.get(ctx.body, 'isBoom')
? ctx.body || error && error.message ? ctx.body || error && error.message
: Boom.wrap(error, ctx.status, ctx.body || error.message); : Boom.wrap(error, ctx.status);
} }
if (ctx.response.headers.location) { if (ctx.response.headers.location) {