Open traut opened 1 month ago
I think dedicated dynamic
be a bit easier to implement and understand than embedding these parameters and functionality in selected few section
& document
blocks.
Not using dedicated block for this would move all content blocks to the lower level on content tree. There is no way to use this dynamic feature to create blocks on the top level of the document or on the same level where it is used.
@dobarx I almost wrote the whole issue about dynamic
blocks! I decided against it because I kept inventing the behavior that reminded me very much of the combo of section
/ document
blocks!
The problem with a dedicated dynamic
block is that we must define its behavior in all situations: Where can it be placed? How does it behave when defined inside and outside the document? If it is outside, where does the data come from? Should we allow data
blocks inside dynamic
block? Should we reference blocks outside dynamic
block on the root level? If we allow data
blocks inside dynamic
blocks, it opens the door to non-document-level data blocks, which will create another set of problems. Can dynamic blocks be referenced? etc
If we take a step back, dynamic
block is just a container around some content with a couple of instructions. And we already have 2 containers with defined behaviour -- document
and section
blocks! Extending these containers allows us to build up on all behaviours the blocks support, which is so much easier.
Not using dedicated block for this would move all content blocks to the lower level on content tree. There is no way to use this dynamic feature to create blocks on the top level of the document or on the same level where it is used.
It might need a dedicated unpacking step, indeed, where all these "dynamic" blocks are unpacked into "normal" blocks. We don't need to retain the knowledge that some nodes were originally dynamic—we can adjust the template tree and continue.
Should we allow data blocks inside dynamic block? Should we reference blocks outside dynamic block on the root level? If we allow data blocks inside dynamic blocks, it opens the door to non-document-level data blocks, which will create another set of problems.
But doesn't allowing document
being dynamic open the door for data
blocks being also dynamic already? That inline
data in given example is already dynamic. My understanding of dynamic
is that we should take for_each
property of it and take all children blocks of it and recreate them dynamically without executing them. Allowing any block to be dynamic.
But doesn't allowing document being dynamic open the door for data blocks being also dynamic already?
they are dynamic in a sense that they will be copied as part of the document
, but they still follow the rules and limitations we established for them
in the description above, for_each
controls the behavior of the block it is defined in (not the children), so if it is inside document
, multiple document
blocks will be created (the same for section
). This allows us to use the existing definitions without defining new ones: for example, if for_each
would affect only children, we would need to invent a block that can include document
to have dynamic documents.
Potentially, we can allow for_each
for every block type -- since it affects the block it is defined in, it can be applied to any block. It might be interesting to do in the future but for the first iteration, enabling for_each
only for document
and section
is easier to explain and to use.
I've updated the issue description with the new design
Background
The content structure in FCL templates is static at the moment. Fabric supports content filtering during rendering (#99), but users can't mutate the document structure based on data.
Requirements
data
blockcontent
andsection
blocks from data defined withdata
block in the templateDesign
We introduce
dynamic
block type. It is somewhat similar to Terraform's dynamic blocks but has a different syntax.dynamic
block works with specific block types, similar toconfig
block:dynamic
block supportsdocument
,section
andcontent
blocks.For example,
dynamic
document would look like this:dynamic
block attributes:for_each_query
-- (optional) a string value, a JQ query. The result of the query provides a collection to iterate over.for_each_item_name
-- (optional) a string attribute, a name for the current element of a collection in the context. By default, it isitem
condition_query
-- (optional) a string attribute, a JQ query. The result of the query is converted to bool.Dynamic blocks produce the block they wrap:
for_each_query
condition_query
returns a response that we treat astrue
: booleantrue
or non-null objectFor example, this snippet shows how we can choose which block to render based on available data:
Behaviour
Execution flow
data
blocks are executed and set in the contextquery
is defined,query
is executed and.query_result
value set in the contextcondition_query
is defined, it is executed.false
ornull
, the dynamic block is skipped completelytrue
or a non-null object, the execution continuesfor_each_query
is defined, it is executed and the blocks that match the number of items returned byfor_each_query
are createdContext for produced blocks
Dynamic block extends the context available for produced blocks with these values:
.dynamic.item
or.dynamic.<item-name>
-- the current element of the collection.dynamic.item_index
-- the index of the current element of the collectionIf the dynamic block has another dynamic block nested inside (if
section
is wrapped in dynamic block),.dynamic.*
values in the context are overwritten by the values for the inner block.Naming
If the dynamic block is named, the names of produced blocks are suffixed with
.dynamic.item_index
value, for examplesection.foo[<.dynamic.item_index>]
.If the block is unnamed, it's given a random name and the names of the copies are suffixed too: for example,
section.24a086f[<.dynamic.item_index>]
.Example
Dynamic section and dynamic content block:
renders into
The
ref
blocks should still be supported:and https://github.com/blackstork-io/fabric/issues/29 is supported as well.
Dynamic documents
The behaviour of the dynamic
document
blocks is slightly more complex.renders into 2 separate documents:
and
Data blocks
for_each_query
relies on data blocks to be already executed and available in.context
.Since
data
blocks do not use the context, it should be possible to execute them only once and pass the results in the produceddocument
block contexts.CLI issues
render
CLI command should supportdynamic.document.<document-name>
as a targetdata
CLI command should supportdynamic.document.<document-name>.data.<...>
as a targetThe behaviour of publish / output flags in CLI should be adjusted in
dynamic
blocks as target introduce ambiguity.References