mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-25 18:13:52 +03:00
Implemented List component for entity. (#32)
This commit is contained in:
parent
c9d52d6c20
commit
46ed578d36
@ -7,6 +7,7 @@ import * as {= entityLowerName =}State from '{= entityStatePath =}'
|
||||
import * as {= entityLowerName =}Actions from '{= entityActionsPath =}'
|
||||
import {= entity.name =} from '{= entityClassPath =}'
|
||||
import {= entity.name =}CreateForm from '{= entityCreateFormPath =}'
|
||||
import {= entity.name =}List from '{= entityListPath =}'
|
||||
{=/ entities =}
|
||||
|
||||
|
||||
|
68
stic/data/Generator/templates/react-app/src/entities/_entity/components/List.js
vendored
Normal file
68
stic/data/Generator/templates/react-app/src/entities/_entity/components/List.js
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
{{={= =}=}}
|
||||
import _ from 'lodash'
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import Paper from '@material-ui/core/Paper'
|
||||
import Table from '@material-ui/core/Table'
|
||||
import TableBody from '@material-ui/core/TableBody'
|
||||
import TableCell from '@material-ui/core/TableCell'
|
||||
import TableHead from '@material-ui/core/TableHead'
|
||||
import TableRow from '@material-ui/core/TableRow'
|
||||
|
||||
import * as {= entityLowerName =}State from '../state'
|
||||
|
||||
import {= entityClassName =} from '../{= entityClassName =}'
|
||||
|
||||
|
||||
export class List extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={ { margin: '20px' } }>
|
||||
<Paper>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{=# entityTypedFields =}
|
||||
{=# boolean =}
|
||||
<TableCell>{= name =} (bool)</TableCell>
|
||||
{=/ boolean =}
|
||||
{=# string =}
|
||||
<TableCell>{= name =} (string)</TableCell>
|
||||
{=/ string =}
|
||||
{=/ entityTypedFields =}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
|
||||
<TableBody>
|
||||
{this.props.{= entityLowerName =}List.map({= entityLowerName =} => (
|
||||
<TableRow>
|
||||
{=# entityTypedFields =}
|
||||
{=# boolean =}
|
||||
<TableCell>
|
||||
{{= entityLowerName =}.{= name =} || 'no bool value'}
|
||||
</TableCell>
|
||||
{=/ boolean =}
|
||||
{=# string =}
|
||||
<TableCell>
|
||||
{{= entityLowerName =}.{= name =} || 'no string value'}
|
||||
</TableCell>
|
||||
{=/ string =}
|
||||
{=/ entityTypedFields =}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Paper>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(state => ({
|
||||
// Selectors
|
||||
{= entityLowerName =}List: {= entityLowerName =}State.selectors.all(state)
|
||||
}), {
|
||||
// Actions
|
||||
})(List)
|
@ -6,6 +6,7 @@ module Generator.EntityGenerator
|
||||
, entityStatePathInSrc
|
||||
, entityActionsPathInSrc
|
||||
, entityCreateFormPathInSrc
|
||||
, entityListPathInSrc
|
||||
|
||||
-- EXPORTED FOR TESTING:
|
||||
, generateEntityClass
|
||||
@ -17,6 +18,7 @@ module Generator.EntityGenerator
|
||||
|
||||
import Data.Aeson ((.=), object)
|
||||
import qualified Data.Aeson as Aeson
|
||||
import qualified Data.Text as Text
|
||||
import System.FilePath (FilePath, (</>), (<.>))
|
||||
|
||||
import qualified Util
|
||||
@ -56,6 +58,7 @@ generateEntityActions wasp entity
|
||||
generateEntityComponents :: Wasp -> Entity -> [FileDraft]
|
||||
generateEntityComponents wasp entity =
|
||||
[ generateEntityCreateForm wasp entity
|
||||
, generateEntityList wasp entity
|
||||
]
|
||||
|
||||
-- TODO: add tests / update tests.
|
||||
@ -76,6 +79,13 @@ generateEntityCreateForm wasp entity
|
||||
= createSimpleEntityFileDraft wasp entity (entityCreateFormPathInSrc entity)
|
||||
("components" </> "CreateForm.js")
|
||||
|
||||
-- TODO(matija): do I need wasp at all?
|
||||
-- | Generates list component for the specified entity, so user can see all the
|
||||
-- entity instances.
|
||||
generateEntityList :: Wasp -> Entity -> FileDraft
|
||||
generateEntityList wasp entity
|
||||
= createSimpleEntityFileDraft wasp entity (entityListPathInSrc entity)
|
||||
("components" </> "List.js")
|
||||
|
||||
-- | Helper function that captures common logic for generating entity file draft.
|
||||
createSimpleEntityFileDraft :: Wasp -> Entity -> FilePath -> FilePath -> FileDraft
|
||||
@ -86,6 +96,22 @@ createSimpleEntityFileDraft wasp entity dstPathInSrc srcPathInEntityTemplatesDir
|
||||
dstPath = "src" </> dstPathInSrc
|
||||
templateData = entityTemplateData wasp entity
|
||||
|
||||
{- | Converts entity field to a JSON where field type is a key to the object holding
|
||||
all the other properties. E.g. a field of type boolean could look this as JSON:
|
||||
|
||||
{ boolean: { name: "description", type: "boolean" }
|
||||
|
||||
This method is needed to achieve conditional rendering with Mustache.
|
||||
-}
|
||||
entityFieldToJsonWithTypeAsKey :: EntityField -> Aeson.Value
|
||||
entityFieldToJsonWithTypeAsKey entityField = object
|
||||
-- TODO(matija): maybe it would be cleaner to have a flat structure, like
|
||||
-- { boolean: true, type: "boolean", name: "description" }
|
||||
[ (toText $ entityFieldType entityField) .= entityField
|
||||
]
|
||||
where
|
||||
toText = Text.pack . show
|
||||
|
||||
-- | Default generic data for entity templates.
|
||||
entityTemplateData :: Wasp -> Entity -> Aeson.Value
|
||||
entityTemplateData wasp entity = object
|
||||
@ -95,6 +121,7 @@ entityTemplateData wasp entity = object
|
||||
-- TODO: this entityClassName is used only in CreateForm, use it also when creating
|
||||
-- Class file itself and in other files.
|
||||
, "entityClassName" .= (Util.toUpperFirst $ entityName entity)
|
||||
, "entityTypedFields" .= map entityFieldToJsonWithTypeAsKey (entityFields entity)
|
||||
]
|
||||
|
||||
-- | Location in templates where entity related templates reside.
|
||||
@ -119,8 +146,13 @@ entityActionTypesPathInSrc entity = (entityDirPathInSrc entity) </> "actionTypes
|
||||
entityClassPathInSrc :: Entity -> FilePath
|
||||
entityClassPathInSrc entity = (entityDirPathInSrc entity) </> (entityName entity) <.> "js"
|
||||
|
||||
-- * Components
|
||||
|
||||
entityComponentsDirPathInSrc :: Entity -> FilePath
|
||||
entityComponentsDirPathInSrc entity = (entityDirPathInSrc entity) </> "components"
|
||||
|
||||
entityCreateFormPathInSrc :: Entity -> FilePath
|
||||
entityCreateFormPathInSrc entity = (entityComponentsDirPathInSrc entity) </> "CreateForm.js"
|
||||
|
||||
entityListPathInSrc :: Entity -> FilePath
|
||||
entityListPathInSrc entity = (entityComponentsDirPathInSrc entity) </> "List.js"
|
||||
|
@ -35,4 +35,5 @@ generatePage wasp page = createTemplateFileDraft dstPath srcPath templateData
|
||||
, "entityActionsPath" .= ("./" ++ (EntityGenerator.entityActionsPathInSrc entity))
|
||||
, "entityClassPath" .= ("./" ++ (EntityGenerator.entityClassPathInSrc entity))
|
||||
, "entityCreateFormPath" .= ("./" ++ (EntityGenerator.entityCreateFormPathInSrc entity))
|
||||
, "entityListPath" .= ("./" ++ (EntityGenerator.entityListPathInSrc entity))
|
||||
]
|
||||
|
@ -5,6 +5,7 @@ module Generator.Templates
|
||||
) where
|
||||
|
||||
import qualified Text.Mustache as Mustache
|
||||
import Text.Mustache.Render (SubstitutionError(..))
|
||||
import qualified Data.Aeson as Aeson
|
||||
import System.FilePath ((</>))
|
||||
import Data.Text (Text)
|
||||
@ -50,11 +51,23 @@ compileMustacheTemplate templateRelPath = do
|
||||
raiseCompileError err = error $ -- TODO: Handle these errors better?
|
||||
printf "Compilation of template %s failed. %s" templateRelPath (show err)
|
||||
|
||||
areAllErrorsSectionDataNotFound :: [SubstitutionError] -> Bool
|
||||
areAllErrorsSectionDataNotFound subsErrors = all isSectionDataNotFoundError subsErrors
|
||||
where
|
||||
isSectionDataNotFoundError e = case e of
|
||||
SectionTargetNotFound _ -> True
|
||||
_ -> False
|
||||
|
||||
renderMustacheTemplate :: Mustache.Template -> Aeson.Value -> IO Text
|
||||
renderMustacheTemplate mustacheTemplate templateData = do
|
||||
let mustacheTemplateData = Mustache.toMustache templateData
|
||||
let (errors, fileText) =
|
||||
Mustache.checkedSubstituteValue mustacheTemplate mustacheTemplateData
|
||||
if (null errors) -- TODO: Handle these errors better.
|
||||
|
||||
-- NOTE(matija): Mustache reports errors when object does
|
||||
-- not have a property specified in the template, which we use to implement
|
||||
-- conditionals. This is why we ignore these errors.
|
||||
if (null errors) || (areAllErrorsSectionDataNotFound errors)
|
||||
then (return fileText)
|
||||
else (error $ "Errors occured while rendering template: " ++ (show errors))
|
||||
else (error $ "Unexpected errors occured while rendering template: "
|
||||
++ (show errors))
|
||||
|
@ -20,6 +20,8 @@ module Wasp
|
||||
) where
|
||||
|
||||
import Data.Aeson ((.=), object, ToJSON(..))
|
||||
import qualified Data.Aeson as Aeson
|
||||
import qualified Data.Text as T
|
||||
|
||||
|
||||
-- * Wasp
|
||||
@ -88,7 +90,11 @@ data EntityField = EntityField
|
||||
, entityFieldType :: !EntityFieldType
|
||||
} deriving (Show, Eq)
|
||||
|
||||
data EntityFieldType = EftString | EftBoolean deriving (Show, Eq)
|
||||
data EntityFieldType = EftString | EftBoolean deriving (Eq)
|
||||
|
||||
instance Show EntityFieldType where
|
||||
show EftString = "string"
|
||||
show EftBoolean = "boolean"
|
||||
|
||||
getEntities :: Wasp -> [Entity]
|
||||
getEntities (Wasp elems) = [entity | (WaspElementEntity entity) <- elems]
|
||||
@ -96,6 +102,7 @@ getEntities (Wasp elems) = [entity | (WaspElementEntity entity) <- elems]
|
||||
addEntity :: Wasp -> Entity -> Wasp
|
||||
addEntity (Wasp elems) entity = Wasp $ (WaspElementEntity entity):elems
|
||||
|
||||
|
||||
-- * ToJSON instances.
|
||||
|
||||
-- NOTE(martin): Here I define general transformation of App into JSON that I can then easily use
|
||||
@ -128,8 +135,7 @@ instance ToJSON EntityField where
|
||||
]
|
||||
|
||||
instance ToJSON EntityFieldType where
|
||||
toJSON EftString = "string"
|
||||
toJSON EftBoolean = "boolean"
|
||||
toJSON = Aeson.String . T.pack . show
|
||||
|
||||
instance ToJSON Wasp where
|
||||
toJSON wasp = object
|
||||
|
@ -37,6 +37,9 @@ spec_parseWasp =
|
||||
\ submitButtonLabel={'Create new task'}\n\
|
||||
\ />\n\
|
||||
\ </div>\n\
|
||||
\\n\
|
||||
\ My tasks\n\
|
||||
\ <TaskList />\n\
|
||||
\ </div>"
|
||||
}
|
||||
, WaspElementPage $ Page
|
||||
|
@ -19,6 +19,9 @@ page Landing {
|
||||
submitButtonLabel={'Create new task'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
My tasks
|
||||
<TaskList />
|
||||
</div>
|
||||
jsx=}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user