Fix edit model, create group

This commit is contained in:
soupette 2019-06-13 15:36:05 +02:00
parent c0ceedbb76
commit 1fe131017a
27 changed files with 531 additions and 803 deletions

View File

@ -3,7 +3,7 @@
{
"method": "GET",
"path": "/articles",
"handler": "Articles.find",
"handler": "Article.find",
"config": {
"policies": []
}
@ -11,7 +11,7 @@
{
"method": "GET",
"path": "/articles/count",
"handler": "Articles.count",
"handler": "Article.count",
"config": {
"policies": []
}
@ -19,7 +19,7 @@
{
"method": "GET",
"path": "/articles/:id",
"handler": "Articles.findOne",
"handler": "Article.findOne",
"config": {
"policies": []
}
@ -27,7 +27,7 @@
{
"method": "POST",
"path": "/articles",
"handler": "Articles.create",
"handler": "Article.create",
"config": {
"policies": []
}
@ -35,7 +35,7 @@
{
"method": "PUT",
"path": "/articles/:id",
"handler": "Articles.update",
"handler": "Article.update",
"config": {
"policies": []
}
@ -43,10 +43,10 @@
{
"method": "DELETE",
"path": "/articles/:id",
"handler": "Articles.delete",
"handler": "Article.delete",
"config": {
"policies": []
}
}
]
}
}

View File

@ -0,0 +1,8 @@
'use strict';
/**
* Read the documentation (https://strapi.io/documentation/3.0.0-beta.x/guides/controllers.html#core-controllers)
* to customize this controller
*/
module.exports = {};

View File

@ -0,0 +1,55 @@
'use strict';
/**
* Lifecycle callbacks for the `Article` model.
*/
module.exports = {
// Before saving a value.
// Fired before an `insert` or `update` query.
// beforeSave: async (model, attrs, options) => {},
// After saving a value.
// Fired after an `insert` or `update` query.
// afterSave: async (model, response, options) => {},
// Before fetching a value.
// Fired before a `fetch` operation.
// beforeFetch: async (model, columns, options) => {},
// After fetching a value.
// Fired after a `fetch` operation.
// afterFetch: async (model, response, options) => {},
// Before fetching all values.
// Fired before a `fetchAll` operation.
// beforeFetchAll: async (model, columns, options) => {},
// After fetching all values.
// Fired after a `fetchAll` operation.
// afterFetchAll: async (model, response, options) => {},
// Before creating a value.
// Fired before an `insert` query.
// beforeCreate: async (model, attrs, options) => {},
// After creating a value.
// Fired after an `insert` query.
// afterCreate: async (model, attrs, options) => {},
// Before updating a value.
// Fired before an `update` query.
// beforeUpdate: async (model, attrs, options) => {},
// After updating a value.
// Fired after an `update` query.
// afterUpdate: async (model, attrs, options) => {},
// Before destroying a value.
// Fired before a `delete` query.
// beforeDestroy: async (model, attrs, options) => {},
// After destroying a value.
// Fired after a `delete` query.
// afterDestroy: async (model, attrs, options) => {}
};

View File

@ -2,7 +2,7 @@
"connection": "default",
"collectionName": "articles",
"info": {
"name": "articles",
"name": "article",
"description": "Super description"
},
"options": {
@ -30,4 +30,4 @@
"plugin": "upload"
}
}
}
}

View File

@ -0,0 +1,8 @@
'use strict';
/**
* Read the documentation (https://strapi.io/documentation/3.0.0-beta.x/guides/services.html#core-services)
* to customize this service
*/
module.exports = {};

View File

@ -1,7 +0,0 @@
'use strict';
/**
* Read the documentation () to implement custom controller functions
*/
module.exports = {};

View File

