Skip to content

Logic/expressions in layout #355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
15 tasks done
olemartinorg opened this issue Jul 29, 2022 · 3 comments · Fixed by #540
Closed
15 tasks done

Logic/expressions in layout #355

olemartinorg opened this issue Jul 29, 2022 · 3 comments · Fixed by #540
Assignees
Labels
area/logic related to logic/dynamics/expressions org/krt org/ssb Issues relevant for Statistisk sentralbyrå.

Comments

@olemartinorg
Copy link
Contributor

olemartinorg commented Jul 29, 2022

Description

Several issues require some form of logic/dynamics in layout files. Along with the solution proposed in #220, we can start implementing this form for layout logic (in issues like #61 and #64), without introducing breaking changes (as in #220).

This issue tracks the implementation of layout expressions in frontend. The project itself is tracked in more detail here.

In scope

New layout logic, as described much more clearly in #220

Out of scope

Breaking changes 😉

Tasks

Development is underway in the feat/layout-expressions branch.

  • Implement tools to work on a layout as a hierarchical structure (respecting repeating group rows, etc), so the expression can be evaluated in the context of a layout node (finding the closest component references when looking up another component id - which could be inside the same repeating group row, the one above, etc).
  • Implement support for evaluating recursive layout expressions
  • Implement a useLayoutExpression() hook that can resolve layout expressions anywhere
  • Test the above hook in a unit-test
  • Use resolved layout expressions (for the required property) when validating a group using triggers: ['validation']
  • Validate all expressions to make sure they are valid when loading the layout (generate error messages if not)
  • Implement support for pre-processing compact lisp-like expressions into full/verbose expressions (do this once in the fetchLayout saga, along with the initial layout expression validation)
  • Evaluate expressions in sagas to make sure we still use and populate the hiddenFields state even when using layout expressions.
    • This could probably benefit from some index, optimizing the code so that we don't have to iterate the entire layout for every form item change - only for those that affects layout expressions.
  • ~~[ ] Optimize the code so layout expressions (and especially the hierarchical layout functions) don't run when we don't absolutely need them to. Memoization should go a long way. ~~ I think I'm deciding against this for now, as it seems to be fast enough (optimizations now might be premature)
  • Make sure expression results are used in places where the properties are read. This means expressions needs to be resolved when performing empty field validation (for expressions in the the required property), etc.
  • Investigate changes/increases in time and memory spent type-checking after these changes. There are quite a few new (and slow/complex) types added in the branch, and during development node has sometimes crashed with out-of-memory errors. Make sure type-checking for happy-path changes does not change significantly for other developers.
  • Support hiding entire pages/layouts
  • Clean up code to avoid complexity warnings from eslint
  • Search for added TODOs in the code and fix them
  • Return default value when top-level expression returns null
  • Expressions: Implement Cypress test(s) #620
@olemartinorg olemartinorg added status/draft Status: When you create an issue before you have enough info to properly describe the issue. Epic labels Jul 29, 2022
@olemartinorg olemartinorg self-assigned this Jul 29, 2022
@olemartinorg
Copy link
Contributor Author

olemartinorg commented Aug 2, 2022

Note: This comment is outdated. Futher talk about the expression format can be found in #8774

In #220 the following syntax has been proposed for toggling hidden fields dynamically via layout expressions:

"hidden": {
  "function": "equals",
  "args": [
    {
      "dataModel": "MyModel.Group.Field"
    },
    {
      "component": "my-input-field"
    }
  ]
}

Along with a simpler DSL variant:

"hidden": {
  "expr": "dataModel(MyModel.Group.Field) == component(my-input-field)"
}

In #61 we'll need an implementation where the text resource for the group edit button changes based on some expression, which requires some extensions to this syntax (as the output is not a boolean true/false, but string constants). This might be an alternative for non-boolean values:

"textResourceBindings": {
  "edit_label": {
    "function": "equals",
    "args": [
      {
        "dataModel": "MyModel.Group.Field.IsEditable"
      },
      "isEditable"
    ],
    "mapping": {
      "true": "edit",
      "false": "Inspect non-editable values"
    }
  }
}

Along with a simpler DSL variant:

"textResourceBindings": {
  "edit_label": {
    "expr": "dataModel(MyModel.Group.Field.IsEditable) == true",
    "mapping": {
      "true": "edit",
      "false": "Inspect non-editable values"
    }
  }
}

This also leads to the obvious, where the text resource key is fetched directly from the data model without mapping the expression result via a boolean:

"textResourceBindings": {
  "edit_label": {
    "expr": "dataModel(MyModel.Group.Field.EditLabel)"
  }
}

Which, when decoded to an expanded expression could perhaps equal:

"textResourceBindings": {
  "edit_label": {
    "function": "lookup",
    "args": [
      {
        "dataModel": "MyModel.Group.Field.EditLabel"
      }
    ]
  }
}

This comment is me thinking out loud. I think I'll go forwards with this solution (adding a lookup function that takes one argument, adding support for it in the DSL). Along with support for optional mapping of outputs (null, bools and numbers would have to be converted to strings to work in such a mapping, so there would essentially be no difference between true and "true").

This means you could also map the lookup if your data model values are not lookup keys already:

"textResourceBindings": {
  "edit_label": {
    "expr": "dataModel(MyModel.Group.Field.EditLabel)",
    "mapping": {
      "null": "edit",
      "customLabel": "Inspect non-editable values"
    }
  }
}

@olemartinorg olemartinorg moved this to In Progress in Layout expressions Aug 10, 2022
@olemartinorg olemartinorg removed the Epic label Aug 19, 2022
@olemartinorg olemartinorg removed the status/draft Status: When you create an issue before you have enough info to properly describe the issue. label Aug 30, 2022
@olemartinorg olemartinorg moved this to 👷 In Progress in Team Apps Oct 12, 2022
@olemartinorg olemartinorg moved this from 👷 In Progress to 🔎 Review in Team Apps Oct 13, 2022
@olemartinorg olemartinorg linked a pull request Oct 13, 2022 that will close this issue
4 tasks
@olemartinorg olemartinorg mentioned this issue Oct 19, 2022
4 tasks
@olemartinorg olemartinorg moved this from 🔎 Review to 👷 In Progress in Team Apps Oct 25, 2022
Repository owner moved this from In Progress to Done in Layout expressions Oct 26, 2022
Repository owner moved this from 👷 In Progress to ✅ Done in Team Apps Oct 26, 2022
@olemartinorg olemartinorg moved this from ✅ Done to 🧪 Test in Team Apps Oct 26, 2022
@olemartinorg
Copy link
Contributor Author

Automatically closed when merged, but testing (and cypress tests) remain here.

@olemartinorg
Copy link
Contributor Author

Closing as done. This has already seen quite some testing, even though Cypress tests are missing as of now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/logic related to logic/dynamics/expressions org/krt org/ssb Issues relevant for Statistisk sentralbyrå.
Projects
Archived in project
Status: Done
Development

Successfully merging a pull request may close this issue.

1 participant