mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-26 10:35:04 +03:00
Implemented parsing and generation of entity-list field render function. (#84)
This commit is contained in:
parent
c695f30704
commit
f955fa6a8d
@ -49,6 +49,14 @@ export class {= listName =} extends React.Component {
|
||||
this.setState({ {= entityBeingEditedStateVar =}: null })
|
||||
}
|
||||
|
||||
{=! Render "render" functions for each field, if provided =}
|
||||
{=# listFields =}
|
||||
{=# render =}
|
||||
{= renderFnName =} =
|
||||
{=& render =}
|
||||
{=/ render =}
|
||||
{=/ listFields =}
|
||||
|
||||
render() {
|
||||
const {= entityLowerName =}ListToShow = this.props.filter ?
|
||||
{=! TODO(matija): duplication, we could extract entityLowerName_List =}
|
||||
@ -104,7 +112,12 @@ export class {= listName =} extends React.Component {
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
{=# render =}
|
||||
this.{= renderFnName =}({= entityLowerName =})
|
||||
{=/ render =}
|
||||
{=^ render =}
|
||||
{= entityLowerName =}.{= name =}
|
||||
{=/ render =}
|
||||
)}
|
||||
</TableCell>
|
||||
</ClickAwayListener>
|
||||
|
@ -68,5 +68,18 @@ entity-form<Task> NewTaskForm {
|
||||
|
||||
// Entity list definition.
|
||||
entity-list<Task> TaskList {
|
||||
// Options TBD, not supported for now.
|
||||
fields: {
|
||||
description: {
|
||||
// The contract for render is: user must provide a function that:
|
||||
// - receives a task as an input
|
||||
// - returns a React Node or something that can be rendered by JSX
|
||||
// - does not depend on any outer context
|
||||
render: {=js
|
||||
(task) => {
|
||||
if (task.isDone) return (<s>{task.description}</s>)
|
||||
return task.description
|
||||
}
|
||||
js=}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,10 +105,12 @@ entity-list<Task> TaskList {
|
||||
// - receives a task as an input
|
||||
// - returns a React Node or something that can be rendered by JSX
|
||||
// - does not depend on any outer context
|
||||
render: (task) => {
|
||||
if (task.isDone) return (<s>task.description</s>)
|
||||
render: {=js
|
||||
(task) => {
|
||||
if (task.isDone) return (<s>{task.description}</s>)
|
||||
return task.description
|
||||
}
|
||||
js=}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,18 @@ import Data.Maybe (fromJust)
|
||||
import Path ((</>), reldir, relfile, parseRelFile)
|
||||
import qualified Path.Aliases as Path
|
||||
|
||||
import qualified Util as U
|
||||
|
||||
import qualified Wasp
|
||||
import Wasp (Wasp)
|
||||
import qualified Wasp.EntityList as WEL
|
||||
import qualified Wasp.JsCode
|
||||
|
||||
import qualified Generator.FileDraft as FD
|
||||
import qualified Generator.Entity.Common as EC
|
||||
import qualified Generator.Common as Common
|
||||
|
||||
|
||||
data EntityListTemplateData = EntityListTemplateData
|
||||
{ _listName :: !String
|
||||
, _entityName :: !String
|
||||
@ -40,6 +44,8 @@ instance ToJSON EntityListTemplateData where
|
||||
data ListFieldTemplateData = ListFieldTemplateData
|
||||
{ _fieldName :: !String
|
||||
, _fieldType :: !Wasp.EntityFieldType
|
||||
, _fieldRender :: Maybe Wasp.JsCode.JsCode
|
||||
, _fieldRenderFnName :: String
|
||||
}
|
||||
|
||||
instance ToJSON ListFieldTemplateData where
|
||||
@ -47,6 +53,8 @@ instance ToJSON ListFieldTemplateData where
|
||||
object
|
||||
[ "name" .= _fieldName f
|
||||
, "type" .= _fieldType f
|
||||
, "render" .= _fieldRender f
|
||||
, "renderFnName" .= _fieldRenderFnName f
|
||||
]
|
||||
|
||||
createEntityListTemplateData :: Wasp.Entity -> WEL.EntityList -> EntityListTemplateData
|
||||
@ -58,17 +66,26 @@ createEntityListTemplateData entity entityList =
|
||||
, _entityName = Wasp.entityName entity
|
||||
, _entityClassName = EC.getEntityClassName entity
|
||||
, _entityLowerName = EC.getEntityLowerName entity
|
||||
, _listFields = map (createListFieldTD entityList) $ Wasp.entityFields entity
|
||||
, _listFields = map (createListFieldTD entity entityList) $ Wasp.entityFields entity
|
||||
, _entityBeingEditedStateVar = entityLowerName ++ "BeingEdited"
|
||||
}
|
||||
where
|
||||
entityLowerName = EC.getEntityLowerName entity
|
||||
|
||||
createListFieldTD :: WEL.EntityList -> Wasp.EntityField -> ListFieldTemplateData
|
||||
createListFieldTD _ entityField = ListFieldTemplateData
|
||||
createListFieldTD :: Wasp.Entity -> WEL.EntityList -> Wasp.EntityField -> ListFieldTemplateData
|
||||
createListFieldTD entity entityList entityField = ListFieldTemplateData
|
||||
{ _fieldName = Wasp.entityFieldName entityField
|
||||
, _fieldType = Wasp.entityFieldType entityField
|
||||
, _fieldRender = listFieldConfig >>= WEL._fieldRender
|
||||
, _fieldRenderFnName = "render" ++ entityUpper ++ entityFieldUpper
|
||||
}
|
||||
where
|
||||
-- Configuration of a form field within entity-list, if there is any.
|
||||
listFieldConfig :: Maybe WEL.Field
|
||||
listFieldConfig = WEL.getConfigForField entityList entityField
|
||||
|
||||
entityUpper = U.toUpperFirst $ Wasp.entityName entity
|
||||
entityFieldUpper = U.toUpperFirst $ Wasp.entityFieldName entityField
|
||||
|
||||
generateEntityList :: Wasp -> WEL.EntityList -> FD.FileDraft
|
||||
generateEntityList wasp entityList =
|
||||
|
@ -12,8 +12,8 @@ import Lexer
|
||||
import Parser.App (app)
|
||||
import Parser.Page (page)
|
||||
import Parser.Entity (entity)
|
||||
import Parser.EntityForm (entityForm)
|
||||
import Parser.EntityList (entityList)
|
||||
import Parser.Entity.EntityForm (entityForm)
|
||||
import Parser.Entity.EntityList (entityList)
|
||||
import Parser.JsImport (jsImport)
|
||||
import Parser.Common (runWaspParser)
|
||||
|
||||
|
@ -12,6 +12,7 @@ import qualified Path.Aliases as Path
|
||||
|
||||
import qualified Lexer as L
|
||||
|
||||
|
||||
-- | Runs given wasp parser on a specified input.
|
||||
runWaspParser :: Parser a -> String -> Either ParseError a
|
||||
runWaspParser waspParser input = parse waspParser sourceName input
|
||||
|
39
src/Parser/Entity/Common.hs
Normal file
39
src/Parser/Entity/Common.hs
Normal file
@ -0,0 +1,39 @@
|
||||
module Parser.Entity.Common
|
||||
( waspPropertyEntityFields
|
||||
) where
|
||||
|
||||
import Text.Parsec.String (Parser)
|
||||
|
||||
import qualified Lexer as L
|
||||
import Parser.Common as P
|
||||
|
||||
-- A function that takes an entity field name (e.g. "description) and a list of parsed field
|
||||
-- options, and then creates a final Wasp AST record from it (fieldConfig).
|
||||
type CreateFieldConfig fieldOption fieldConfig = (String, [fieldOption]) -> fieldConfig
|
||||
|
||||
-- | Parses configuration of fields within a wasp entity component (e.g. entity-form
|
||||
-- or entity-list). Parses the following format:
|
||||
--
|
||||
-- fields: { FIELD_NAME: {...}, FIELD_NAME: {...}, ... }
|
||||
--
|
||||
-- At least one field must be specified.
|
||||
waspPropertyEntityFields
|
||||
:: Parser fo -- ^ Parser of a single field option.
|
||||
-> CreateFieldConfig fo fc -- ^ Function that creates a record with all parsed field options.
|
||||
-> Parser [fc] -- ^ Field configs, a list of record with all the field options.
|
||||
waspPropertyEntityFields fieldOptionP createFieldConfig = P.waspPropertyClosure "fields" $
|
||||
L.commaSep1 $ waspPropertyEntityField fieldOptionP createFieldConfig
|
||||
|
||||
|
||||
-- | Parses configuration of a specific field within a wasp entity component (e.g. entity-form
|
||||
-- or entity-list). Parses the following format:
|
||||
--
|
||||
-- FIELD_NAME: { option1, option2 }
|
||||
--
|
||||
-- At least one option must be present.
|
||||
waspPropertyEntityField
|
||||
:: Parser fo -- ^ Parser of a single field option.
|
||||
-> CreateFieldConfig fo fc -- ^ Function that creates a record with all parsed field options.
|
||||
-> Parser fc -- ^ Field config, a record with all the field options.
|
||||
waspPropertyEntityField fieldOptionP createFieldConfig =
|
||||
(P.waspIdentifierClosure $ L.commaSep1 fieldOptionP) >>= (return . createFieldConfig)
|
@ -1,4 +1,4 @@
|
||||
module Parser.EntityForm
|
||||
module Parser.Entity.EntityForm
|
||||
( entityForm
|
||||
|
||||
-- For testing
|
||||
@ -11,10 +11,11 @@ module Parser.EntityForm
|
||||
import Text.Parsec (choice)
|
||||
import Text.Parsec.String (Parser)
|
||||
|
||||
import qualified Wasp.EntityForm as EF
|
||||
import qualified Wasp.EntityForm as WEF
|
||||
import Wasp.EntityForm (EntityForm)
|
||||
|
||||
import qualified Parser.Common as P
|
||||
import qualified Parser.Entity.Common as PE
|
||||
import qualified Util as U
|
||||
import qualified Lexer as L
|
||||
|
||||
@ -27,16 +28,16 @@ entityForm = do
|
||||
(entityName, formName, options) <-
|
||||
P.waspElementLinkedToEntity L.reservedNameEntityForm entityFormOptions
|
||||
|
||||
return EF.EntityForm
|
||||
{ EF._name = formName
|
||||
, EF._entityName = entityName
|
||||
, EF._submit = maybeGetSubmitConfig options
|
||||
, EF._fields = getFieldsConfig options
|
||||
return WEF.EntityForm
|
||||
{ WEF._name = formName
|
||||
, WEF._entityName = entityName
|
||||
, WEF._submit = maybeGetSubmitConfig options
|
||||
, WEF._fields = getFieldsConfig options
|
||||
}
|
||||
|
||||
data EntityFormOption
|
||||
= EfoSubmit EF.Submit
|
||||
| EfoFields [EF.Field]
|
||||
= EfoSubmit WEF.Submit
|
||||
| EfoFields [WEF.Field]
|
||||
deriving (Show, Eq)
|
||||
|
||||
entityFormOptions :: Parser [EntityFormOption]
|
||||
@ -50,25 +51,25 @@ entityFormOption = choice
|
||||
|
||||
-- * Submit
|
||||
|
||||
maybeGetSubmitConfig :: [EntityFormOption] -> Maybe EF.Submit
|
||||
maybeGetSubmitConfig :: [EntityFormOption] -> Maybe WEF.Submit
|
||||
maybeGetSubmitConfig options = U.headSafe [s | EfoSubmit s <- options]
|
||||
|
||||
entityFormOptionSubmit :: Parser EntityFormOption
|
||||
entityFormOptionSubmit = EfoSubmit <$> (P.waspPropertyClosure "submit" submitConfig)
|
||||
|
||||
submitConfig :: Parser EF.Submit
|
||||
submitConfig :: Parser WEF.Submit
|
||||
submitConfig = do
|
||||
-- TODO(matija): this pattern of "having at least 1 property in closure" could be further
|
||||
-- extracted to e.g. "waspClosureOptions" - but again sometimes it is ok not to have any props,
|
||||
-- e.g. EntityForm. Maybe then "waspClosureOptions1" and "waspClosureOptions"?
|
||||
options <- L.commaSep1 submitOption
|
||||
|
||||
return EF.Submit
|
||||
{ EF._onEnter = maybeGetSoOnEnter options
|
||||
, EF._submitButton = maybeGetSoSubmitButton options
|
||||
return WEF.Submit
|
||||
{ WEF._onEnter = maybeGetSoOnEnter options
|
||||
, WEF._submitButton = maybeGetSoSubmitButton options
|
||||
}
|
||||
|
||||
data SubmitOption = SoOnEnter Bool | SoSubmitButton EF.SubmitButton deriving (Show, Eq)
|
||||
data SubmitOption = SoOnEnter Bool | SoSubmitButton WEF.SubmitButton deriving (Show, Eq)
|
||||
|
||||
submitOption :: Parser SubmitOption
|
||||
submitOption = choice [submitOptionOnEnter, submitOptionSubmitButton]
|
||||
@ -84,15 +85,15 @@ maybeGetSoOnEnter options = U.headSafe [b | SoOnEnter b <- options]
|
||||
submitOptionSubmitButton :: Parser SubmitOption
|
||||
submitOptionSubmitButton = SoSubmitButton <$> P.waspPropertyClosure "button" submitButtonConfig
|
||||
|
||||
maybeGetSoSubmitButton :: [SubmitOption] -> Maybe EF.SubmitButton
|
||||
maybeGetSoSubmitButton :: [SubmitOption] -> Maybe WEF.SubmitButton
|
||||
maybeGetSoSubmitButton options = U.headSafe [sb | SoSubmitButton sb <- options]
|
||||
|
||||
submitButtonConfig :: Parser EF.SubmitButton
|
||||
submitButtonConfig :: Parser WEF.SubmitButton
|
||||
submitButtonConfig = do
|
||||
options <- L.commaSep1 submitButtonOption
|
||||
|
||||
return EF.SubmitButton
|
||||
{ EF._submitButtonShow = maybeGetSboShow options
|
||||
return WEF.SubmitButton
|
||||
{ WEF._submitButtonShow = maybeGetSboShow options
|
||||
}
|
||||
|
||||
data SubmitButtonOption = SboShow Bool deriving (Show, Eq)
|
||||
@ -108,28 +109,24 @@ maybeGetSboShow options = U.headSafe [b | SboShow b <- options]
|
||||
|
||||
-- * Fields
|
||||
|
||||
getFieldsConfig :: [EntityFormOption] -> [EF.Field]
|
||||
getFieldsConfig :: [EntityFormOption] -> [WEF.Field]
|
||||
getFieldsConfig options = case [fs | EfoFields fs <- options] of
|
||||
[] -> []
|
||||
ls -> head ls
|
||||
|
||||
entityFormOptionFields :: Parser EntityFormOption
|
||||
entityFormOptionFields = EfoFields <$> (P.waspPropertyClosure "fields" $ L.commaSep1 field)
|
||||
entityFormOptionFields = EfoFields <$> PE.waspPropertyEntityFields fieldOption createFieldConfig
|
||||
|
||||
-- | Parses 'FIELD_NAME: { ... }.'
|
||||
field :: Parser EF.Field
|
||||
field = do
|
||||
(fieldName, options) <- P.waspIdentifierClosure $ L.commaSep1 fieldOption
|
||||
|
||||
return EF.Field
|
||||
{ EF._fieldName = fieldName
|
||||
, EF._fieldShow = maybeGetFieldOptionShow options
|
||||
, EF._fieldDefaultValue = maybeGetFieldOptionDefaultValue options
|
||||
createFieldConfig :: (String, [FieldOption]) -> WEF.Field
|
||||
createFieldConfig (fieldName, options) = WEF.Field
|
||||
{ WEF._fieldName = fieldName
|
||||
, WEF._fieldShow = maybeGetFieldOptionShow options
|
||||
, WEF._fieldDefaultValue = maybeGetFieldOptionDefaultValue options
|
||||
}
|
||||
|
||||
data FieldOption
|
||||
= FieldOptionShow Bool
|
||||
| FieldOptionDefaultValue EF.DefaultValue
|
||||
| FieldOptionDefaultValue WEF.DefaultValue
|
||||
deriving (Show, Eq)
|
||||
|
||||
-- | Parses a single field option, e.g. "show" or "defaultValue".
|
||||
@ -139,14 +136,14 @@ fieldOption = choice
|
||||
, FieldOptionDefaultValue <$> defaultValue
|
||||
]
|
||||
|
||||
defaultValue :: Parser EF.DefaultValue
|
||||
defaultValue :: Parser WEF.DefaultValue
|
||||
defaultValue = P.waspProperty "defaultValue" $ choice
|
||||
[ EF.DefaultValueString <$> L.stringLiteral
|
||||
, EF.DefaultValueBool <$> L.bool
|
||||
[ WEF.DefaultValueString <$> L.stringLiteral
|
||||
, WEF.DefaultValueBool <$> L.bool
|
||||
]
|
||||
|
||||
maybeGetFieldOptionShow :: [FieldOption] -> Maybe Bool
|
||||
maybeGetFieldOptionShow options = U.headSafe [b | FieldOptionShow b <- options]
|
||||
|
||||
maybeGetFieldOptionDefaultValue :: [FieldOption] -> Maybe EF.DefaultValue
|
||||
maybeGetFieldOptionDefaultValue :: [FieldOption] -> Maybe WEF.DefaultValue
|
||||
maybeGetFieldOptionDefaultValue options = U.headSafe [dv | FieldOptionDefaultValue dv <- options]
|
75
src/Parser/Entity/EntityList.hs
Normal file
75
src/Parser/Entity/EntityList.hs
Normal file
@ -0,0 +1,75 @@
|
||||
module Parser.Entity.EntityList
|
||||
( entityList
|
||||
) where
|
||||
|
||||
import Text.Parsec (choice)
|
||||
import Text.Parsec.String (Parser)
|
||||
|
||||
import qualified Wasp.EntityList as WEL
|
||||
import Wasp.EntityList (EntityList)
|
||||
|
||||
import qualified Wasp.JsCode as WJS
|
||||
|
||||
import qualified Parser.JsCode
|
||||
import qualified Parser.Common as P
|
||||
import qualified Parser.Entity.Common as PE
|
||||
import qualified Util as U
|
||||
import qualified Lexer as L
|
||||
|
||||
-- * EntityList
|
||||
|
||||
-- | Parses entity list, e.g. "entity-list<Task> TaskList {...}"
|
||||
entityList :: Parser EntityList
|
||||
entityList = do
|
||||
(entityName, listName, options) <-
|
||||
P.waspElementLinkedToEntity L.reservedNameEntityList entityListOptions
|
||||
|
||||
return WEL.EntityList
|
||||
{ WEL._name = listName
|
||||
, WEL._entityName = entityName
|
||||
, WEL._fields = getFieldsConfig options
|
||||
}
|
||||
|
||||
data EntityListOption
|
||||
= EloFields [WEL.Field]
|
||||
deriving (Show, Eq)
|
||||
|
||||
entityListOptions :: Parser [EntityListOption]
|
||||
-- TODO(matija): this could be further abstracted as waspClosureOptions option ->
|
||||
-- that way we abstract L.commaSep
|
||||
entityListOptions = L.commaSep entityListOption
|
||||
|
||||
entityListOption :: Parser EntityListOption
|
||||
entityListOption = choice
|
||||
[ entityListOptionFields
|
||||
]
|
||||
|
||||
-- * Fields
|
||||
|
||||
getFieldsConfig :: [EntityListOption] -> [WEL.Field]
|
||||
getFieldsConfig options = case [fs | EloFields fs <- options] of
|
||||
[] -> []
|
||||
ls -> head ls
|
||||
|
||||
entityListOptionFields :: Parser EntityListOption
|
||||
entityListOptionFields = EloFields <$> PE.waspPropertyEntityFields fieldOption createFieldConfig
|
||||
|
||||
createFieldConfig :: (String, [FieldOption]) -> WEL.Field
|
||||
createFieldConfig (fieldName, options) = WEL.Field
|
||||
{ WEL._fieldName = fieldName
|
||||
, WEL._fieldRender = maybeGetFieldOptionRender options
|
||||
}
|
||||
|
||||
data FieldOption
|
||||
= FieldOptionRender WJS.JsCode
|
||||
|
||||
fieldOption :: Parser FieldOption
|
||||
fieldOption = choice
|
||||
[ fieldOptionRender
|
||||
]
|
||||
|
||||
fieldOptionRender :: Parser FieldOption
|
||||
fieldOptionRender = FieldOptionRender <$> P.waspProperty "render" Parser.JsCode.jsCode
|
||||
|
||||
maybeGetFieldOptionRender :: [FieldOption] -> Maybe WJS.JsCode
|
||||
maybeGetFieldOptionRender options = U.headSafe [js | FieldOptionRender js <- options]
|
@ -1,26 +0,0 @@
|
||||
module Parser.EntityList
|
||||
( entityList
|
||||
) where
|
||||
|
||||
import Text.Parsec.String (Parser)
|
||||
import Text.Parsec.Char (spaces)
|
||||
|
||||
import qualified Wasp.EntityList as EL
|
||||
import Wasp.EntityList (EntityList)
|
||||
|
||||
import qualified Parser.Common as P
|
||||
import qualified Lexer as L
|
||||
|
||||
-- * EntityList
|
||||
|
||||
-- | Parses entity list, e.g. "entity-list<Task> TaskList {...}"
|
||||
entityList :: Parser EntityList
|
||||
entityList = do
|
||||
(entityName, listName, _) <-
|
||||
-- NOTE(matija): not supporting any options yet.
|
||||
P.waspElementLinkedToEntity L.reservedNameEntityList spaces
|
||||
|
||||
return EL.EntityList
|
||||
{ EL._name = listName
|
||||
, EL._entityName = entityName
|
||||
}
|
12
src/Parser/JsCode.hs
Normal file
12
src/Parser/JsCode.hs
Normal file
@ -0,0 +1,12 @@
|
||||
module Parser.JsCode
|
||||
( jsCode
|
||||
) where
|
||||
|
||||
import Text.Parsec.String (Parser)
|
||||
import qualified Data.Text as Text
|
||||
|
||||
import qualified Parser.Common as P
|
||||
import qualified Wasp.JsCode as WJS
|
||||
|
||||
jsCode :: Parser WJS.JsCode
|
||||
jsCode = (WJS.JsCode . Text.pack) <$> P.waspNamedClosure "js"
|
@ -21,6 +21,12 @@ data EntityForm = EntityForm
|
||||
, _fields :: [Field]
|
||||
} deriving (Show, Eq)
|
||||
|
||||
-- NOTE(matija): Ideally generator would not depend on this logic defined outside of it.
|
||||
-- We are moving away from this approach but some parts of code (Page generator) still
|
||||
-- rely on it so we cannot remove it completely yet without further refactoring.
|
||||
--
|
||||
-- Some record fields are note even included (e.g. _fields), we are keeping this only for the
|
||||
-- backwards compatibility.
|
||||
instance ToJSON EntityForm where
|
||||
toJSON entityForm = object
|
||||
[ "name" .= _name entityForm
|
||||
|
@ -1,16 +1,49 @@
|
||||
module Wasp.EntityList
|
||||
( EntityList(..)
|
||||
, Field(..)
|
||||
, getConfigForField
|
||||
) where
|
||||
|
||||
import Data.Aeson ((.=), object, ToJSON(..))
|
||||
|
||||
import Wasp.JsCode (JsCode)
|
||||
|
||||
import qualified Util as U
|
||||
import qualified Wasp.Entity as Entity
|
||||
|
||||
|
||||
data EntityList = EntityList
|
||||
{ _name :: !String -- Name of the list
|
||||
, _entityName :: !String -- Name of the entity the form is linked to
|
||||
, _fields :: [Field]
|
||||
} deriving (Show, Eq)
|
||||
|
||||
-- NOTE(matija): Ideally generator would not depend on this logic defined outside of it.
|
||||
-- We are moving away from this approach but some parts of code (Page generator) still
|
||||
-- rely on it so we cannot remove it completely yet without further refactoring.
|
||||
--
|
||||
-- Some record fields are note even included (e.g. _fields), we are keeping this only for the
|
||||
-- backwards compatibility.
|
||||
instance ToJSON EntityList where
|
||||
toJSON entityList = object
|
||||
[ "name" .= _name entityList
|
||||
, "entityName" .= _entityName entityList
|
||||
]
|
||||
|
||||
-- | For a given entity field, returns its configuration from the given entity-list, if present.
|
||||
-- TODO(matija): this is very similar to the same function in EntityForm, we could extract it
|
||||
-- (prob. using typeclass or TH) in the future.
|
||||
getConfigForField :: EntityList -> Entity.EntityField -> Maybe Field
|
||||
getConfigForField entityList entityField =
|
||||
U.headSafe $ filter isConfigOfInputEntityField $ _fields entityList
|
||||
where
|
||||
isConfigOfInputEntityField :: Field -> Bool
|
||||
isConfigOfInputEntityField =
|
||||
(== Entity.entityFieldName entityField) . _fieldName
|
||||
|
||||
-- * Field
|
||||
|
||||
data Field = Field
|
||||
{ _fieldName :: !String
|
||||
, _fieldRender :: Maybe JsCode -- Js function that renders a list field.
|
||||
} deriving (Show, Eq)
|
||||
|
14
src/Wasp/JsCode.hs
Normal file
14
src/Wasp/JsCode.hs
Normal file
@ -0,0 +1,14 @@
|
||||
module Wasp.JsCode
|
||||
( JsCode(..)
|
||||
) where
|
||||
|
||||
import Data.Aeson (ToJSON(..))
|
||||
import Data.Text (Text)
|
||||
|
||||
data JsCode = JsCode !Text deriving (Show, Eq)
|
||||
|
||||
-- TODO(matija): Currently generator is relying on this implementation, which is not
|
||||
-- ideal. Ideally all the generation logic would be in the generator. But for now this was
|
||||
-- the simplest way to implement it.
|
||||
instance ToJSON JsCode where
|
||||
toJSON (JsCode code) = toJSON code
|
@ -3,7 +3,7 @@ module Parser.EntityFormTest where
|
||||
import Test.Tasty.Hspec
|
||||
|
||||
import Parser.Common (runWaspParser)
|
||||
import Parser.EntityForm
|
||||
import Parser.Entity.EntityForm
|
||||
( entityForm
|
||||
, submitConfig
|
||||
|
||||
|
@ -9,6 +9,7 @@ import Wasp
|
||||
import qualified Wasp.EntityForm as EF
|
||||
import qualified Wasp.EntityList as EL
|
||||
import qualified Wasp.Style
|
||||
import qualified Wasp.JsCode
|
||||
|
||||
|
||||
spec_parseWasp :: Spec
|
||||
@ -88,6 +89,12 @@ spec_parseWasp =
|
||||
, WaspElementEntityList $ EL.EntityList
|
||||
{ EL._name = "TaskList"
|
||||
, EL._entityName = "Task"
|
||||
, EL._fields =
|
||||
[ EL.Field
|
||||
{ EL._fieldName = "description"
|
||||
, EL._fieldRender = Just $ Wasp.JsCode.JsCode "task => task.description"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
`setJsImports` [ JsImport "something" [relfile|some/file|] ]
|
||||
|
@ -69,5 +69,11 @@ entity-form<Task> CreateTaskForm {
|
||||
}
|
||||
|
||||
entity-list<Task> TaskList {
|
||||
// Options TBD.
|
||||
fields: {
|
||||
description: {
|
||||
render: {=js
|
||||
task => task.description
|
||||
js=}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user