diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 3dd3f7fb0e..8564e9139e 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -95,6 +95,7 @@ module.exports = { title: '💡 Guides', children: [ '/3.0.0-beta.x/concepts/concepts', + '/3.0.0-beta.x/guides/api-endpoints', '/3.0.0-beta.x/guides/api-documentation', '/3.0.0-beta.x/guides/authentication', '/3.0.0-beta.x/configurations/configurations', diff --git a/docs/3.0.0-beta.x/guides/api-endpoints.md b/docs/3.0.0-beta.x/guides/api-endpoints.md new file mode 100644 index 0000000000..bf7b90a07a --- /dev/null +++ b/docs/3.0.0-beta.x/guides/api-endpoints.md @@ -0,0 +1,313 @@ +# API Endpoints + +When you create a `ContentType` you will have a certain number of REST API endpoints available to interact with it. + +As an example let's consider the `Post` ContentType for the next steps. + +### `Post` ContentType + +| Fields | Type | Description | Options | +| :----- | :----- | ------------------ | ------------ | +| title | string | Post's title | | +| cover | media | Post's cover image | | +| seo | group | Post's seo group | `repeatable` | + +### `Seo` Group + +| Fields | Type | Description | +| :------ | :----- | -------------- | +| name | string | Meta's name | +| content | text | Meta's content | + +--- + +## Endpoints + + + +
+ +| Method | Path | Description | +| :----- | :------------------------------- | :------------------ | +| GET | [/posts](#get-posts) | Get a list of posts | +| GET | [/posts/count](#get-posts-count) | Count posts | +| POST | [/posts](#post-posts) | Create a post | +| GET | [/posts/:id](#get-posts-id) | Get a specific post | +| PUT | [/posts/:id](#put-posts-id) | Update a post | +| DELETE | [/posts/:id](#delete-posts-id) | Delete a post | + +
+ +## GET `/posts` + +Returns the posts matching the query filters. You can read more about filtering [here](./filters.md). + +**Example request** + +```js +GET http://localhost:1337/posts +``` + +**Example response** + +```json +[ + { + "id": 1, + "title": "Post 1", + "cover": { + "id": 1, + "url": "/uploads/3d89ba92f762433bbb75bbbfd9c13974.png" + //... + }, + "seo": [ + { + "id": 1, + "name": "description", + "content": "This is a press post about Strapi" + }, + { + "id": 2, + "name": "keywords", + "content": "post, article, news, press" + } + ] + } +] +``` + +## GET `/posts/count` + +Returns the count of posts matching the query filters. You can read more about filtering [here](./filters.md). + +**Example response** + +``` +1 +``` + +## POST `/posts` + +Creates a post and returns its value. + +**Example request** + +```js +POST http://localhost:1337/posts +``` + +```json +{ + "title": "Post 1", + "cover": 1, + "seo": [ + { + "name": "title", + "content": "Post 1" + } + ] +} +``` + +**Example response** + +```json +{ + "id": 1, + "title": "Post 1", + "cover": { + "id": 1, + "url": "/uploads/3d89ba92f762433bbb75bbbfd9c13974.png" + //... + }, + "seo": [ + { + "id": 1, + "name": "title", + "content": "Post 1" + } + ] +} +``` + +## GET `/posts/:id` + +Returns a post by id. + +**Example request** + +```js +GET http://localhost:1337/posts/1 +``` + +**Example response** + +```json +{ + "id": 1, + "title": "Post 1", + "cover": { + "id": 1, + "url": "/uploads/3d89ba92f762433bbb75bbbfd9c13974.png" + //... + }, + "seo": [ + { + "id": 1, + "name": "title", + "content": "Post 1" + } + ] +} +``` + +## PUT `/posts/:id` + +Partially updates a post by id and returns its value. +Fields that aren't sent in the query are not changed in the db. Send a `null` value if you want to clear them. + +**Example request** + +```js +PUT http://localhost:1337/posts/1 +``` + +```json +{ + "title": "Post 1", + "seo": [ + { + // adding a new item + "name": "description", + "content": "Post 1 description meta" + }, + { + // editing one of the previous item by passing its id + "id": 1, + "name": "title", + "content": "Post 1" + } + ] +} +``` + +**Example response** + +```json +{ + "id": 1, + "title": "Post 1", + "cover": { + "id": 1, + "url": "/uploads/3d89ba92f762433bbb75bbbfd9c13974.png" + //... + }, + "seo": [ + { + "id": 2, + "name": "description", + "content": "Post 1 description meta" + }, + { + "id": 1, + "name": "title", + "content": "Post 1" + } + ] +} +``` + +## DELETE `/posts/:id` + +Deletes a post by id and returns its value. + +**Example request** + +```js +DELETE http://localhost:1337/posts/1 +``` + +**Example response** + +```json +{ + "id": 1, + "title": "Post 1", + "cover": { + "id": 1, + "url": "/uploads/3d89ba92f762433bbb75bbbfd9c13974.png" + //... + }, + "seo": [ + { + "id": 2, + "name": "description", + "content": "Post 1 description meta" + }, + { + "id": 1, + "name": "title", + "content": "Post 1" + } + ] +} +``` + +::: tip +Whether you are using MongoDB or a SQL database you can use the field `id` as described in this documentation. It will be provided in both cases and work the same way. +::: + +## GraphQL + +When you are using the GraphQL plugin, all your `ContentTypes` will be generated in your Graphql schema and made accessible through queries and mutations. + +If you are using `Groups`, they will be available as fields in the `ContentTypes` they are used in. + +```graphql +type Post { + title: String + cover: UploadFile + seo: [GroupSeo] +} + +type GroupSeo { + name: String + content: String +} + +type Query { + post(id: ID!): Post + posts(sort: String, limit: Int, start: Int, where: JSON): [Post] +} + +type Mutation { + createPost(input: createPostInput): createPostPayload + updatePost(input: updatePostInput): updatePostPayload + deletePost(input: deletePostInput): deletePostPayload +} +``` + +You can read more about the graphql plugin [here](./graphql.md). diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/ListRowCollapse/StyledListRowCollapse.js b/packages/strapi-plugin-content-type-builder/admin/src/components/ListRowCollapse/StyledListRowCollapse.js index 982e4d3c16..96beaabe90 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/ListRowCollapse/StyledListRowCollapse.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/ListRowCollapse/StyledListRowCollapse.js @@ -84,6 +84,9 @@ const StyedListRowCollapse = styled.tr` top: 0; height: 100%; padding-right: 30px; + button:last-of-type { + padding-right: 0; + } i { margin: auto; } diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js index 4dde48c0f0..2da02a9822 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/ModelPage/index.js @@ -665,26 +665,28 @@ export class ModelPage extends React.Component { )} -
- { - e.stopPropagation(); + {!this.getSource() && ( +
+ { + e.stopPropagation(); - if (canOpenModal || this.isUpdatingTemporaryContentType()) { - this.toggleDeleteModalWarning(true); - } else { - strapi.notification.info( - `${pluginId}.notification.info.work.notSaved` - ); - } - }} - > -
- -
- -
-
+ if (canOpenModal || this.isUpdatingTemporaryContentType()) { + this.toggleDeleteModalWarning(true); + } else { + strapi.notification.info( + `${pluginId}.notification.info.work.notSaved` + ); + } + }} + > +
+ +
+ +
+
+ )}