Skip to content

Commit

Permalink
Implemented "show" and "defaultValue" options for a field of an entit…
Browse files Browse the repository at this point in the history
…y form. (wasp-lang#76)
  • Loading branch information
matijaSos committed Jan 28, 2020
1 parent a717a06 commit e2a885b
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,15 @@ export default class {= name =} extends React.Component {
// TODO: Add propTypes.

state = {
// TODO(matija): Currently we hardcoded default values for each field type.
// In the future we might let user decide on the default value.
fields: {
{=# entityTypedFields =}
{=# formFields =}
{=# boolean =}
{= name =}: false,
{= name =}: {= defaultValue =},
{=/ boolean =}
{=# string =}
{= name =}: '',
{= name =}: '{= defaultValue =}',
{=/ string =}
{=/ entityTypedFields =}
{=/ formFields =}
}
}

Expand All @@ -38,14 +36,14 @@ export default class {= name =} extends React.Component {
}

resetAllFields = () => {
{=# entityTypedFields =}
{=# formFields =}
{=# boolean =}
this.setField('{= name =}', false)
this.setField('{= name =}', {= defaultValue =})
{=/ boolean =}
{=# string =}
this.setField('{= name =}', '')
this.setField('{= name =}', '{= defaultValue =}')
{=/ string =}
{=/ entityTypedFields =}
{=/ formFields =}
}

toggleField = (name) => {
Expand All @@ -66,9 +64,10 @@ export default class {= name =} extends React.Component {
<div style={ { margin: '20px' } }>
<form noValidate onSubmit={this.handleSubmit} action="javascript:void(0);">

{=# entityTypedFields =}
{=# formFields =}

{=# boolean =}
{=# show =}
<div>
<FormControlLabel
label="{= name =}"
Expand All @@ -81,9 +80,11 @@ export default class {= name =} extends React.Component {
}
/>
</div>
{=/ show =}
{=/ boolean =}

{=# string =}
{=# show =}
<div>
<TextField
label="{= name =}"
Expand All @@ -92,9 +93,10 @@ export default class {= name =} extends React.Component {
margin="normal"
/>
</div>
{=/ show =}
{=/ string =}

{=/ entityTypedFields =}
{=/ formFields =}

{=# showSubmitButton =}
<div>
Expand Down
3 changes: 1 addition & 2 deletions examples/todoMVC/todoMVC.wasp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ page Main {
entity-form<Task> NewTaskForm {
fields: {
description: {
show: true,
defaultValue: "doableTask"
show: true
},
isDone: {
show: false,
Expand Down
17 changes: 12 additions & 5 deletions src/Generator/Entity/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Generator.Entity.Common
, entityTemplateData
, entityComponentsDirPathInSrc
, entityFieldToJsonWithTypeAsKey
, addEntityFieldTypeToJsonAsKeyWithValueTrue
, getEntityLowerName
, getEntityClassName
) where
Expand Down Expand Up @@ -61,8 +62,14 @@ Mustache template we cannot check if type == "boolean", but only whether a "bool
is set or not.
-}
entityFieldToJsonWithTypeAsKey :: EntityField -> Aeson.Value
entityFieldToJsonWithTypeAsKey entityField =
Util.jsonSet (toText efType) (Aeson.toJSON True) $ Aeson.toJSON entityField
where
toText = Text.pack . show
efType = entityFieldType entityField
entityFieldToJsonWithTypeAsKey entityField = addEntityFieldTypeToJsonAsKeyWithValueTrue
(entityFieldType entityField)
(Aeson.toJSON entityField)

-- | Adds "FIELD_TYPE: true" to a given json. This is needed for Mustache so we can differentiate
-- between the form fields of different types.
addEntityFieldTypeToJsonAsKeyWithValueTrue :: EntityFieldType -> Aeson.Value -> Aeson.Value
addEntityFieldTypeToJsonAsKeyWithValueTrue efType json =
Util.jsonSet (toText efType) (Aeson.toJSON True) json
where
toText = Text.pack . show
101 changes: 76 additions & 25 deletions src/Generator/Entity/EntityForm.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,126 @@ module Generator.Entity.EntityForm

-- For testing
, entityCreateFormPathInSrc
, FormFieldTemplateData(..)
) where

import Data.Aeson ((.=), object, ToJSON(..))
import qualified Data.Aeson as Aeson
import Control.Exception (assert)
import Data.Maybe (fromJust)
import Path ((</>), reldir, relfile)
import qualified Path
import qualified Path.Aliases as Path
import qualified Util

import Wasp
import qualified Wasp.EntityForm as EF
import Wasp.EntityForm (EntityForm)
import qualified Wasp as Wasp
import Wasp (Wasp)

import qualified Wasp.EntityForm as EF
import Generator.FileDraft
import qualified Generator.Entity.Common as EC
import qualified Generator.Common as Common

data TemplateData = TemplateData
{ _name :: !String
-- | Data which will be fed to the Mustache "create form" template.
data EntityFormTemplateData = EntityFormTemplateData
{ _formName :: !String
, _entityClassName :: !String
, _entityFields :: ![EntityField]
, _formFields :: ![FormFieldTemplateData]
-- Submit
, _showSubmitButton :: !Bool
} deriving (Show)

instance ToJSON TemplateData where
instance ToJSON EntityFormTemplateData where
toJSON td = object
[ "name" .= _name td
[ "name" .= _formName td
, "entityClassName" .= _entityClassName td
, "entityTypedFields" .= map EC.entityFieldToJsonWithTypeAsKey (_entityFields td)
, "formFields" .= _formFields td
, "showSubmitButton" .= _showSubmitButton td
]

createEntityFormTemplateData :: Entity -> EntityForm -> Aeson.Value
createEntityFormTemplateData entity entityForm =
assert (entityName entity == EF._entityName entityForm) $
-- | Represents template data for the individual form field.
data FormFieldTemplateData = FormFieldTemplateData
{ _fieldName :: !String
, _fieldType :: Wasp.EntityFieldType
, _fieldShow :: !Bool
, _fieldDefaultValue :: !EF.DefaultValue
} deriving (Show)

instance ToJSON FormFieldTemplateData where
toJSON f = EC.addEntityFieldTypeToJsonAsKeyWithValueTrue (_fieldType f) $
object
[ "name" .= _fieldName f
, "type" .= _fieldType f
, "show" .= _fieldShow f
, "defaultValue" .= case (_fieldDefaultValue f) of
(EF.DefaultValueString s) -> s
(EF.DefaultValueBool b) -> Util.toLowerFirst $ show b
]

-- | Given entity and an entity form for it, creates a single data structure
-- with all the values needed by the template to generate the form.
createEntityFormTemplateData :: Wasp.Entity -> EF.EntityForm -> EntityFormTemplateData
createEntityFormTemplateData entity entityForm =
assert (Wasp.entityName entity == EF._entityName entityForm) $

toJSON $ TemplateData
{ _name = EF._name entityForm
, _entityClassName = EC.getEntityClassName entity
, _entityFields = entityFields entity
-- Submit
, _showSubmitButton = maybe True id maybeShowSubmitButton
}
EntityFormTemplateData
{ _formName = EF._name entityForm
, _entityClassName = EC.getEntityClassName entity
, _formFields = map (createFormField entityForm) $ Wasp.entityFields entity
-- Submit
, _showSubmitButton = maybe True id maybeShowSubmitButton
}
where
maybeShowSubmitButton :: Maybe Bool
maybeShowSubmitButton = EF._submit entityForm >>= EF._submitButton >>= EF._submitButtonShow

-- | Given field data from entity and an entity form for it, creates a single
-- data structure with all the values needed by the template to generate a form field.
createFormField :: EF.EntityForm -> Wasp.EntityField -> FormFieldTemplateData
createFormField entityForm entityField = FormFieldTemplateData
{ _fieldName = Wasp.entityFieldName entityField
, _fieldType = Wasp.entityFieldType entityField
, _fieldShow = maybe True id $ formFieldConfig >>= EF._fieldShow
, _fieldDefaultValue = maybe
defaultValueIfNothingInForm
id
$ formFieldConfig >>= EF._fieldDefaultValue
}
where
-- Configuration of a form field within entity-form, if there is any.
formFieldConfig :: Maybe EF.Field
formFieldConfig = EF.getConfigForField entityForm entityField

getDefaultValueForFieldWithType :: Wasp.EntityFieldType -> EF.DefaultValue
getDefaultValueForFieldWithType efType = case efType of
Wasp.EftString -> EF.DefaultValueString ""
Wasp.EftBoolean -> EF.DefaultValueBool False

-- If user did not explicitly set a default value, we determine it ourselves.
defaultValueIfNothingInForm :: EF.DefaultValue
defaultValueIfNothingInForm =
getDefaultValueForFieldWithType $ Wasp.entityFieldType entityField


-- | Generates entity creation form.
generateEntityCreateForm :: Wasp -> EntityForm -> FileDraft
generateEntityCreateForm :: Wasp -> EF.EntityForm -> FileDraft
generateEntityCreateForm wasp entityForm =
createTemplateFileDraft dstPath templateSrcPath (Just templateData)
where
-- NOTE(matija): There should always be an entity in wasp for the given entity form,
-- we want an error to be thrown otherwise.
entity = maybe
(error $ "Wasp must contain entity to which the entity form refers: " ++
EF._entityName entityForm)
EF._entityName entityForm)
id
(getEntityByName wasp (EF._entityName entityForm))
(Wasp.getEntityByName wasp (EF._entityName entityForm))

templateSrcPath = EC.entityTemplatesDirPath </> [reldir|components|] </> [relfile|CreateForm.js|]

dstPath = Common.srcDirPath </> (entityCreateFormPathInSrc entity entityForm)

templateData = createEntityFormTemplateData entity entityForm
templateData = toJSON $ createEntityFormTemplateData entity entityForm

entityCreateFormPathInSrc :: Entity -> EntityForm -> Path.RelFile
entityCreateFormPathInSrc :: Wasp.Entity -> EF.EntityForm -> Path.RelFile
entityCreateFormPathInSrc entity entityForm =
EC.entityComponentsDirPathInSrc entity </>
(fromJust $ Path.parseRelFile $ (EF._name entityForm) ++ ".js")
14 changes: 14 additions & 0 deletions src/Wasp/EntityForm.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ module Wasp.EntityForm
, SubmitButton(..)
, Field(..)
, DefaultValue(..)
, getConfigForField
) where

import Data.Aeson ((.=), object, ToJSON(..))

import qualified Util as U
import qualified Wasp.Entity as Entity


data EntityForm = EntityForm
{ _name :: !String -- Name of the form
, _entityName :: !String -- Name of the entity the form is linked to
Expand All @@ -23,6 +28,15 @@ instance ToJSON EntityForm where
, "submitConfig" .= _submit entityForm
]

-- | For a given entity field, returns its configuration from the given entity-form, if present.
getConfigForField :: EntityForm -> Entity.EntityField -> Maybe Field
getConfigForField entityForm entityField =
U.headSafe $ filter isConfigOfInputEntityField $ _fields entityForm
where
isConfigOfInputEntityField :: Field -> Bool
isConfigOfInputEntityField =
(== Entity.entityFieldName entityField) . _fieldName

-- * Submit

data Submit = Submit
Expand Down
9 changes: 9 additions & 0 deletions test/Fixtures.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Fixtures where

import Wasp
import qualified Wasp.EntityForm as EF
import qualified Generator.Entity.EntityForm as GEF

app :: App
app = App
Expand Down Expand Up @@ -52,3 +53,11 @@ wasp = fromWaspElems
, WaspElementEntity taskEntity
, WaspElementEntityForm taskCreateForm
]

formFieldIsDone :: GEF.FormFieldTemplateData
formFieldIsDone = GEF.FormFieldTemplateData
{ GEF._fieldName = "isDone"
, GEF._fieldType = Wasp.EftBoolean
, GEF._fieldShow = True
, GEF._fieldDefaultValue = EF.DefaultValueBool True
}
9 changes: 9 additions & 0 deletions testEnv.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{- stack
exec ghci
--package pretty-simple
--package aeson-pretty
--
test/Fixtures.hs
-}
Expand All @@ -14,4 +15,12 @@
-}

import Text.Pretty.Simple (pPrint)
import Data.Aeson
import Data.Aeson.Encode.Pretty
import Data.ByteString.Lazy.Char8 as L

import Fixtures

-- | Prints any ToJSON instance, useful when testing parser.
printJSON :: ToJSON a => a -> IO ()
printJSON = L.putStrLn . encodePretty

0 comments on commit e2a885b

Please sign in to comment.