From 92145ea2c53a7094095276ac59fcc377a8f936da Mon Sep 17 00:00:00 2001 From: Ivar Nesje Date: Fri, 13 Dec 2024 12:12:12 +0100 Subject: [PATCH] Fix issue with Removal of hidden data the way it is used for expression validation * Add [DebuggerDisplay] for easier debugging * Change ComponentContext.ChildContexts from IEnumerable to List<> --- .../Internal/Expressions/LayoutEvaluator.cs | 4 + .../Models/Expressions/ComponentContext.cs | 33 +- .../CommonTests/ExpressionTestCaseRoot.cs | 2 +- .../FullTests/ExpressionValidation/CV.json | 412 ++++++++++++++++++ ...ests.TestExpressionValidation.verified.txt | 93 ++++ .../ExpressionValidationTests.cs | 122 ++++++ .../ExpressionValidation/Skjul felter.json | 112 +++++ 7 files changed, 774 insertions(+), 4 deletions(-) create mode 100644 test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/CV.json create mode 100644 test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/ExpressionValidationTests.TestExpressionValidation.verified.txt create mode 100644 test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/ExpressionValidationTests.cs create mode 100644 test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/Skjul felter.json diff --git a/src/Altinn.App.Core/Internal/Expressions/LayoutEvaluator.cs b/src/Altinn.App.Core/Internal/Expressions/LayoutEvaluator.cs index 96cc44569..11498aa67 100644 --- a/src/Altinn.App.Core/Internal/Expressions/LayoutEvaluator.cs +++ b/src/Altinn.App.Core/Internal/Expressions/LayoutEvaluator.cs @@ -51,6 +51,10 @@ ComponentContext context // Ignore children of hidden rows if includeHiddenRowChildren is false if (!includeHiddenRowChildren && childContext.Component is RepeatingGroupComponent) { + if (childContext.ChildContexts.Count > 0) + { + continue; + } var hiddenRows = await childContext.GetHiddenRows(state); var currentRow = childContext.RowIndices?[^1]; var rowIsHidden = currentRow is not null && hiddenRows[currentRow.Value]; diff --git a/src/Altinn.App.Core/Models/Expressions/ComponentContext.cs b/src/Altinn.App.Core/Models/Expressions/ComponentContext.cs index 37b39703b..f6c00ed6b 100644 --- a/src/Altinn.App.Core/Models/Expressions/ComponentContext.cs +++ b/src/Altinn.App.Core/Models/Expressions/ComponentContext.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Diagnostics; using Altinn.App.Core.Internal.Expressions; using Altinn.App.Core.Models.Layout; using Altinn.App.Core.Models.Layout.Components; @@ -8,6 +9,8 @@ namespace Altinn.App.Core.Models.Expressions; /// /// Simple class for holding the context for /// +[DebuggerDisplay("{_debuggerDisplay}", Name = "{_debuggerName}")] +[DebuggerTypeProxy(typeof(DebuggerProxy))] public sealed class ComponentContext { private readonly int? _rowLength; @@ -20,7 +23,7 @@ public ComponentContext( int[]? rowIndices, int? rowLength, DataElementIdentifier dataElementIdentifier, - IEnumerable? childContexts = null + List? childContexts = null ) { DataElementIdentifier = dataElementIdentifier; @@ -96,7 +99,7 @@ public async Task GetHiddenRows(LayoutEvaluatorState state) rowIndices, rowLength: hiddenRows.Length, dataElementIdentifier: DataElementIdentifier, - childContexts: childContexts + childContexts: childContexts.ToList() ); var rowHidden = await ExpressionEvaluator.EvaluateBooleanExpression(state, rowContext, "hiddenRow", false); @@ -111,7 +114,7 @@ public async Task GetHiddenRows(LayoutEvaluatorState state) /// /// Contexts that logically belongs under this context (eg cell => row => group=> page) /// - public IEnumerable ChildContexts { get; } + public List ChildContexts { get; } /// /// Parent context or null, if this is a root context, or a context created without setting parent @@ -140,4 +143,28 @@ public IEnumerable Descendants } } } + + private string _debuggerName => + $"{Component?.Type}" + (RowIndices is not null ? $"[{string.Join(',', RowIndices)}]" : ""); + private string _debuggerDisplay => + $"id:\"{Component?.Id}\"" + (ChildContexts.Count > 0 ? $"children:{ChildContexts.Count}" : ""); + + private class DebuggerProxy + { + private readonly ComponentContext _context; + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public List ChildContexts => _context.ChildContexts; + public BaseComponent? Component => _context.Component; + public ComponentContext? Parent => _context.Parent; + public bool? IsHidden => _context._isHidden; + public string? HiddenRows => + _context._hiddenRows is not null ? string.Join(',', _context._hiddenRows.GetEnumerator()) : null; + public Guid DataElementId => _context.DataElementIdentifier.Guid; + + public DebuggerProxy(ComponentContext context) + { + _context = context; + } + } } diff --git a/test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/ExpressionTestCaseRoot.cs b/test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/ExpressionTestCaseRoot.cs index f04359b75..6049fc924 100644 --- a/test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/ExpressionTestCaseRoot.cs +++ b/test/Altinn.App.Core.Tests/LayoutExpressions/CommonTests/ExpressionTestCaseRoot.cs @@ -108,7 +108,7 @@ public ComponentContext ToContext(LayoutModel? model, LayoutEvaluatorState state rowLength: component is RepeatingGroupComponent ? 0 : null, // TODO: get from data model, but currently not important for tests state.GetDefaultDataElementId(), - ChildContexts.Select(c => c.ToContext(model, state)) + ChildContexts.Select(c => c.ToContext(model, state)).ToList() ); } diff --git a/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/CV.json b/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/CV.json new file mode 100644 index 000000000..4cfe9de8b --- /dev/null +++ b/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/CV.json @@ -0,0 +1,412 @@ +{ + "$schema": "https://altinncdn.no/schemas/json/layout/layout.schema.v1.json", + "data": { + "layout": [ + { + "id": "nav-bar", + "type": "NavigationBar" + }, + { + "id": "tittel2", + "type": "Header", + "size": "L", + "textResourceBindings": { + "title": "CV.tittel.title" + } + }, + { + "id": "fornavn", + "type": "Input", + "hidden": [ + "commaContains", + ["dataModel", "root.SF_skjul-felter"], + "fornavn" + ], + "dataModelBindings": { + "simpleBinding": "root.fornavn" + }, + "showValidations": ["AllExceptRequired"], + "required": true, + "autocomplete": "given-name", + "textResourceBindings": { + "title": "CV.fornavn.title" + }, + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "etternavn", + "type": "Input", + "hidden": [ + "commaContains", + ["dataModel", "root.SF_skjul-felter"], + "etternavn" + ], + "dataModelBindings": { + "simpleBinding": "root.etternavn" + }, + "showValidations": ["AllExceptRequired"], + "required": true, + "textResourceBindings": { + "title": "CV.etternav.title" + }, + "autocomplete": "family-name", + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "alder", + "type": "Input", + "hidden": [ + "commaContains", + ["dataModel", "root.SF_skjul-felter"], + "alder" + ], + "dataModelBindings": { + "simpleBinding": "root.alder" + }, + "showValidations": ["AllExceptRequired"], + "required": true, + "textResourceBindings": { + "title": "CV.alder.title" + }, + "autocomplete": "off", + "formatting": { + "number": { + "allowNegative": false, + "decimalScale": 0 + } + }, + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "kjonn", + "type": "Dropdown", + "hidden": [ + "commaContains", + ["dataModel", "root.SF_skjul-felter"], + "kjonn" + ], + "dataModelBindings": { + "simpleBinding": "root.kjonn" + }, + "showValidations": ["AllExceptRequired"], + "required": true, + "optionsId": "kjønn", + "textResourceBindings": { + "title": "CV.kj.title" + }, + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "e-post", + "type": "Input", + "hidden": [ + "commaContains", + ["dataModel", "root.SF_skjul-felter"], + "epost" + ], + "dataModelBindings": { + "simpleBinding": "root.epost" + }, + "showValidations": ["AllExceptRequired"], + "required": true, + "textResourceBindings": { + "title": "CV.e-post.title" + }, + "autocomplete": "email", + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "telefon", + "type": "Input", + "hidden": [ + "commaContains", + ["dataModel", "root.SF_skjul-felter"], + "telefon" + ], + "dataModelBindings": { + "simpleBinding": "root.telefonnummer" + }, + "showValidations": ["AllExceptRequired"], + "required": true, + "textResourceBindings": { + "title": "CV.telefon.title" + }, + "autocomplete": "tel", + "formatting": { + "number": { + "format": "+47 ### ## ###" + } + }, + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "bosted", + "type": "Dropdown", + "hidden": [ + "commaContains", + ["dataModel", "root.SF_skjul-felter"], + "bosted" + ], + "dataModelBindings": { + "simpleBinding": "root.bosted" + }, + "showValidations": ["AllExceptRequired"], + "optionsId": "kommuner", + "required": true, + "textResourceBindings": { + "title": "CV.bosted.title" + }, + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "vedlegg-cv", + "type": "FileUploadWithTag", + "displayMode": "list", + "hasCustomFileEndings": true, + "maxFileSizeInMB": 25, + "maxNumberOfAttachments": 10, + "minNumberOfAttachments": 0, + "optionsId": "applicationdocs", + "dataModelBindings": { + "list": "root.vedlegg" + }, + "textResourceBindings": { + "title": "CV.vedlegg-cv.title", + "description": "CV.vedlegg-cv.description", + "tagTitle": "CV.vedlegg-cv.tagTitle" + }, + "validFileEndings": ".pdf, .png, .jpg", + "required": false + }, + { + "id": "arbeidserfaring", + "type": "RepeatingGroup", + "children": [ + "arbeidsgiver", + "dato-fra", + "dato-til", + "erfaring-stilling", + "erfaring-beskrivelse", + "Vedlegg", + "prosjekter" + ], + "tableHeaders": [ + "arbeidsgiver", + "erfaring-stilling", + "dato-fra", + "dato-til" + ], + "validateOnSaveRow": ["All"], + "hiddenRow": [ + "and", + [ + "equals", + ["dataModel", "root.arbeidserfaring.stilling"], + ["dataModel", "root.SF_skjul-arbeidsgiver"] + ], + [ + "greaterThan", + ["stringLength", ["dataModel", "root.SF_skjul-arbeidsgiver"]], + 0 + ] + ], + "dataModelBindings": { + "group": "root.arbeidserfaring" + }, + "textResourceBindings": { + "add_button": "arbeidserfaring.add_button" + } + }, + { + "id": "arbeidsgiver", + "type": "Input", + "dataModelBindings": { + "simpleBinding": "root.arbeidserfaring.arbeidsgiver" + }, + "showValidations": ["AllExceptRequired"], + "required": true, + "textResourceBindings": { + "title": "CV.arbeidsgiver.title" + } + }, + { + "id": "dato-fra", + "type": "Datepicker", + "dataModelBindings": { + "simpleBinding": "root.arbeidserfaring.fra" + }, + "showValidations": ["AllExceptRequired"], + "minDate": "1900-01-01T12:00:00.000Z", + "maxDate": "2100-01-01T12:00:00.000Z", + "timeStamp": false, + "required": true, + "textResourceBindings": { + "title": "CV.dato-fra.title" + }, + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "dato-til", + "type": "Datepicker", + "dataModelBindings": { + "simpleBinding": "root.arbeidserfaring.til" + }, + "showValidations": ["AllExceptRequired"], + "minDate": "1900-01-01T12:00:00.000Z", + "maxDate": "2100-01-01T12:00:00.000Z", + "timeStamp": false, + "required": true, + "textResourceBindings": { + "title": "CV.dato-til.title" + }, + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "erfaring-stilling", + "type": "Input", + "dataModelBindings": { + "simpleBinding": "root.arbeidserfaring.stilling" + }, + "showValidations": ["AllExceptRequired"], + "required": true, + "textResourceBindings": { + "title": "CV.stilling.title" + } + }, + { + "id": "erfaring-beskrivelse", + "type": "TextArea", + "dataModelBindings": { + "simpleBinding": "root.arbeidserfaring.beskrivelse" + }, + "showValidations": ["AllExceptRequired"], + "required": false, + "textResourceBindings": { + "title": "CV.erfaring-beskrivelse.title" + } + }, + { + "id": "Vedlegg", + "type": "FileUploadWithTag", + "displayMode": "list", + "hasCustomFileEndings": true, + "maxFileSizeInMB": 25, + "maxNumberOfAttachments": 10, + "minNumberOfAttachments": 0, + "optionsId": "cert", + "dataModelBindings": { + "list": "root.arbeidserfaring.vedlegg" + }, + "textResourceBindings": { + "title": "CV.Vedlegg.title", + "description": "CV.Vedlegg.description", + "tagTitle": "CV.Vedlegg.tagTitle" + }, + "validFileEndings": ".pdf, .png, .jpg", + "required": false + }, + { + "id": "prosjekter", + "type": "RepeatingGroup", + "children": ["prosjekt-tittel", "prosjekt-beskrivelse"], + "tableHeaders": ["prosjekt-tittel"], + "validateOnSaveRow": ["All"], + "hiddenRow": [ + "and", + [ + "equals", + ["dataModel", "root.arbeidserfaring.prosjekter.tittel"], + ["dataModel", "root.SF_skjul-prosjekt"] + ], + [ + "greaterThan", + ["stringLength", ["dataModel", "root.SF_skjul-prosjekt"]], + 0 + ] + ], + "dataModelBindings": { + "group": "root.arbeidserfaring.prosjekter" + }, + "textResourceBindings": { + "add_button": "tsnLc5YNPHLJ" + } + }, + { + "id": "prosjekt-tittel", + "type": "Input", + "dataModelBindings": { + "simpleBinding": "root.arbeidserfaring.prosjekter.tittel" + }, + "showValidations": ["AllExceptRequired"], + "required": true, + "textResourceBindings": { + "title": "CV.prosjekt-tittel.title" + } + }, + { + "id": "prosjekt-beskrivelse", + "type": "TextArea", + "dataModelBindings": { + "simpleBinding": "root.arbeidserfaring.prosjekter.beskrivelse" + }, + "showValidations": ["AllExceptRequired"], + "required": false, + "textResourceBindings": { + "title": "CV.prosjekt-beskrivelse.title" + } + }, + { + "id": "button-group", + "type": "ButtonGroup", + "children": ["nav", "send-inn"] + }, + { + "id": "nav", + "type": "NavigationButtons", + "showBackButton": true, + "validateOnNext": { + "page": "current", + "show": ["All"] + }, + "textResourceBindings": { + "next": "CV.nav.next", + "back": "CV.nav.back" + } + }, + { + "id": "send-inn", + "type": "Button", + "textResourceBindings": { + "title": "CV.Button-U7p0KF.title" + } + } + ] + } +} diff --git a/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/ExpressionValidationTests.TestExpressionValidation.verified.txt b/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/ExpressionValidationTests.TestExpressionValidation.verified.txt new file mode 100644 index 000000000..b4a0e8b96 --- /dev/null +++ b/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/ExpressionValidationTests.TestExpressionValidation.verified.txt @@ -0,0 +1,93 @@ +[ + { + Field: root.fornavn, + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.etternavn, + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.alder, + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.kjonn, + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.epost, + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.telefonnummer, + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.bosted, + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.arbeidserfaring[0].prosjekter[3], + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.arbeidserfaring[0].prosjekter[1], + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.arbeidserfaring[1].prosjekter[3], + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.arbeidserfaring[1].prosjekter[0], + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.arbeidserfaring[2], + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + }, + { + Field: root.arbeidserfaring[1], + DataElementIdentifier: { + Guid: Guid_1, + Id: Guid_1 + } + } +] diff --git a/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/ExpressionValidationTests.cs b/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/ExpressionValidationTests.cs new file mode 100644 index 000000000..100384f2e --- /dev/null +++ b/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/ExpressionValidationTests.cs @@ -0,0 +1,122 @@ +using System.Text.Json; +using Altinn.App.Core.Features; +using Altinn.App.Core.Internal.Expressions; +using Altinn.App.Core.Tests.LayoutExpressions.TestUtilities; +using Altinn.Platform.Storage.Interface.Models; + +namespace Altinn.App.Core.Tests.LayoutExpressions.FullTests.ExpressionValidation; + +public class ExpressionValidationTests +{ + [Fact] + public async Task TestExpressionValidation() + { + var jsonData = """ + { + "root": { + "fornavn": null, + "etternavn": null, + "alder": null, + "arbeidserfaring": [ + { + "altinnRowId": "7bca5a19-8654-4e9d-a7d5-1b12f670b1aa", + "arbeidsgiver": "Digitaliseringsdirektoratet", + "fra": "2020-01-01", + "til": "2020-12-31", + "stilling": "GyldigUtvikler", + "beskrivelse": "Jobbet med Altinn Studio", + "prosjekter": [ + { + "altinnRowId": "00351338-13af-4084-9532-e41cb96262ec", + "tittel": "GyldigProsjekt", + "beskrivelse": "Laget Altinn Studio" + }, + { + "altinnRowId": "a38766c8-635e-41e8-9b2b-274af49092dc", + "tittel": "UgyldigProsjekt", + "beskrivelse": "kult" + }, + { + "altinnRowId": "c21976e3-ac06-41a7-bb00-c61822d0b1f8", + "tittel": "GyldigProsjekt", + "beskrivelse": "Laget Altinn Studio" + }, + { + "altinnRowId": "21fe3c90-aa74-4bda-a6fb-3927a98cfb4d", + "tittel": "UgyldigProsjekt", + "beskrivelse": "kult" + } + ], + "vedlegg": [ + "ce83fcaf-bdc5-4be2-aa28-0551cea31119" + ] + }, + { + "altinnRowId": "554b961b-f8f7-40a2-b700-27d1832b8c39", + "arbeidsgiver": "Digitaliseringsdirektoratet", + "fra": "2020-01-01", + "til": "2020-12-31", + "stilling": "UgyldigUtvikler", + "beskrivelse": "flink", + "prosjekter": [ + { + "altinnRowId": "8c0f9db5-642c-4456-804c-e327666fa30b", + "tittel": "UgyldigProsjekt", + "beskrivelse": "kult" + }, + { + "altinnRowId": "8c539f35-a095-408c-8dda-ca50e1be5c7b", + "tittel": "GyldigProsjekt", + "beskrivelse": "Laget Altinn Studio" + }, + { + "altinnRowId": "d5193bf9-b594-42ae-a577-b02d23a3ee75", + "tittel": "ErrorProsjekt", + "beskrivelse": "kult" + }, + { + "altinnRowId": "fdfbe892-2d2c-45f1-b260-28415b3e0407", + "tittel": "UgyldigProsjekt", + "beskrivelse": "kult" + } + ], + "vedlegg": [ + "7d16376c-68c5-4de8-b44e-b2da64d1617e" + ] + }, + { + "altinnRowId": "4bef4f3a-506d-4f70-a652-a75500bd5621", + "arbeidsgiver": "Digitaliseringsdirektoratet", + "fra": "2020-01-01", + "til": "2020-12-31", + "stilling": "UgyldigUtvikler", + "beskrivelse": "flink", + "prosjekter": [], + "vedlegg": [ + "a97d8c01-781e-4fb5-a66d-03174d529209" + ] + } + ], + "epost": null, + "telefonnummer": null, + "bosted": null, + "kjonn": null, + "SF_skjul-felter": "fornavn,etternavn,alder,kjonn,epost,telefon,bosted", + "SF_skjul-arbeidsgiver": "UgyldigUtvikler", + "SF_skjul-prosjekt": "UgyldigProsjekt", + "vedlegg": [] + } + } + """; + using var jsonDoc = JsonDocument.Parse(jsonData); + IInstanceDataAccessor dataAccessor = DynamicClassBuilder.DataAccessorFromJsonDocument( + new Instance(), + jsonDoc.RootElement + ); + var data = await dataAccessor.GetFormData(dataAccessor.Instance.Data.First()); + var state = await LayoutTestUtils.GetLayoutModelTools(data, "ExpressionValidation"); + var hidden = await LayoutEvaluator.GetHiddenFieldsForRemoval(state); + + await Verify(hidden); + } +} diff --git a/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/Skjul felter.json b/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/Skjul felter.json new file mode 100644 index 000000000..b369db8c3 --- /dev/null +++ b/test/Altinn.App.Core.Tests/LayoutExpressions/FullTests/ExpressionValidation/Skjul felter.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://altinncdn.no/schemas/json/layout/layout.schema.v1.json", + "data": { + "layout": [ + { + "id": "nav-bar2", + "type": "NavigationBar" + }, + { + "id": "tittel1", + "type": "Header", + "size": "L", + "textResourceBindings": { + "title": "Skjul_felter.tittel.title" + } + }, + { + "id": "skjul-felter", + "type": "Checkboxes", + "dataModelBindings": { + "simpleBinding": "root.SF_skjul-felter" + }, + "layout": "row", + "required": false, + "textResourceBindings": { + "title": "Skjul_felter.skjul-felter.title" + }, + "options": [ + { + "value": "fornavn", + "label": "Fornavn" + }, + { + "value": "etternavn", + "label": "Etternavn" + }, + { + "value": "alder", + "label": "Alder" + }, + { + "value": "kjonn", + "label": "Kjønn" + }, + { + "value": "epost", + "label": "E-post" + }, + { + "value": "telefon", + "label": "Telefon" + }, + { + "value": "bosted", + "label": "Bosted" + } + ] + }, + { + "id": "skjul-arbeid", + "type": "Input", + "dataModelBindings": { + "simpleBinding": "root.SF_skjul-arbeidsgiver" + }, + "required": false, + "textResourceBindings": { + "title": "Skjul_felter.skjul-arbeid.title" + }, + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "skjul-prosjekt", + "type": "Input", + "dataModelBindings": { + "simpleBinding": "root.SF_skjul-prosjekt" + }, + "required": false, + "textResourceBindings": { + "title": "Skjul_felter.skjul-prosjekt.title" + }, + "grid": { + "xs": 12, + "sm": 6 + } + }, + { + "id": "button-group2", + "type": "ButtonGroup", + "children": ["nav2", "send-inn2"] + }, + { + "id": "nav2", + "type": "NavigationButtons", + "showBackButton": true, + "textResourceBindings": { + "next": "Skjul_felter.nav2.next", + "back": "Skjul_felter.nav2.back" + } + }, + { + "id": "send-inn2", + "type": "Button", + "textResourceBindings": { + "title": "Skjul_felter.send-inn2.title" + } + } + ] + } +}