Merge branch 'master' into testLinterInCI

This commit is contained in:
Jim LAURIE 2018-11-01 17:19:56 +01:00 committed by GitHub
commit 6ed7f494ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 152 additions and 14 deletions

View File

@ -30,7 +30,7 @@ If you send a pull request, please do it against the `master` branch. We are dev
***
## Setup Development Environment
To facilitate the contribution, we drastically reduce the amount of commands necessary to install the entire development environment. First of all, you need to check if you're using the recommended versions of Node.js (v8) and npm (v5).
To facilitate the contribution, we drastically reduce the amount of commands necessary to install the entire development environment. First of all, you need to check if you're using the [required versions of Node.js and npm](https://strapi.io/documentation/3.x.x/getting-started/installation.html#requirements)
Then, please follow the instructions below:

View File

@ -86,6 +86,7 @@ module.exports = {
'/3.x.x/guides/responses',
'/3.x.x/guides/routing',
'/3.x.x/guides/services',
'/3.x.x/guides/webhooks',
],
},
{

View File

@ -182,7 +182,7 @@ strapi generate:plugin <name>
Example: `strapi generate:plugin user` will create the plugin at `./plugins/user`.
Please refer to the [plugin develoment documentation](../plugin-development/quick-start.md) to know more.
Please refer to the [plugin development documentation](../plugin-development/quick-start.md) to know more.
***

View File

@ -0,0 +1,121 @@
# Webhooks
If you are using a static website generator (or framework with build option) with Strapi (Gatsby, Nuxt, Next, etc.) it is necessary to rebuild it when the content is updated in Strapi. In a Headless CMS, this is typically called a [Webhook feature](https://strapi.io/marketplace/webhooks). Unfortunately it is not available yet in Strapi even if [it has been requested](https://portal.productboard.com/strapi/c/27-webhooks).
But what we like at Strapi is to help developers. So even if the feature is not developed yet, here is an easy to implement work around!
### Discovering the lifecycle callbacks 🔍
As you may know, every Content Type (aka models) has lifecycle callbacks: functions which are triggered every time an entry is fetched, inserted, updated or deleted. Here is the list:
- Callbacks on `save` (both triggered on entry creation and update): `beforeSave`, `afterSave`.
- Callbacks on `fetch`: `beforeFetch`, `afterFetch`.
- Callbacks on `fetchAll`: `beforeFetchAll`, `afterFetchAll`.
- Callbacks on `create`: `beforeCreate`, `afterCreate`.
- Callbacks on `update`: `beforeUpdate`, `afterUpdate`.
- Callbacks on `destroy`: `beforeDestroy`, `afterDestroy`.
All of these functions are available in a file located at `api/yourContentType/models/YourContentType.js`.
If your goal is to rebuild a static website, the only useful callbacks are `afterCreate`, `afterUpdate` and `afterDestroy`. So, uncomment them, add logs and try to create, update and delete entries from the admin panel.
*Path: `api/yourContentType/models/YourContentType.js`*
```js
'use strict';
/**
* Lifecycle callbacks for the `Post` model.
*/
module.exports = {
afterCreate: async (entry) => {
console.log('afterCreate');
},
afterUpdate: async (entry) => {
console.log('afterUpdate');
},
afterDestroy: async (entry) => {
console.log('afterDestroy');
}
};
```
### Making the HTTP call 🔊
We are almost there: the only thing we still need to do is to actually make the HTTP call to the URL which will rebuild the static website.
#### URL config
So first of all, let's store this URL in a proper way. To do so, edit `config/environments/development/custom.json`:
*Path: `config/environments/development/custom.json`*
```json
{
"staticWebsiteBuildURL": "https://yourservice.com/"
}
```
Do the same thing for other environments.
#### HTTP call
Now it is time to make the HTTP call. In this example we will use `request` as it is already in the list of Strapi's dependencies. Let's install it:
```
npm i request --save
```
Edit `api/yourContentType/models/YourContentType.js`:
*Path: `api/yourContentType/models/YourContentType.js`*
```js
'use strict';
const request = require('request');
/**
* Lifecycle callbacks for the `Post` model.
*/
module.exports = {
afterCreate: async (entry) => {
axios.post(strapi.config.currentEnvironment.staticWebsiteBuildURL, entry)
.catch(() => {
// Ignore
}
);
},
afterUpdate: async (entry) => {
axios.post(strapi.config.currentEnvironment.staticWebsiteBuildURL, entry)
.catch(() => {
// Ignore
}
);
},
afterDestroy: async (entry) => {
axios.post(strapi.config.currentEnvironment.staticWebsiteBuildURL, entry)
.catch(() => {
// Ignore
}
);
}
};
```
#### Mongoose limitation
Until September 2018, `remove` lifecycle callback [was not supported by Mongoose](https://github.com/Automattic/mongoose/issues/3054). This has been added but `strapi-hook-mongoose` is not adapted yet to this update.
So, to trigger an url on delete, please add `request.post(strapi.config.currentEnvironment.staticWebsiteBuildURL, entry);` in:
- `remove` action of `api/yourContentType/services/YourContentType.js` (triggered by your public API).
- `delete` action of `plugins/content-manager/services/ContentManager.js` (triggered by the Content Manager).
*Note: do not forget to require `request` at the top of these files.*

View File

@ -12,7 +12,8 @@
"dependencies": {
"directory-tree": "^2.1.0",
"markdown-it-decorate": "^1.2.2",
"vuepress": "^0.14.2"
"vuepress": "^0.14.2",
"cache-loader": "1.2.2"
},
"devDependencies": {
"markdown-it-container": "^2.0.0"

View File

@ -25,6 +25,7 @@
"app.components.ComingSoonPage.featuresNotAvailable": "Este recurso está em desenvolvimento",
"app.components.DownloadInfo.download": "Transferência em progresso...",
"app.components.DownloadInfo.text": "Isto poderá levar alguns minutos. Obrigado pela sua paciência",
"app.components.EmptyAttributes.title": "Ainda não existem campos",
"app.components.HomePage.button.blog": "VEJA MAIS NO BLOG",
"app.components.HomePage.button.quickStart": "INICIAR TUTORIAL (Quick Start)",
"app.components.HomePage.community": "Nossa comunidade na web",
@ -91,6 +92,7 @@
"app.components.listPluginsPage.deletePlugin.error": "Ocorreu um erro ao desinstalar extensão",
"app.utils.SelectOption.defaultMessage": " ",
"app.utils.defaultMessage": " ",
"app.utils.delete": "Excluir",
"app.utils.placeholder.defaultMessage": " ",
"components.AutoReloadBlocker.description": "Abra o seguinte arquivo e ative o recurso.",
"components.AutoReloadBlocker.header": "Auto recarregamento é necessário para esta extensão.",
@ -136,4 +138,4 @@
"notification.error": "Ocorreu um erro",
"notification.error.layout": "Não foi possível recuperar o layout",
"request.error.model.unknown": "Este modelo não existe"
}
}

View File

@ -94,8 +94,8 @@ module.exports = (scope, cb) => {
});
} else {
const alphaDependencies = othersDependencies.map(dep => {
if (_.includes(dep, 'strapi') && !_.includes(dep, '@alpha')) { // We need this for yarn
return `${dep}@alpha`;
if (_.includes(dep, 'strapi')) { // We need this for yarn
return `${dep}@${scope.strapiPackageJSON.version}`;
}
return dep;

View File

@ -225,14 +225,14 @@ module.exports = (scope, cb) => {
shell.exec(`mkdir ${scope.tmpPath}`);
}
let cmd = `${packageCmd} ${scope.client.connector}@alpha`;
let cmd = `${packageCmd} ${scope.client.connector}@${scope.strapiPackageJSON.version}`;
if (scope.client.module) {
cmd += ` ${scope.client.module}`;
}
if (scope.client.connector === 'strapi-hook-bookshelf') {
cmd += ` strapi-hook-knex@alpha`;
cmd += ` strapi-hook-knex@${scope.strapiPackageJSON.version}`;
scope.additionalsDependencies = ['strapi-hook-knex', 'knex'];
}

View File

@ -3,6 +3,8 @@
"components.AddFilterCTA.add": "Filtros",
"components.AddFilterCTA.hide": "Filtros",
"components.DraggableAttr.edit": "Clique para editar",
"components.EmptyAttributesBlock.button": "Ir para página de configurações",
"components.EmptyAttributesBlock.description": "Você pode alterar suas configurações",
"components.FilterOptions.FILTER_TYPES.=": "é",
"components.FilterOptions.FILTER_TYPES._contains": "contém",
"components.FilterOptions.FILTER_TYPES._containss": "contém (case sensitive)",
@ -25,10 +27,13 @@
"components.TableEmpty.withFilters": "Nenhum {contentType} com os filtros aplicados...",
"components.TableEmpty.withSearch": "Nenhum {contentType} encontrado na pesquisa ({search})...",
"components.TableEmpty.withoutFilter": "Nenhum {contentType}...",
"containers.Edit.addAnItem": "Adicione um item...",
"containers.Edit.clickToJump": "Clique para pular para o registro",
"containers.Edit.delete": "Remove",
"containers.Edit.editing": "Editando...",
"containers.Edit.reset": "Reiniciar",
"containers.Edit.returnList": "Retornar à lista",
"containers.Edit.seeDetails": "Detalhes",
"containers.Edit.submit": "Salvar",
"containers.Home.introduction": "Para editar seus registros, acesse o link específico no menu à esquerda. Esta extensão não permite editar configurações, ainda está em desenvolvimento.",
"containers.Home.pluginHeaderDescription": "Gerencie seus registros através de uma interface poderosa e elegante.",
@ -37,15 +42,17 @@
"containers.List.errorFetchRecords": "Erro",
"containers.List.pluginHeaderDescription": "{label} registros encontrados",
"containers.List.pluginHeaderDescription.singular": "{label} registro encontrado",
"containers.ListPage.displayedFields": "Campos exibidos",
"containers.SettingPage.addField": "Adicionar campo",
"containers.SettingPage.addRelationalField": "Adicionar novo campo relacional",
"containers.SettingPage.attributes": "Atributos",
"containers.SettingPage.attributes.description": "Define a ordem dos atributos",
"containers.SettingPage.editSettings.description": "Drag & drop the fields to build the layout",
"containers.SettingPage.editSettings.title": "Edit — Settings",
"containers.SettingPage.editSettings.description": "Arraste e solte os campos para construir o layout",
"containers.SettingPage.editSettings.title": "Editar — Configurações",
"containers.SettingPage.listSettings.description": "Configure as opções para este Tipo de Conteúdo",
"containers.SettingPage.listSettings.title": "Lista — Configurações",
"containers.SettingPage.pluginHeaderDescription": "Defina as configurações específicas para este Tipo de Conteúdo",
"containers.SettingPage.relations": "Relational fields",
"containers.SettingPage.relations": "Campos relacionais",
"containers.SettingsPage.Block.contentType.description": "Defina as configurações específicas",
"containers.SettingsPage.Block.contentType.title": "Tipos de Conteúdo",
"containers.SettingsPage.Block.generalSettings.description": "Configure as opções padrões para seu Tipo de Conteúdo",
@ -76,14 +83,20 @@
"error.validation.required": "O valor deste registro é obrigatório.",
"form.Input.bulkActions": "Habilitar ações em lote",
"form.Input.defaultSort": "Atributo de ordenação padrão",
"form.Input.description": "Descrição",
"form.Input.description.placeholder": "Nome exibido no perfil",
"form.Input.disabled": "Campo editável",
"form.Input.filters": "Habilitar filtros",
"form.Input.label": "Rótulo",
"form.Input.label.inputDescription": "Este valor substitui o rótulo apresentado no cabeçalho da tabela",
"form.Input.pageEntries": "Entradas por página",
"form.Input.pageEntries.inputDescription": "Nota: Você pode substituir este valor na página de configurações do Tipo de Conteúdo.",
"form.Input.placeholder": "Placeholder",
"form.Input.placeholder.placeholder": "Meu valor incrível",
"form.Input.search": "Habilitar busca",
"form.Input.search.field": "Habilitar busca neste campo",
"form.Input.sort.field": "Habilitar ordenação neste campo",
"notification.error.displayedFields": "Você precisa ao menos um campo exibido",
"notification.error.relationship.fetch": "Ocorreu um erro durante a busca da relação.",
"notification.info.SettingPage.disableSort": "Você precisa de um atributo com permissão de ordenação",
"pageNotFound": "Página não encontrada",
@ -98,4 +111,4 @@
"popUpWarning.warning.updateAllSettings": "Isto irá modificar todas as suas configurações",
"success.record.delete": "Removido",
"success.record.save": "Salvo"
}
}

View File

@ -936,7 +936,7 @@ module.exports = {
if (connector && !installedConnector) {
strapi.log.info(`Installing ${connector} dependency ...`);
exec('npm', ['install', `${connector}@alpha`]);
exec('npm', ['install', `${connector}@${strapi.config.info.strapi}`]);
}
if (client && !installedClient) {

View File

@ -94,4 +94,4 @@
},
"preferGlobal": true,
"license": "MIT"
}
}