@ -1,615 +0,0 @@
{
"paths": {
"/articles": {
"get": {
"deprecated": false,
"description": "Find all the articles's records",
"responses": {
"200": {
"description": "Retrieve articles document(s)",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Articles"
}
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"summary": "",
"tags": [
"Articles"
],
"parameters": [
{
"name": "_limit",
"in": "query",
"required": false,
"description": "Maximum number of results possible",
"schema": {
"type": "integer"
},
"deprecated": false
},
{
"name": "_sort",
"in": "query",
"required": false,
"description": "Sort according to a specific field.",
"schema": {
"type": "string"
},
"deprecated": false
},
{
"name": "_start",
"in": "query",
"required": false,
"description": "Skip a specific number of entries (especially useful for pagination)",
"schema": {
"type": "integer"
},
"deprecated": false
},
{
"name": "=",
"in": "query",
"required": false,
"description": "Get entries that matches exactly your input",
"schema": {
"type": "string"
},
"deprecated": false
},
{
"name": "_ne",
"in": "query",
"required": false,
"description": "Get records that are not equals to something",
"schema": {
"type": "string"
},
"deprecated": false
},
{
"name": "_lt",
"in": "query",
"required": false,
"description": "Get record that are lower than a value",
"schema": {
"type": "string"
},
"deprecated": false
},
{
"name": "_lte",
"in": "query",
"required": false,
"description": "Get records that are lower than or equal to a value",
"schema": {
"type": "string"
},
"deprecated": false
},
{
"name": "_gt",
"in": "query",
"required": false,
"description": "Get records that are greater than a value",
"schema": {
"type": "string"
},
"deprecated": false
},
{
"name": "_gte",
"in": "query",
"required": false,
"description": "Get records that are greater than or equal a value",
"schema": {
"type": "string"
},
"deprecated": false
},
{
"name": "_contains",
"in": "query",
"required": false,
"description": "Get records that contains a value",
"schema": {
"type": "string"
},
"deprecated": false
},
{
"name": "_containss",
"in": "query",
"required": false,
"description": "Get records that contains (case sensitive) a value",
"schema": {
"type": "string"
},
"deprecated": false
},
{
"name": "_in",
"in": "query",
"required": false,
"description": "Get records that matches any value in the array of values",
"schema": {
"type": "array"
},
"deprecated": false
},
{
"name": "_nin",
"in": "query",
"required": false,
"description": "Get records that doesn't match any value in the array of values",
"schema": {
"type": "array"
},
"deprecated": false
}
]
},
"post": {
"deprecated": false,
"description": "Create a new articles record",
"responses": {
"200": {
"description": "Retrieve articles document(s)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Articles"
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"summary": "",
"tags": [
"Articles"
],
"requestBody": {
"description": "",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NewArticles"
}
}
}
}
}
},
"/articles/count": {
"get": {
"deprecated": false,
"description": "Retrieve the numver of articles documents",
"responses": {
"200": {
"description": "Retrieve articles document(s)",
"content": {
"application/json": {
"schema": {
"properties": {
"count": {
"type": "integer"
}
}
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"summary": "",
"tags": [
"Articles"
],
"parameters": []
}
},
"/articles/{id}": {
"get": {
"deprecated": false,
"description": "Find one articles record",
"responses": {
"200": {
"description": "Retrieve articles document(s)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Articles"
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"summary": "",
"tags": [
"Articles"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "",
"deprecated": false,
"required": true,
"schema": {
"type": "string"
}
}
]
},
"put": {
"deprecated": false,
"description": "Update a single articles record",
"responses": {
"200": {
"description": "Retrieve articles document(s)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Articles"
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"summary": "",
"tags": [
"Articles"
],
"requestBody": {
"description": "",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NewArticles"
}
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"description": "",
"deprecated": false,
"required": true,
"schema": {
"type": "string"
}
}
]
},
"delete": {
"deprecated": false,
"description": "Delete a single articles record",
"responses": {
"200": {
"description": "deletes a single articles based on the ID supplied",
"content": {
"application/json": {
"schema": {
"type": "integer",
"format": "int64"
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"summary": "",
"tags": [
"Articles"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "",
"deprecated": false,
"required": true,
"schema": {
"type": "string"
}
}
]
}
}
},
"components": {
"schemas": {
"Articles": {
"required": [
"id"
],
"properties": {
"id": {
"type": "string"
},
"content2": {
"type": "string"
},
"posts": {
"type": "array",
"items": {
"required": [
"id"
],
"properties": {
"id": {
"type": "string"
},
"articles": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"title": {
"type": "string"
},
"image": {
"required": [
"id",
"name",
"hash",
"mime",
"size",
"url",
"provider"
],
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"hash": {
"type": "string"
},
"sha256": {
"type": "string"
},
"ext": {
"type": "string"
},
"mime": {
"type": "string"
},
"size": {
"type": "string"
},
"url": {
"type": "string"
},
"provider": {
"type": "string"
},
"public_id": {
"type": "string"
},
"related": {
"type": "string"
}
}
}
}
},
"NewArticles": {
"properties": {
"content2": {
"type": "string"
},
"posts": {
"type": "array",
"items": {
"type": "string"
}
},
"title": {
"type": "string"
}
}
}
}
},
"tags": [
{
"name": "Articles"
}
]
}

View File

@ -1,7 +0,0 @@
'use strict';
/**
* Read the documentation () to implement custom service functions
*/
module.exports = {};

View File

@ -10,7 +10,7 @@
},
"attributes": {
"articles": {
"collection": "articles",
"collection": "article",
"dominant": true,
"via": "posts"
}

View File

@ -0,0 +1,52 @@
{
"routes": [
{
"method": "GET",
"path": "/zobs",
"handler": "Zob.find",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/zobs/count",
"handler": "Zob.count",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/zobs/:id",
"handler": "Zob.findOne",
"config": {
"policies": []
}
},
{
"method": "POST",
"path": "/zobs",
"handler": "Zob.create",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/zobs/:id",
"handler": "Zob.update",
"config": {
"policies": []
}
},
{
"method": "DELETE",
"path": "/zobs/:id",
"handler": "Zob.delete",
"config": {
"policies": []
}
}
]
}

View File

@ -0,0 +1,8 @@
'use strict';
/**
* Read the documentation (https://strapi.io/documentation/3.0.0-beta.x/guides/controllers.html#core-controllers)
* to customize this controller
*/
module.exports = {};

View File

@ -1,7 +1,7 @@
'use strict';
/**
* Lifecycle callbacks for the `Test` model.
* Lifecycle callbacks for the `Zob` model.
*/
module.exports = {

View File

@ -0,0 +1,18 @@
{
"connection": "default",
"collectionName": "zobs",
"info": {
"name": "zob",
"description": ""
},
"options": {
"increments": true,
"timestamps": true,
"comment": ""
},
"attributes": {
"name": {
"type": "string"
}
}
}

View File

@ -0,0 +1,8 @@
'use strict';
/**
* Read the documentation (https://strapi.io/documentation/3.0.0-beta.x/guides/services.html#core-services)
* to customize this service
*/
module.exports = {};

View File

@ -1,5 +1,5 @@
"""Super description"""
type Articles {
type Article {
id: ID!
created_at: DateTime!
updated_at: DateTime!
@ -9,19 +9,19 @@ type Articles {
posts(sort: String, limit: Int, start: Int, where: JSON): [Post]
}
input ArticlesInput {
input ArticleInput {
content2: String
posts: [ID]
title: String
image: ID
}
input createArticlesInput {
data: ArticlesInput
input createArticleInput {
data: ArticleInput
}
type createArticlesPayload {
article: Articles
type createArticlePayload {
article: Article
}
input createPostInput {
@ -48,17 +48,25 @@ type createUserPayload {
user: UsersPermissionsUser
}
input createZobInput {
data: ZobInput
}
type createZobPayload {
zob: Zob
}
"""
The `DateTime` scalar represents a date and time following the ISO 8601 standard
"""
scalar DateTime
input deleteArticlesInput {
input deleteArticleInput {
where: InputID
}
type deleteArticlesPayload {
article: Articles
type deleteArticlePayload {
article: Article
}
input deletePostInput {
@ -85,7 +93,15 @@ type deleteUserPayload {
user: UsersPermissionsUser
}
input editArticlesInput {
input deleteZobInput {
where: InputID
}
type deleteZobPayload {
zob: Zob
}
input editArticleInput {
content2: String
posts: [ID]
title: String
@ -132,6 +148,10 @@ input editUserInput {
role: ID
}
input editZobInput {
name: String
}
input FileInput {
name: String!
hash: String!
@ -154,15 +174,18 @@ scalar JSON
"""The `Long` scalar type represents 52-bit integers"""
scalar Long
union Morph = UsersPermissionsMe | UsersPermissionsMeRole | Articles | createArticlesPayload | updateArticlesPayload | deleteArticlesPayload | Post | createPostPayload | updatePostPayload | deletePostPayload | UploadFile | UsersPermissionsPermission | UsersPermissionsRole | createRolePayload | updateRolePayload | deleteRolePayload | UsersPermissionsUser | createUserPayload | updateUserPayload | deleteUserPayload | MypluginTest
union Morph = UsersPermissionsMe | UsersPermissionsMeRole | Article | createArticlePayload | updateArticlePayload | deleteArticlePayload | Post | createPostPayload | updatePostPayload | deletePostPayload | Zob | createZobPayload | updateZobPayload | deleteZobPayload | UploadFile | UsersPermissionsPermission | UsersPermissionsRole | createRolePayload | updateRolePayload | deleteRolePayload | UsersPermissionsUser | createUserPayload | updateUserPayload | deleteUserPayload | MypluginTest
type Mutation {
createArticles(input: createArticlesInput): createArticlesPayload
updateArticles(input: updateArticlesInput): updateArticlesPayload
deleteArticles(input: deleteArticlesInput): deleteArticlesPayload
createArticle(input: createArticleInput): createArticlePayload
updateArticle(input: updateArticleInput): updateArticlePayload
deleteArticle(input: deleteArticleInput): deleteArticlePayload
createPost(input: createPostInput): createPostPayload
updatePost(input: updatePostInput): updatePostPayload
deletePost(input: deletePostInput): deletePostPayload
createZob(input: createZobInput): createZobPayload
updateZob(input: updateZobInput): updateZobPayload
deleteZob(input: deleteZobInput): deleteZobPayload
"""Create a new role"""
createRole(input: createRoleInput): createRolePayload
@ -193,7 +216,7 @@ type Post {
id: ID!
created_at: DateTime!
updated_at: DateTime!
articles(sort: String, limit: Int, start: Int, where: JSON): [Articles]
articles(sort: String, limit: Int, start: Int, where: JSON): [Article]
}
input PostInput {
@ -201,10 +224,12 @@ input PostInput {
}
type Query {
article(id: ID!): Articles
articles(sort: String, limit: Int, start: Int, where: JSON): [Articles]
article(id: ID!): Article
articles(sort: String, limit: Int, start: Int, where: JSON): [Article]
post(id: ID!): Post
posts(sort: String, limit: Int, start: Int, where: JSON): [Post]
zob(id: ID!): Zob
zobs(sort: String, limit: Int, start: Int, where: JSON): [Zob]
files(sort: String, limit: Int, start: Int, where: JSON): [UploadFile]
role(id: ID!): UsersPermissionsRole
@ -231,13 +256,13 @@ input TestInput {
type: String!
}
input updateArticlesInput {
input updateArticleInput {
where: InputID
data: editArticlesInput
data: editArticleInput
}
type updateArticlesPayload {
article: Articles
type updateArticlePayload {
article: Article
}
input updatePostInput {
@ -267,6 +292,15 @@ type updateUserPayload {
user: UsersPermissionsUser
}
input updateZobInput {
where: InputID
data: editZobInput
}
type updateZobPayload {
zob: Zob
}
"""The `Upload` scalar type represents a file upload."""
scalar Upload
@ -343,3 +377,14 @@ type UsersPermissionsUser {
blocked: Boolean
role: UsersPermissionsRole
}
type Zob {
id: ID!
created_at: DateTime!
updated_at: DateTime!
name: String
}
input ZobInput {
name: String
}

View File

@ -13,6 +13,7 @@ import {
CLEAR_TEMPORARY_ATTRIBUTE,
CLEAR_TEMPORARY_ATTRIBUTE_RELATION,
CREATE_TEMP_CONTENT_TYPE,
CREATE_TEMP_GROUP,
DELETE_GROUP,
DELETE_GROUP_SUCCEEDED,
DELETE_MODEL,
@ -95,6 +96,12 @@ export function createTempContentType() {
};
}
export function createTempGroup() {
return {
type: CREATE_TEMP_GROUP,
};
}
export function deleteGroup(uid) {
return {
type: DELETE_GROUP,

View File

@ -18,6 +18,7 @@ export const CLEAR_TEMPORARY_ATTRIBUTE_RELATION =
'ContentTypeBuilder/App/CLEAR_TEMPORARY_ATTRIBUTE_RELATION';
export const CREATE_TEMP_CONTENT_TYPE =
'ContentTypeBuilder/App/CREATE_TEMP_CONTENT_TYPE';
export const CREATE_TEMP_GROUP = 'ContentTypeBuilder/App/CREATE_TEMP_GROUP';
export const DELETE_GROUP = 'ContentTypeBuilder/App/DELETE_GROUP';
export const DELETE_GROUP_SUCCEEDED =
'ContentTypeBuilder/App/DELETE_GROUP_SUCCEEDED';

View File

@ -9,7 +9,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators, compose } from 'redux';
import { Switch, Route } from 'react-router-dom';
import { isEmpty } from 'lodash';
import { get, isEmpty } from 'lodash';
import { NotFound, getQueryParameters } from 'strapi-helper-plugin';
@ -28,6 +28,7 @@ import {
cancelNewContentType,
clearTemporaryAttributeRelation,
createTempContentType,
createTempGroup,
deleteGroup,
deleteModel,
deleteTemporaryGroup,
@ -113,6 +114,45 @@ export class App extends React.Component {
getFeatureType = () => getQueryParameters(this.getSearch(), 'modalType');
getFormDataForModel = () => {
const { modifiedData, newContentType } = this.props;
if (this.isUpdatingTemporaryModel()) {
return newContentType;
}
return get(modifiedData, this.getFeatureNameFromSearch(), {});
};
getFeatureNameFromSearch = () =>
getQueryParameters(this.getSearch(), 'modelName');
isUpdatingTemporaryModel = (modelName = this.getFeatureNameFromSearch()) => {
const { models } = this.props;
const currentModel = models.find(model => model.name === modelName) || {
isTemporary: true,
};
const { isTemporary } = currentModel;
return isTemporary;
};
isUpdatingTemporaryFeature = (
groupName = this.getFeatureNameFromSearch()
) => {
const { groups } = this.props;
const currentGroup = groups.find(group => group.uid === groupName) || {
isTemporary: true,
};
const { isTemporary } = currentGroup;
return isTemporary;
};
renderRoute = route => {
const { component: Component, to } = route;
@ -135,7 +175,10 @@ export class App extends React.Component {
render() {
const {
cancelNewContentType,
connections,
createTempContentType,
createTempGroup,
groups,
history: { push },
location: { pathname, search },
@ -143,14 +186,61 @@ export class App extends React.Component {
models,
newContentType,
newGroup,
onChangeExistingContentTypeMainInfos,
onChangeNewContentTypeMainInfos,
onChangeNewGroupMainInfos,
resetExistingContentTypeMainInfos,
resetNewContentTypeMainInfos,
updateTempContentType,
} = this.props;
if (isLoading) {
return <Loader />;
}
const featureForms = [
{
actionType: this.getActionType(),
activeTab: getQueryParameters(search, 'settingType'),
allTakenNames: this.getAllGroupsAndModelsNames(),
cancelNewFeatureType: cancelNewContentType,
connections,
createTempFeatureType: createTempContentType,
featureToEditName: this.getFeatureNameFromSearch(),
featureType: 'model',
isOpen: getQueryParameters(search, 'modalType') === 'model',
isUpdatingTemporaryFeatureType: this.isUpdatingTemporaryModel(),
modifiedData: this.getFormDataForModel(),
onChangeExistingFeatureTypeMainInfos: onChangeExistingContentTypeMainInfos,
onChangeNewFeatureTypeMainInfos: onChangeNewContentTypeMainInfos,
pathname,
push,
resetExistingFeatureTypeMainInfos: resetExistingContentTypeMainInfos,
resetNewFeatureTypeMainInfos: resetNewContentTypeMainInfos,
updateTempFeatureType: updateTempContentType,
},
{
actionType: this.getActionType(),
activeTab: getQueryParameters(search, 'settingType'),
allTakenNames: this.getAllGroupsAndModelsNames(),
cancelNewFeatureType: () => {},
connections,
createTempFeatureType: createTempGroup,
featureToEditName: this.getFeatureNameFromSearch(),
featureType: 'group',
isOpen: getQueryParameters(search, 'modalType') === 'group',
isUpdatingTemporaryFeatureType: this.isUpdatingTemporaryFeature(),
modifiedData: newGroup,
onChangeExistingFeatureTypeMainInfos: () => {},
onChangeNewFeatureTypeMainInfos: onChangeNewGroupMainInfos,
pathname,
push,
resetExistingFeatureTypeMainInfos: () => {},
resetNewFeatureTypeMainInfos: () => {},
updateTempFeatureType: () => {},
},
];
return (
<MenuContext.Provider
value={{
@ -166,29 +256,9 @@ export class App extends React.Component {
<Route component={NotFound} />
</Switch>
</div>
<ModelForm
actionType={this.getActionType()}
activeTab={getQueryParameters(search, 'settingType')}
allTakenNames={this.getAllGroupsAndModelsNames()}
cancelNewContentType={() => {}}
connections={connections}
createTempContentType={() => {}}
featureType={this.getFeatureType()}
modifiedData={
this.getFeatureType() === 'model' ? newContentType : newGroup
}
onChangeNewContentTypeMainInfos={
this.getFeatureType() === 'model'
? onChangeNewContentTypeMainInfos
: onChangeNewGroupMainInfos
}
// onChangeNewContentTypeMainInfos={
// this.props.onChangeNewContentTypeMainInfos
// }
isOpen={!isEmpty(search)}
pathname={pathname}
push={push}
/>
{featureForms.map(feature => (
<ModelForm key={feature.featureType} {...feature} />
))}
</MenuContext.Provider>
);
}
@ -227,6 +297,7 @@ export function mapDispatchToProps(dispatch) {
cancelNewContentType,
clearTemporaryAttributeRelation,
createTempContentType,
createTempGroup,
deleteGroup,
deleteModel,
deleteTemporaryGroup,

View File

@ -14,6 +14,7 @@ import {
CLEAR_TEMPORARY_ATTRIBUTE,
CLEAR_TEMPORARY_ATTRIBUTE_RELATION,
CREATE_TEMP_CONTENT_TYPE,
CREATE_TEMP_GROUP,
DELETE_GROUP_SUCCEEDED,
DELETE_MODEL_ATTRIBUTE,
DELETE_MODEL_SUCCEEDED,
@ -241,7 +242,27 @@ function appReducer(state = initialState, action) {
)
)
.update('newContentTypeClone', () => state.get('newContentType'));
case CREATE_TEMP_GROUP:
return state
.update('groups', list =>
list.push(
fromJS({
icon: 'fa-cube',
name: state.getIn(['newGroup', 'name']),
description: state.getIn(['newGroup', 'description']),
fields: 0,
isTemporary: true,
})
)
)
.update('newGroupClone', () => state.get('newGroup'));
case DELETE_GROUP_SUCCEEDED:
console.log({
st: state
.get('groups')
.findIndex(group => group.get('uid') === action.uid),
action,
});
return state.removeIn([
'groups',
state.get('groups').findIndex(group => group.get('uid') === action.uid),

View File

@ -78,6 +78,7 @@ describe('<App />', () => {
modifiedData: {},
onChangeExistingContentTypeMainInfos: jest.fn(),
onChangeNewContentTypeMainInfos: jest.fn(),
onChangeNewGroupMainInfos: jest.fn(),
saveEditedAttribute: jest.fn(),
saveEditedAttributeRelation: jest.fn(),
setTemporaryAttribute: jest.fn(),

View File

@ -147,6 +147,21 @@ describe('appReducer', () => {
unique: false,
},
shouldRefetchData: false,
newGroup: {
collectionName: '',
connection: '',
description: '',
name: '',
attributes: [],
},
newGroupClone: {
collectionName: '',
connection: '',
description: '',
name: '',
attributes: [],
},
});
});
@ -1025,6 +1040,20 @@ describe('appReducer', () => {
unique: false,
},
shouldRefetchData: false,
newGroup: {
collectionName: '',
connection: '',
description: '',
name: '',
attributes: [],
},
newGroupClone: {
collectionName: '',
connection: '',
description: '',
name: '',
attributes: [],
},
});
expect(appReducer(state, resetProps())).toEqual(expected);
@ -1174,6 +1203,20 @@ describe('SavedEditedAttributeRelation with a temporary model', () => {
unique: false,
},
shouldRefetchData: false,
newGroup: {
collectionName: '',
connection: '',
description: '',
name: '',
attributes: [],
},
newGroupClone: {
collectionName: '',
connection: '',
description: '',
name: '',
attributes: [],
},
});
});

View File

@ -69,7 +69,7 @@ function Row({
e.stopPropagation();
const to = uid || name;
onClickGoTo(to, source, true);
onClickGoTo(to, source, isTemporary);
}}
>
<i className="fa fa-pencil link-icon" />
@ -111,8 +111,9 @@ function Row({
action();
} else {
const action = viewType === 'models' ? deleteModel : deleteGroup;
const featureName = viewType === 'models' ? name : uid;
action(name, context);
action(featureName, context);
}
setIsOpen(false);
}}

View File

@ -86,7 +86,7 @@ class HomePage extends React.Component {
const modalType = type === 'models' ? 'model' : 'group';
const search =
shouldEdit && canOpenModal
shouldEdit || canOpenModal
? `?modalType=${modalType}&settingType=base&actionType=edit&modelName=${to}`
: '';
push(

View File

@ -7,7 +7,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { get, isEmpty } from 'lodash';
import { get, isEmpty, upperFirst } from 'lodash';
import { InputsIndex as Input } from 'strapi-helper-plugin';
@ -37,20 +37,20 @@ class ModelForm extends React.Component {
handleCancel = () => {
const {
actionType,
cancelNewContentType,
isUpdatingTemporaryContentType,
modelToEditName,
cancelNewFeatureType,
isUpdatingTemporaryFeatureType,
featureToEditName,
push,
resetExistingContentTypeMainInfos,
resetNewContentTypeMainInfos,
resetExistingFeatureTypeMainInfos,
resetNewFeatureTypeMainInfos,
} = this.props;
if (actionType === 'create') {
cancelNewContentType();
} else if (isUpdatingTemporaryContentType) {
resetNewContentTypeMainInfos();
cancelNewFeatureType();
} else if (isUpdatingTemporaryFeatureType) {
resetNewFeatureTypeMainInfos();
} else {
resetExistingContentTypeMainInfos(modelToEditName);
resetExistingFeatureTypeMainInfos(featureToEditName);
}
push({ search: '' });
@ -58,15 +58,16 @@ class ModelForm extends React.Component {
handleGoTo = to => {
const { emitEvent } = this.context;
const { actionType, modelToEditName, push } = this.props;
const model = actionType === 'edit' ? `&modelName=${modelToEditName}` : '';
const { actionType, featureType, featureToEditName, push } = this.props;
const model =
actionType === 'edit' ? `&modelName=${featureToEditName}` : '';
if (to === 'advanced') {
emitEvent('didSelectContentTypeSettings');
}
push({
search: `modalType=model&settingType=${to}&actionType=${actionType}${model}`,
search: `modalType=${featureType}&settingType=${to}&actionType=${actionType}${model}`,
});
};
@ -80,16 +81,16 @@ class ModelForm extends React.Component {
const {
allTakenNames,
actionType,
createTempContentType,
createTempFeatureType,
featureType,
isUpdatingTemporaryContentType,
modelToEditName,
isUpdatingTemporaryFeatureType,
featureToEditName,
modifiedData,
push,
updateTempContentType,
updateTempFeatureType,
} = this.props;
const alreadyTakenContentTypeNames = allTakenNames.filter(
name => name !== modelToEditName
name => name !== featureToEditName
);
let formErrors = {};
@ -113,13 +114,13 @@ class ModelForm extends React.Component {
if (isEmpty(formErrors)) {
if (actionType === 'create') {
createTempContentType();
createTempFeatureType();
push({
pathname,
search: 'modalType=chooseAttributes',
});
} else if (isUpdatingTemporaryContentType) {
updateTempContentType();
} else if (isUpdatingTemporaryFeatureType) {
updateTempFeatureType();
push({ pathname, search: '' });
} else {
push({ search: '' });
@ -137,12 +138,12 @@ class ModelForm extends React.Component {
const {
actionType,
connections,
isUpdatingTemporaryContentType,
isUpdatingTemporaryFeatureType,
featureToEditName,
featureType,
modelToEditName,
modifiedData,
onChangeExistingContentTypeMainInfos,
onChangeNewContentTypeMainInfos,
onChangeExistingFeatureTypeMainInfos,
onChangeNewFeatureTypeMainInfos,
} = this.props;
const { didCheckErrors, formErrors, isVisible } = this.state;
@ -171,13 +172,13 @@ class ModelForm extends React.Component {
const errors = get(formErrors, input.name, []);
const onChange =
actionType === 'create' || isUpdatingTemporaryContentType
? onChangeNewContentTypeMainInfos
: onChangeExistingContentTypeMainInfos;
actionType === 'create' || isUpdatingTemporaryFeatureType
? onChangeNewFeatureTypeMainInfos
: onChangeExistingFeatureTypeMainInfos;
const name =
actionType === 'create' || isUpdatingTemporaryContentType
actionType === 'create' || isUpdatingTemporaryFeatureType
? input.name
: `${modelToEditName}.${input.name}`;
: `${featureToEditName}.${input.name}`;
return (
<Input
@ -208,7 +209,13 @@ class ModelForm extends React.Component {
};
render() {
const { actionType, activeTab, featureType, isOpen } = this.props;
const {
actionType,
activeTab,
featureToEditName,
featureType,
isOpen,
} = this.props;
const currentForm = get(forms, activeTab, forms.base);
return (
@ -233,6 +240,7 @@ class ModelForm extends React.Component {
<FormattedMessage
id={`${pluginId}.popUpForm.${actionType ||
'create'}.${featureType}.header.subTitle`}
values={{ name: upperFirst(featureToEditName) }}
/>
</HeaderModalTitle>
<div className="settings-tabs">
@ -270,42 +278,42 @@ ModelForm.contextTypes = {
ModelForm.defaultProps = {
actionType: 'create',
activeTab: 'base',
cancelNewContentType: () => {},
cancelNewFeatureType: () => {},
connections: ['default'],
createTempContentType: () => {},
createTempFeatureType: () => {},
isOpen: false,
isUpdatingTemporaryContentType: false,
isUpdatingTemporaryFeatureType: false,
featureType: 'model',
modelToEditName: '',
featureToEditName: '',
modifiedData: {},
onChangeExistingContentTypeMainInfos: () => {},
onChangeExistingFeatureTypeMainInfos: () => {},
onSubmit: e => {
e.preventDefault();
},
resetExistingContentTypeMainInfos: () => {},
resetNewContentTypeMainInfos: () => {},
updateTempContentType: () => {},
resetExistingFeatureTypeMainInfos: () => {},
resetNewFeatureTypeMainInfos: () => {},
updateTempFeatureType: () => {},
};
ModelForm.propTypes = {
actionType: PropTypes.string,
activeTab: PropTypes.string,
allTakenNames: PropTypes.arrayOf(PropTypes.string).isRequired,
cancelNewContentType: PropTypes.func,
cancelNewFeatureType: PropTypes.func,
connections: PropTypes.arrayOf(PropTypes.string),
createTempContentType: PropTypes.func,
createTempFeatureType: PropTypes.func,
isOpen: PropTypes.bool,
isUpdatingTemporaryContentType: PropTypes.bool,
isUpdatingTemporaryFeatureType: PropTypes.bool,
featureToEditName: PropTypes.string,
featureType: PropTypes.string,
modelToEditName: PropTypes.string,
modifiedData: PropTypes.object,
onChangeExistingContentTypeMainInfos: PropTypes.func,
onChangeNewContentTypeMainInfos: PropTypes.func.isRequired,
onChangeExistingFeatureTypeMainInfos: PropTypes.func,
onChangeNewFeatureTypeMainInfos: PropTypes.func.isRequired,
onSubmit: PropTypes.func,
push: PropTypes.func.isRequired,
resetExistingContentTypeMainInfos: PropTypes.func,
resetNewContentTypeMainInfos: PropTypes.func,
updateTempContentType: PropTypes.func,
resetExistingFeatureTypeMainInfos: PropTypes.func,
resetNewFeatureTypeMainInfos: PropTypes.func,
updateTempFeatureType: PropTypes.func,
};
export default ModelForm;

View File

@ -24,12 +24,12 @@ describe('<ModelForm />', () => {
actionType: 'create',
activeTab: 'base',
allTakenNames: [],
cancelNewContentType: jest.fn(),
cancelNewFeatureType: jest.fn(),
connections: ['default'],
createTempContentType: jest.fn(),
createTempFeatureType: jest.fn(),
isOpen: true,
isUpdatingTemporaryContentType: false,
modelToEditName: '',
isUpdatingTemporaryFeatureType: false,
featureToEditName: '',
modifiedData: {
collectionName: '',
connection: '',
@ -38,13 +38,13 @@ describe('<ModelForm />', () => {
name: '',
attributes: {},
},
onChangeExistingContentTypeMainInfos: jest.fn(),
onChangeNewContentTypeMainInfos: jest.fn(),
onChangeExistingFeatureTypeMainInfos: jest.fn(),
onChangeNewFeatureTypeMainInfos: jest.fn(),
onSubmit: jest.fn(),
push: jest.fn(),
resetExistingContentTypeMainInfos: jest.fn(),
resetNewContentTypeMainInfos: jest.fn(),
updateTempContentType: jest.fn(),
resetExistingFeatureTypeMainInfos: jest.fn(),
resetNewFeatureTypeMainInfos: jest.fn(),
updateTempFeatureType: jest.fn(),
};
});
@ -57,44 +57,42 @@ describe('<ModelForm />', () => {
});
it('should use the defaultProps', () => {
delete props.cancelNewContentType;
delete props.createTempContentType;
delete props.onChangeExistingContentTypeMainInfos;
delete props.cancelNewFeatureType;
delete props.createTempFeatureType;
delete props.onChangeExistingFeatureTypeMainInfos;
delete props.onSubmit;
delete props.resetExistingContentTypeMainInfos;
delete props.resetNewContentTypeMainInfos;
delete props.resetNewContentTypeMainInfos;
delete props.resetNewContentTypeMainInfos;
delete props.updateTempContentType;
delete props.resetExistingFeatureTypeMainInfos;
delete props.resetNewFeatureTypeMainInfos;
delete props.updateTempFeatureType;
wrapper = renderComponent(props);
const {
defaultProps: {
cancelNewContentType,
createTempContentType,
onChangeExistingContentTypeMainInfos,
cancelNewFeatureType,
createTempFeatureType,
onChangeExistingFeatureTypeMainInfos,
onSubmit,
resetExistingContentTypeMainInfos,
resetNewContentTypeMainInfos,
updateTempContentType,
resetExistingFeatureTypeMainInfos,
resetNewFeatureTypeMainInfos,
updateTempFeatureType,
},
} = ModelForm;
expect(cancelNewContentType).toBeDefined();
expect(cancelNewContentType()).toBe(undefined);
expect(createTempContentType).toBeDefined();
expect(createTempContentType()).toBe(undefined);
expect(onChangeExistingContentTypeMainInfos).toBeDefined();
expect(onChangeExistingContentTypeMainInfos()).toBe(undefined);
expect(cancelNewFeatureType).toBeDefined();
expect(cancelNewFeatureType()).toBe(undefined);
expect(createTempFeatureType).toBeDefined();
expect(createTempFeatureType()).toBe(undefined);
expect(onChangeExistingFeatureTypeMainInfos).toBeDefined();
expect(onChangeExistingFeatureTypeMainInfos()).toBe(undefined);
expect(onSubmit).toBeDefined();
expect(onSubmit({ preventDefault: jest.fn() })).toBe(undefined);
expect(resetExistingContentTypeMainInfos).toBeDefined();
expect(resetExistingContentTypeMainInfos()).toBe(undefined);
expect(resetNewContentTypeMainInfos).toBeDefined();
expect(resetNewContentTypeMainInfos()).toBe(undefined);
expect(updateTempContentType).toBeDefined();
expect(updateTempContentType()).toBe(undefined);
expect(resetExistingFeatureTypeMainInfos).toBeDefined();
expect(resetExistingFeatureTypeMainInfos()).toBe(undefined);
expect(resetNewFeatureTypeMainInfos).toBeDefined();
expect(resetNewFeatureTypeMainInfos()).toBe(undefined);
expect(updateTempFeatureType).toBeDefined();
expect(updateTempFeatureType()).toBe(undefined);
});
it('should not show the inputs until the modal is fully opened', () => {
@ -116,7 +114,7 @@ describe('<ModelForm />', () => {
it('should handle the edition of a temporary CT correctly for the inputs settings', () => {
props.actionType = 'edit';
props.isUpdatingTemporaryContentType = true;
props.isUpdatingTemporaryFeatureType = true;
wrapper = renderComponent(props);
wrapper.setState({ isVisible: true });
@ -128,13 +126,13 @@ describe('<ModelForm />', () => {
input.simulate('change');
expect(props.onChangeNewContentTypeMainInfos).toHaveBeenCalled();
expect(props.onChangeNewFeatureTypeMainInfos).toHaveBeenCalled();
});
it('should handle the edition of a saved CT correctly for the inputs settings', () => {
props.actionType = 'edit';
props.isUpdatingTemporaryContentType = false;
props.modelToEditName = 'test';
props.isUpdatingTemporaryFeatureType = false;
props.featureToEditName = 'test';
wrapper = renderComponent(props);
wrapper.setState({ isVisible: true });
@ -146,7 +144,7 @@ describe('<ModelForm />', () => {
input.simulate('change');
expect(props.onChangeExistingContentTypeMainInfos).toHaveBeenCalled();
expect(props.onChangeExistingFeatureTypeMainInfos).toHaveBeenCalled();
});
describe('Instances', () => {
@ -178,7 +176,7 @@ describe('<ModelForm />', () => {
describe('HandleGoTo', () => {
it('should add the modelName when navvigating if the user is editing a model', () => {
props.actionType = 'edit';
props.modelToEditName = 'test';
props.featureToEditName = 'test';
wrapper = renderComponent(props);
const { handleGoTo } = wrapper.instance();
@ -210,46 +208,46 @@ describe('<ModelForm />', () => {
});
describe('HandleCancel', () => {
it('should call only the cancelNewContentType if the actionType is create', () => {
it('should call only the cancelNewFeatureType if the actionType is create', () => {
wrapper = renderComponent(props);
const { handleCancel } = wrapper.instance();
handleCancel();
expect(props.cancelNewContentType).toHaveBeenCalled();
expect(props.resetNewContentTypeMainInfos).not.toHaveBeenCalled();
expect(props.resetExistingContentTypeMainInfos).not.toHaveBeenCalled();
expect(props.cancelNewFeatureType).toHaveBeenCalled();
expect(props.resetNewFeatureTypeMainInfos).not.toHaveBeenCalled();
expect(props.resetExistingFeatureTypeMainInfos).not.toHaveBeenCalled();
expect(props.push).toHaveBeenCalledWith({ search: '' });
});
it('should call only the resetNewContentTypeMainInfos if the actionType is edit and if the user is editing a temporary ct', () => {
it('should call only the resetNewFeatureTypeMainInfos if the actionType is edit and if the user is editing a temporary ct', () => {
props.actionType = 'edit';
props.isUpdatingTemporaryContentType = true;
props.isUpdatingTemporaryFeatureType = true;
wrapper = renderComponent(props);
const { handleCancel } = wrapper.instance();
handleCancel();
expect(props.cancelNewContentType).not.toHaveBeenCalled();
expect(props.resetNewContentTypeMainInfos).toHaveBeenCalled();
expect(props.resetExistingContentTypeMainInfos).not.toHaveBeenCalled();
expect(props.cancelNewFeatureType).not.toHaveBeenCalled();
expect(props.resetNewFeatureTypeMainInfos).toHaveBeenCalled();
expect(props.resetExistingFeatureTypeMainInfos).not.toHaveBeenCalled();
expect(props.push).toHaveBeenCalledWith({ search: '' });
});
it('should call only the resetExistingContentTypeMainInfos if the actionType is edit and if the user is not editing a temporary ct', () => {
it('should call only the resetExistingFeatureTypeMainInfos if the actionType is edit and if the user is not editing a temporary ct', () => {
props.actionType = 'edit';
props.isUpdatingTemporaryContentType = false;
props.isUpdatingTemporaryFeatureType = false;
wrapper = renderComponent(props);
const { handleCancel } = wrapper.instance();
handleCancel();
expect(props.cancelNewContentType).not.toHaveBeenCalled();
expect(props.resetNewContentTypeMainInfos).not.toHaveBeenCalled();
expect(props.resetExistingContentTypeMainInfos).toHaveBeenCalled();
expect(props.cancelNewFeatureType).not.toHaveBeenCalled();
expect(props.resetNewFeatureTypeMainInfos).not.toHaveBeenCalled();
expect(props.resetExistingFeatureTypeMainInfos).toHaveBeenCalled();
expect(props.push).toHaveBeenCalledWith({ search: '' });
});
});
@ -271,7 +269,7 @@ describe('<ModelForm />', () => {
it('should not submit if the name of the CT is already taken', () => {
props.allTakenNames = ['test'];
props.modifiedData.name = 'test';
props.modelToEditName = '';
props.featureToEditName = '';
props.actionType = 'create';
wrapper = renderComponent(props);
@ -298,16 +296,16 @@ describe('<ModelForm />', () => {
pathname: `/plugins/${pluginId}/models/test`,
search: 'modalType=chooseAttributes',
});
expect(props.createTempContentType).toHaveBeenCalled();
expect(props.updateTempContentType).not.toHaveBeenCalled();
expect(props.createTempFeatureType).toHaveBeenCalled();
expect(props.updateTempFeatureType).not.toHaveBeenCalled();
});
it('should submit if the form is not empty and the user is editing a temporary CT', () => {
props.modifiedData.name = 'test';
props.allTakenNames = ['test'];
props.actionType = 'edit';
props.isUpdatingTemporaryContentType = true;
props.modelToEditName = 'test';
props.isUpdatingTemporaryFeatureType = true;
props.featureToEditName = 'test';
wrapper = renderComponent(props);
const { handleSubmit } = wrapper.instance();
@ -319,16 +317,16 @@ describe('<ModelForm />', () => {
pathname: '/plugins/content-type-builder/models/test',
search: '',
});
expect(props.createTempContentType).not.toHaveBeenCalled();
expect(props.updateTempContentType).toHaveBeenCalled();
expect(props.createTempFeatureType).not.toHaveBeenCalled();
expect(props.updateTempFeatureType).toHaveBeenCalled();
});
it('should submit if the form is not empty and the user is editing a saved CT', () => {
props.modifiedData.name = 'test';
props.actionType = 'edit';
props.isUpdatingTemporaryContentType = false;
props.isUpdatingTemporaryFeatureType = false;
props.allTakenNames = ['test'];
props.modelToEditName = 'test';
props.featureToEditName = 'test';
wrapper = renderComponent(props);
const { handleSubmit } = wrapper.instance();
@ -339,8 +337,8 @@ describe('<ModelForm />', () => {
expect(props.push).toHaveBeenCalledWith({
search: '',
});
expect(props.updateTempContentType).not.toHaveBeenCalled();
expect(props.createTempContentType).not.toHaveBeenCalled();
expect(props.updateTempFeatureType).not.toHaveBeenCalled();
expect(props.createTempFeatureType).not.toHaveBeenCalled();
});
});
});

View File

@ -155,9 +155,13 @@
"popUpForm.create.contentType.header.title": "New Content Type",
"popUpForm.create.contentType.header.subtitle": "Name your Content Type",
"popUpForm.create.model.header.title": "Create a Content Type",
"popUpForm.edit.model.header.title": "Edit the Content Type",
"popUpForm.create.group.header.title": "Create a Group",
"popUpForm.edit.group.header.title": "Edit the Group",
"popUpForm.create.model.header.subTitle": "Content Type's Settings",
"popUpForm.edit.model.header.subTitle": "{name}'s Settings",
"popUpForm.create.group.header.subTitle": "Group's Settings",
"popUpForm.edit.group.header.subTitle": "{name}'s Settings",
"popUpForm.edit": "Edit",
"popUpForm.edit.contentType.header.title": "Edit Content Type",
"popUpForm.field": "Field",

View File

@ -5,7 +5,7 @@ module.exports = {
const groups = {
data: [
{
uid: 'ingredients',
uid: 'ingredientes',
name: 'Ingredients',
source: null,
schema: {