diff --git a/16/umbraco-forms/.gitbook.yaml b/16/umbraco-forms/.gitbook.yaml new file mode 100644 index 00000000000..b047897620f --- /dev/null +++ b/16/umbraco-forms/.gitbook.yaml @@ -0,0 +1,8 @@ +root: ./ + +​structure: + readme: README.md + summary: SUMMARY.md + +redirects: + diff --git a/16/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_ (1).png b/16/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_ (1).png new file mode 100644 index 00000000000..2a8c064f60e Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_ (1).png differ diff --git a/16/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_.png b/16/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_.png new file mode 100644 index 00000000000..2a8c064f60e Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_.png differ diff --git a/16/umbraco-forms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Creating_A_Form.png b/16/umbraco-forms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Creating_A_Form.png new file mode 100644 index 00000000000..f900855ff15 Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Creating_A_Form.png differ diff --git a/16/umbraco-forms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Frontend.png b/16/umbraco-forms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Frontend.png new file mode 100644 index 00000000000..433b9c526ec Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Frontend.png differ diff --git a/16/umbraco-forms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Install.png b/16/umbraco-forms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Install.png new file mode 100644 index 00000000000..e4aa739cb56 Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/Documentations Icons_Umbraco_Forms_Install.png differ diff --git a/16/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete (1).png b/16/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete (1).png new file mode 100644 index 00000000000..148c59918e3 Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete (1).png differ diff --git a/16/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete.png b/16/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete.png new file mode 100644 index 00000000000..148c59918e3 Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete.png differ diff --git a/16/umbraco-forms/.gitbook/assets/FormSettingsFieldsDisplayed.png b/16/umbraco-forms/.gitbook/assets/FormSettingsFieldsDisplayed.png new file mode 100644 index 00000000000..18cc4170619 Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/FormSettingsFieldsDisplayed.png differ diff --git a/16/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80 (1).jpg b/16/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80 (1).jpg new file mode 100644 index 00000000000..d12b2963fc0 Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80 (1).jpg differ diff --git a/16/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80.jpg b/16/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80.jpg new file mode 100644 index 00000000000..d12b2963fc0 Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80.jpg differ diff --git a/16/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px (1).png b/16/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px (1).png new file mode 100644 index 00000000000..824e289115a Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px (1).png differ diff --git a/16/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px.png b/16/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px.png new file mode 100644 index 00000000000..824e289115a Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px.png differ diff --git a/16/umbraco-forms/.gitbook/assets/image.png b/16/umbraco-forms/.gitbook/assets/image.png new file mode 100644 index 00000000000..002dbcbe5c8 Binary files /dev/null and b/16/umbraco-forms/.gitbook/assets/image.png differ diff --git a/16/umbraco-forms/.gitbook/assets/umbraco_forms_swagger.json b/16/umbraco-forms/.gitbook/assets/umbraco_forms_swagger.json new file mode 100644 index 00000000000..360a0c02bf4 --- /dev/null +++ b/16/umbraco-forms/.gitbook/assets/umbraco_forms_swagger.json @@ -0,0 +1,555 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Umbraco Forms API", + "description": "Describes the Umbraco Forms API available for rendering and submitting forms. You can find out more about the API in [the documentation](https://docs.umbraco.com/umbraco-forms/v/12.forms.latest/developer/ajaxforms)", + "version": "Latest" + }, + "paths": { + "/umbraco/forms/delivery/api/v1/definitions/{id}": { + "get": { + "tags": [ + "Forms" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The form's Id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "contentId", + "in": "query", + "description": "The Id of the content page on which the form is hosted.", + "schema": { + "type": "string" + } + }, + { + "name": "culture", + "in": "query", + "description": "The culture code for the form's localization context.", + "schema": { + "type": "string" + } + }, + { + "name": "additionalData", + "in": "query", + "description": "Additional data provided when rendering the form.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FormDto" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/umbraco/forms/delivery/api/v1/entries/{id}": { + "post": { + "tags": [ + "Forms" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The form's Id.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FormEntryDto" + } + } + } + }, + "responses": { + "202": { + "description": "Accepted" + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "422": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "FieldConditionActionType": { + "enum": [ + "Show", + "Hide" + ], + "type": "integer", + "format": "int32" + }, + "FieldConditionLogicType": { + "enum": [ + "All", + "Any" + ], + "type": "integer", + "format": "int32" + }, + "FieldConditionRuleOperator": { + "enum": [ + "Is", + "IsNot", + "GreaterThen", + "LessThen", + "Contains", + "StartsWith", + "EndsWith" + ], + "type": "integer", + "format": "int32" + }, + "FormConditionDto": { + "type": "object", + "properties": { + "actionType": { + "$ref": "#/components/schemas/FieldConditionActionType" + }, + "logicType": { + "$ref": "#/components/schemas/FieldConditionLogicType" + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FormConditionRuleDto" + } + } + }, + "additionalProperties": false + }, + "FormConditionRuleDto": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "operator": { + "$ref": "#/components/schemas/FieldConditionRuleOperator" + }, + "value": { + "type": "string" + } + }, + "additionalProperties": false + }, + "FormDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "indicator": { + "type": "string" + }, + "cssClass": { + "type": "string", + "nullable": true + }, + "nextLabel": { + "type": "string", + "nullable": true + }, + "previousLabel": { + "type": "string", + "nullable": true + }, + "submitLabel": { + "type": "string", + "nullable": true + }, + "disableDefaultStylesheet": { + "type": "boolean" + }, + "fieldIndicationType": { + "$ref": "#/components/schemas/FormFieldIndication" + }, + "hideFieldValidation": { + "type": "boolean" + }, + "messageOnSubmit": { + "type": "string", + "nullable": true + }, + "messageOnSubmitIsHtml": { + "type": "boolean" + }, + "showValidationSummary": { + "type": "boolean" + }, + "gotoPageOnSubmit": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "gotoPageOnSubmitRoute": { + "$ref": "#/components/schemas/IApiContentRouteModel" + }, + "pages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FormPageDto" + } + } + }, + "additionalProperties": false + }, + "FormEntryDto": { + "type": "object", + "properties": { + "values": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "contentId": { + "type": "string", + "nullable": true + }, + "culture": { + "type": "string", + "nullable": true + }, + "additionalData": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "FormFieldDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "caption": { + "type": "string" + }, + "helpText": { + "type": "string", + "nullable": true + }, + "placeholder": { + "type": "string", + "nullable": true + }, + "cssClass": { + "type": "string", + "nullable": true + }, + "alias": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "requiredErrorMessage": { + "type": "string", + "nullable": true + }, + "pattern": { + "type": "string", + "nullable": true + }, + "patternInvalidErrorMessage": { + "type": "string", + "nullable": true + }, + "condition": { + "$ref": "#/components/schemas/FormConditionDto" + }, + "fileUploadOptions": { + "$ref": "#/components/schemas/FormFileUploadOptionsDto" + }, + "preValues": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FormFieldPrevalueDto" + } + }, + "settings": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "type": { + "$ref": "#/components/schemas/FormFieldTypeDto" + } + }, + "additionalProperties": false + }, + "FormFieldIndication": { + "enum": [ + "NoIndicator", + "MarkMandatoryFields", + "MarkOptionalFields" + ], + "type": "integer", + "format": "int32" + }, + "FormFieldPrevalueDto": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "caption": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "FormFieldTypeDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "supportsPreValues": { + "type": "boolean" + }, + "supportsUploadTypes": { + "type": "boolean" + }, + "renderInputType": { + "type": "string" + } + }, + "additionalProperties": false + }, + "FormFieldsetColumnDto": { + "type": "object", + "properties": { + "caption": { + "type": "string", + "nullable": true + }, + "width": { + "type": "integer", + "format": "int32" + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FormFieldDto" + } + } + }, + "additionalProperties": false + }, + "FormFieldsetDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "caption": { + "type": "string", + "nullable": true + }, + "condition": { + "$ref": "#/components/schemas/FormConditionDto" + }, + "columns": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FormFieldsetColumnDto" + } + } + }, + "additionalProperties": false + }, + "FormFileUploadOptionsDto": { + "type": "object", + "properties": { + "allowAllUploadExtensions": { + "type": "boolean" + }, + "allowedUploadExtensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "allowMultipleFileUploads": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "FormPageDto": { + "type": "object", + "properties": { + "caption": { + "type": "string", + "nullable": true + }, + "condition": { + "$ref": "#/components/schemas/FormConditionDto" + }, + "fieldsets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FormFieldsetDto" + } + } + }, + "additionalProperties": false + }, + "IApiContentRouteModel": { + "type": "object", + "properties": { + "path": { + "type": "string", + "readOnly": true + }, + "startItem": { + "$ref": "#/components/schemas/IApiContentStartItemModel" + } + }, + "additionalProperties": false + }, + "IApiContentStartItemModel": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "readOnly": true + }, + "path": { + "type": "string", + "readOnly": true + } + }, + "additionalProperties": false + }, + "ProblemDetails": { + "type": "object", + "properties": { + "type": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "status": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "detail": { + "type": "string", + "nullable": true + }, + "instance": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": { } + } + } + } +} \ No newline at end of file diff --git a/16/umbraco-forms/README.md b/16/umbraco-forms/README.md new file mode 100644 index 00000000000..c0cc5146f23 --- /dev/null +++ b/16/umbraco-forms/README.md @@ -0,0 +1,27 @@ +--- +description: >- + Documentation on how to work with Umbraco Forms for both editors and + developers. +--- + +# Umbraco Forms Documentation + +Umbraco Forms is a tool that lets you build forms of all shapes and sizes and put them on your Umbraco websites. Build forms using a long list of elements like multiple choice, dropdowns, text areas and checkboxes. Choose between a series of different workflows and control what happens once a form has been submitted. + +[Purchase Umbraco Forms](https://umbraco.com/products/umbraco-forms/) or sign up for an [Umbraco Cloud](https://try.umbraco.com/) project where Umbraco Forms is part of the package. + +
Installing Umbraco FormsInstall Umbraco Forms in a few steps.install.md_packageBlog_post_for_com_900x400px.png
Creating a FormCreate new Forms and add them to your Umbraco site in minutes.creating-a-formBlog_post_for_com_900x400px_1_8_7_.png
Preparing your FrontendEnsure you have the necessary client dependencies before adding a Form to your site.prepping-frontend.mdUmbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80.jpg
+ +## Quick Links + +{% content-ref url="upgrading/manualupgrade.md" %} +[manualupgrade.md](upgrading/manualupgrade.md) +{% endcontent-ref %} + +{% content-ref url="editor/attaching-workflows/" %} +[attaching-workflows](editor/attaching-workflows/) +{% endcontent-ref %} + +{% content-ref url="developer/forms-in-the-database.md" %} +[forms-in-the-database.md](developer/forms-in-the-database.md) +{% endcontent-ref %} diff --git a/16/umbraco-forms/SUMMARY.md b/16/umbraco-forms/SUMMARY.md new file mode 100644 index 00000000000..4af4cd066de --- /dev/null +++ b/16/umbraco-forms/SUMMARY.md @@ -0,0 +1,77 @@ +# Table of contents + +* [Umbraco Forms Documentation](README.md) +* [Legacy Documentation](legacy-documentation.md) +* [Release Notes](release-notes.md) + +## Installation + +* [Installing Umbraco Forms](installation/install.md) +* [Licensing](installation/the-licensing-model.md) + +## Upgrading + +* [Upgrading Umbraco Forms](upgrading/manualupgrade.md) +* [Version Specific Upgrade Notes](upgrading/version-specific.md) +* [Migration IDs](upgrading/migration-ids.md) + +## Editor + +* [Creating a Form - The basics](editor/creating-a-form/README.md) + * [Form Settings](editor/creating-a-form/form-settings.md) + * [Form Advanced Options](editor/creating-a-form/form-advanced.md) + * [Form Information](editor/creating-a-form/form-info.md) + * [Overview Of The Field Types](editor/creating-a-form/fieldtypes/README.md) + * [Date](editor/creating-a-form/fieldtypes/date.md) + * [File Upload](editor/creating-a-form/fieldtypes/fileupload.md) + * [reCAPTCHA V2](editor/creating-a-form/fieldtypes/recaptcha2.md) + * [reCAPTCHA V3](editor/creating-a-form/fieldtypes/recaptcha3.md) + * [Setting-up Conditional Logic on Fields](editor/creating-a-form/conditional-logic.md) +* [Attaching Workflows](editor/attaching-workflows/README.md) + * [Workflow Types](editor/attaching-workflows/workflow-types.md) +* [Viewing And Exporting Entries](editor/viewing-and-exporting-entries.md) +* [Defining And Attaching Prevalue Sources](editor/defining-and-attaching-prevaluesources/README.md) + * [Prevalue Source Types Overview](editor/defining-and-attaching-prevaluesources/prevalue-source-types.md) + +## Developer + +* [Property Editors](developer/property-editors.md) +* [Preparing Your Frontend](developer/prepping-frontend.md) +* [Rendering Forms](developer/rendering-forms.md) +* [Rendering Forms Scripts](developer/rendering-scripts.md) +* [Themes](developer/themes.md) +* [Custom Markup](developer/custom-markup.md) +* [Email Templates](developer/email-templates.md) +* [Working With Record Data](developer/working-with-data.md) +* [Umbraco Forms in the Database](developer/forms-in-the-database.md) +* [Extending](developer/extending/README.md) + * [Adding A Type To The Provider Model](developer/extending/adding-a-type.md) + * [Setting Types](developer/extending/setting-types.md) + * [Adding A Field Type To Umbraco Forms](developer/extending/adding-a-fieldtype.md) + * [Excluding a built-in field](developer/extending/excluding-a-built-in-field.md) + * [Adding A Prevalue Source Type To Umbraco Forms](developer/extending/adding-a-prevaluesourcetype.md) + * [Adding A Workflow Type To Umbraco Forms](developer/extending/adding-a-workflowtype.md) + * [Adding An Export Type To Umbraco Forms](developer/extending/adding-a-exporttype.md) + * [Adding a Magic String Format Function](developer/extending/adding-a-magic-string-format-function.md) + * [Adding A Server-Side Notification Handler To Umbraco Forms](developer/extending/adding-an-event-handler.md) + * [Adding a Validation Pattern](developer/extending/adding-a-validation-pattern.md) + * [Customize Default Fields and Workflows For a Form](developer/extending/customize-default-workflows.md) +* [Configuration](developer/configuration/README.md) + * [Forms Provider Type Details](developer/configuration/type-details.md) +* [Webhooks](developer/webhooks.md) +* [Security](developer/security.md) +* [Magic Strings](developer/magic-strings.md) +* [Health Checks](developer/healthchecks/README.md) + * [Apply keys and indexes](developer/healthchecks/apply-keys.md) + * [Apply keys and indexes for forms in the database](developer/healthchecks/forms-in-the-database-apply-keys.md) +* [Localization](developer/localization.md) +* [Headless/AJAX Forms](developer/ajaxforms.md) +* [Block List Labels](developer/blocklistlabels.md) +* [Field Types](developer/field-types.md) +* [Storing Prevalue Text Files With IPreValueTextFileStorage](developer/iprevaluetextfilestorage.md) + +## Tutorials + +* [Overview](tutorials/overview.md) +* [Creating a Contact Form](tutorials/creating-a-contact-form.md) +* [Creating a Multi-Page Form](tutorials/creating-a-multipage-form.md) diff --git a/16/umbraco-forms/developer/ajaxforms.md b/16/umbraco-forms/developer/ajaxforms.md new file mode 100644 index 00000000000..ba1e678dab6 --- /dev/null +++ b/16/umbraco-forms/developer/ajaxforms.md @@ -0,0 +1,600 @@ +# Headless/AJAX Forms + +Umbraco Forms provides an API for client-side rendering and submission of forms. This will be useful when you want to handle forms in a headless style scenario. + +## Enabling the API + +The Forms API is disabled by default. To enable it, set the `Umbraco:Forms:Options:EnableFormsApi` configuration key to `true`. + +For example: + +```json + "Umbraco": { + "Forms": { + "Options": { + "EnableFormsApi": true + } + } + } +``` + +## API Definition + +The API supports two endpoints, one for rendering a form and one for submitting it. + +{% swagger src="../.gitbook/assets/umbraco_forms_swagger.json" path="/umbraco/forms/delivery/api/v1/definitions/{id}" method="get" %} +[umbraco_forms_swagger.json](../.gitbook/assets/umbraco_forms_swagger.json) +{% endswagger %} + +{% swagger src="../.gitbook/assets/umbraco_forms_swagger.json" path="/umbraco/forms/delivery/api/v1/entries/{id}" method="post" %} +[umbraco_forms_swagger.json](../.gitbook/assets/umbraco_forms_swagger.json) +{% endswagger %} + +As well as this documentation, the definition of the API can also be reviewed via the Swagger UI. + +This is available alongside the Umbraco 12 Content Delivery Api at: `/umbraco/swagger/index.html`. Select "Umbraco Forms API" from the "Select a definition" list to view the methods available. + +![Swagger UI](images/swagger-ui.png) + +The Open API specification is available from: `/umbraco/swagger/forms/swagger.json` + +### Requesting a Form Definition + +To request the definition of a form, the following request can be made: + +```none +GET /umbraco/forms/delivery/api/v1/definitions/{id}?contentId={contentId}&culture={culture}&additionalData[{key}]={value}&additionalData[key2]={value2} +``` + +The GET request requires the Guid identifying the form. + +An optional `contentId` parameter can be provided, which can either be the integer or GUID identifier for the current page. If provided, the content item identified will be used for Forms features requiring information from the page the form is hosted on. This includes the parsing of ["magic string" placeholders](magic-strings.md). + +A `culture` parameter can also be provided, expected as an ISO code identifying a language used in the Umbraco installation (for example, `en-US`). This will be used to ensure the correct translation for dictionary keys is used. It will also retrieve page content from the appropriate language variant. If the parameter is not provided in the request, the default Umbraco language will be used. + +Finally, an `additionalData` parameter can be provided as a dictionary. This information will be made available when rendering the form allowing it to be used as a source for ["magic string" replacements](./magic-strings.md). + +If the requested form is not found, a 404 status code will be returned. + +A successful request will return a 200 status code. An example response is as follows. It will differ depending on the pages, fields and other settings available for the form. + +```json +{ + "disableDefaultStylesheet": false, + "fieldIndicationType": "MarkMandatoryFields", + "hideFieldValidation": false, + "id": "34ef4a19-efa7-40c1-b8b6-2fd7257f2ed3", + "indicator": "*", + "messageOnSubmit": "Thanks for submitting the form", + "name": "Simple Comment Form", + "nextLabel": "Next", + "pages": [ + { + "caption": "Your comment", + "fieldsets": [ + { + "caption": "", + "columns": [ + { + "caption": "", + "width": 12, + "fields": [ + { + "alias": "name", + "caption": "Name", + "condition": { + "actionType": "Show", + "logicType": "All", + "rules": [] + }, + "helpText": "[#message] from [#pageName]", + "id": "25185934-9a61-491c-9610-83dfe774662c", + "pattern": "", + "patternInvalidErrorMessage": "Please provide a valid value for Name", + "placeholder": "", + "preValues": [], + "required": true, + "requiredErrorMessage": "Please provide a value for Name", + "settings": { + "defaultValue": "", + "placeholder": "Please enter your name.", + "showLabel": "", + "maximumLength": "", + "fieldType": "", + "autocompleteAttribute": "" + }, + "type": { + "id": "3f92e01b-29e2-4a30-bf33-9df5580ed52c", + "name": "Short answer" + } + }, + { + "alias": "email", + "caption": "Email", + "condition": { + "actionType": "Show", + "logicType": "All", + "rules": [] + }, + "helpText": "", + "id": "816fdf3b-a796-4677-a317-943a54bf9d55", + "pattern": "^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,4})$", + "patternInvalidErrorMessage": "Please provide a valid value for Email", + "placeholder": "", + "preValues": [], + "required": true, + "requiredErrorMessage": "Please provide a value for Email", + "settings": { + "defaultValue": "", + "placeholder": "", + "showLabel": "", + "maximumLength": "", + "fieldType": "email", + "autocompleteAttribute": "" + }, + "type": { + "id": "3f92e01b-29e2-4a30-bf33-9df5580ed52c", + "name": "Short answer" + } + }, + { + "alias": "comment", + "caption": "Comment", + "condition": { + "actionType": "Show", + "logicType": "All", + "rules": [] + }, + "helpText": "", + "id": "9d723100-ec34-412f-aaa5-516634d7c833", + "pattern": "", + "patternInvalidErrorMessage": "Please provide a valid value for Comment", + "placeholder": "", + "preValues": [], + "required": false, + "requiredErrorMessage": "Please provide a value for Comment", + "settings": { + "defaultValue": "", + "placeholder": "", + "showLabel": "", + "autocompleteAttribute": "", + "numberOfRows": "2", + "maximumLength": "" + }, + "type": { + "id": "023f09ac-1445-4bcb-b8fa-ab49f33bd046", + "name": "Long answer" + } + }, + { + "alias": "country", + "caption": "Country", + "condition": { + "actionType": "Show", + "logicType": "All", + "rules": [] + }, + "helpText": "", + "id": "30ff8f37-28d4-47df-f281-422b36c62e73", + "pattern": "", + "patternInvalidErrorMessage": "Please provide a valid value for Country", + "placeholder": "", + "preValues": [ + { + "caption": "France", + "value": "fr" + }, + { + "caption": "Italy", + "value": "it" + }, + { + "caption": "Span", + "value": "es" + }, + { + "caption": "United Kingdom", + "value": "gb" + } + ], + "required": false, + "requiredErrorMessage": "Please provide a value for Country", + "settings": { + "defaultValue": "", + "allowMultipleSelections": "", + "showLabel": "", + "autocompleteAttribute": "", + "selectPrompt": "Please select" + }, + "type": { + "id": "0dd29d42-a6a5-11de-a2f2-222256d89593", + "name": "Dropdown" + } + }, + { + "alias": "favouriteColour", + "caption": "Favourite Colour", + "condition": { + "actionType": "Show", + "logicType": "All", + "rules": [] + }, + "helpText": "", + "id": "a6e2e27f-097d-476a-edb9-4aa79449ab5c", + "pattern": "", + "patternInvalidErrorMessage": "Please provide a valid value for Favourite Colour", + "placeholder": "", + "preValues": [ + { + "caption": "Red", + "value": "red" + }, + { + "caption": "Green", + "value": "green" + }, + { + "caption": "Yellow", + "value": "yello" + } + ], + "required": false, + "requiredErrorMessage": "Please provide a value for Favourite Colour", + "settings": { + "defaultValue": "", + "showLabel": "" + }, + "type": { + "id": "fab43f20-a6bf-11de-a28f-9b5755d89593", + "name": "Multiple choice" + } + }, + { + "alias": "dataConsent", + "caption": "Data consent", + "condition": { + "actionType": "Show", + "logicType": "All", + "rules": [] + }, + "helpText": "Please indicate if it's OK to store your data.", + "id": "9f25acaf-4ac4-4105-9afe-eb0bb0c03b31", + "pattern": "", + "patternInvalidErrorMessage": "Please provide a valid value for Data consent", + "placeholder": "", + "preValues": [], + "required": true, + "requiredErrorMessage": "Please confirm your data consent", + "settings": { + "acceptCopy": "Yes, I give permission to store and process my data.", + "showLabel": "" + }, + "type": { + "id": "a72c9df9-3847-47cf-afb8-b86773fd12cd", + "name": "Data Consent" + } + }, + { + "alias": "tickToAddMoreInfo", + "caption": "Tick to add more info", + "condition": { + "actionType": "Show", + "logicType": "All", + "rules": [] + }, + "helpText": "", + "id": "6ce0cf78-5102-47c1-85c6-9530d9e9c6a6", + "pattern": "", + "patternInvalidErrorMessage": "Please provide a valid value for Tick to add more info", + "placeholder": "", + "preValues": [], + "required": false, + "requiredErrorMessage": "Please provide a value for Tick to add more info", + "settings": { + "defaultValue": "" + }, + "type": { + "id": "d5c0c390-ae9a-11de-a69e-666455d89593", + "name": "Checkbox" + } + }, + { + "alias": "moreInfo", + "caption": "More info", + "condition": { + "actionType": "Show", + "logicType": "All", + "rules": [ + { + "field": "6ce0cf78-5102-47c1-85c6-9530d9e9c6a6", + "operator": "Is", + "value": "on" + } + ] + }, + "helpText": "", + "id": "5b4100ed-cc5e-4113-943c-ee5a8f4e448d", + "pattern": "", + "patternInvalidErrorMessage": "Please provide a valid value for More info", + "placeholder": "", + "preValues": [], + "required": false, + "requiredErrorMessage": "Please provide a value for More info", + "settings": { + "defaultValue": "", + "placeholder": "", + "showLabel": "", + "maximumLength": "", + "fieldType": "", + "autocompleteAttribute": "" + }, + "type": { + "id": "3f92e01b-29e2-4a30-bf33-9df5580ed52c", + "name": "Short answer" + } + } + ], + "width": 0 + } + ], + "id": "d677b96f-488d-4052-b00d-fb852b35e9c5" + } + ] + } + ], + "previousLabel": "Previous", + "showValidationSummary": false, + "submitLabel": "Submit" +} +``` + +It's possible to define either a message displayed when a form is submitted, or a redirect to another website page. + +With the former, the output will be as above, and as shown in this extract: + +```json +{ + ... + "messageOnSubmit": "Thanks for submitting the form", + ... +} +``` + +When a redirect is configured, details of the content ID and a route will be included, as follows: + +```json +{ + ... + "gotoPageOnSubmit": "eab72f13-b22e-46d5-b270-9c196e49a53b", + "gotoPageOnSubmitRoute": { + "path": "/contact-us/thanks/", + "startItem": { + "id": "ca4249ed-2b23-4337-b522-63cabe5587d1", + "path": "home" + } + }, + ... +} +``` + +### Submitting a Form Entry + +To submit a form entry, the following request can be made: + +```none +POST /umbraco/forms/delivery/api/v1/entries/{id} +``` + +The POST request requires the Guid identifying the form. + +It also requires a `Content-Type` header of `application/json` and accepts a body as per this example: + +```json +{ + "values": { + "name": "Fred", + "email": "fred@test.com", + "comment": "Test", + "country": "it", + "favouriteColours": ["red", "green"], + "dataConsent": "on" + }, + "contentId": "ca4249ed-2b23-4337-b522-63cabe5587d1", + "culture": "en-US", + "additionalData": { + "foo": "bar", + "baz": "buzz", + } +} +``` + +The `values` collection consists of a set of name/value pairs, where the name is the alias of a form field. The value is the value of the submitted field, which can either be a string, or an array of strings. In this way we support fields that accept multiple values, such as checkbox lists. + +The `contentId` and `culture` parameters are optional. If provided they will be used to customize the response for the current page and language respectively. + +Similarly the `additionalData` dictionary is optional. This data is associated with the created record and made available within workflows. + +In the case of a validation error, a 422 "Unprocessable Entity" status code will be returned, along with a response similar to the following: + +```json +{ + "errors": { + "name": [ + "Please provide a value for Name" + ] + }, + "extensions": {}, + "status": 422, + "title": "One or more validation errors occurred." +} +``` + +A successful response will return a 202 "Accepted" status code. + +It will contain an object detailing the post-submission configured the form, for example: + +```json +{ + "gotoPageOnSubmit": "3cce2545-e3ac-44ec-bf55-a52cc5965db3", + "gotoPageOnSubmitRoute": { + "path": "/about-us/", + "startItem": { + "id": "ca4249ed-2b23-4337-b522-63cabe5587d1", + "path": "home" + } + }, + "messageOnSubmit": "Thanks for your entry", + "messageOnSubmitIsHtml": false +} +``` + +#### File Uploads + +The file upload field type is supported via the API for the rendering and submission of forms. + +When retrieving a form definition, some additional detail is provided for fields of this type to allow for the appropriate rendering of the form interface: + +```json + ... + "fields": [ + { + "alias": "uploadAPicture", + ... + "fileUploadOptions": { + "allowAllUploadExtensions": false, + "allowedUploadExtensions": [ + "png", + "jpg", + "gif" + ], + "allowMultipleFileUploads": false + }, + } + ] + ... +``` + +When submitting a form, the value should be a JSON structure that provides a collection. Each item in the collection should contain the file name and the file contents as a base64 encoded data URL. + +```json +{ + "values": { + "uploadAPicture": [ + { + "fileName": "mypic.jpg", + "fileContents": "data:image/png;base64,iVBORw..." + } + ] + }, +} +``` + +## Securing the API + +### Antiforgery Protection + +When posting forms in the traditional way, via a full page post back, an anti-forgery token is generated and validated. This provides protection against Cross-Site Request Forgery (CSRF) attacks. + +The same protection is available for forms submitted via AJAX techniques. + +In order to generate the token and provide it in the form post, the following code can be applied to the .cshtml template: + +```csharp +@using Microsoft.AspNetCore.Antiforgery + +@inject IAntiforgery antiforgery + +@{ + var tokenSet = antiforgery.GetAndStoreTokens(Context); +} +``` + +When posting the form, the header value generated can be provided, where it will be validated server-side before accepting the request. + +```javascript + let response = await fetch("/umbraco/forms/delivery/api/v1/entries/" + formId, { + method: "POST", + headers: { + "Content-Type": "application/json", + "@tokenSet.HeaderName" : "@tokenSet.RequestToken" + }, + body: JSON.stringify(data), + }); +``` + +### API Key + +The antiforgery token security approach is valid when building a client-side integration with API calls made from the browser. + +Providing the token isn't possible though in other headless situations such as server-to-server requests. In these situations, an alternative approach to securing the API is available. + +Firstly, with server-to-server integrations you will want to disable the antiforgery token protection. + +This is done by setting the `Umbraco:Forms:Security:EnableAntiForgeryTokenForFormsApi` configuration key to a value of `false`. + +You should then configure an API key `Umbraco:Forms:Security:FormsApiKey`. This can be any string value, but it should be complex enough to resist being guessed by a brute force attack. + +With this in place any request to the Forms API will be rejected unless the configured value is provided in an HTTP header named `Api-Key`. + +## Rendering and Submitting forms with JavaScript + +For an illustrative example showing how a form can be rendered, validated and submitted using the API and vanilla JavaScript, please [see this gist](https://gist.github.com/AndyButland/9371175d6acf24a5307b053398f08448). + +Examples demonstrating how to handle a file upload and use reCAPTCHA fields are included. + +## Working with the CMS Content Delivery API + +The [Content Delivery API](https://docs.umbraco.com/umbraco-cms/v/12.latest/reference/content-delivery-api) provides headless capabilities within Umbraco by allowing you to retrieve content in JSON format. + +When retrieving content that contains an Umbraco Forms form picker, the output by default will consist of the ID of the selected form: + +```json +{ + "name": "Contact Us", + "route": { + "path": "/contact-us/", + "startItem": { + "id": "ca4249ed-2b23-4337-b522-63cabe5587d1", + "path": "home" + } + }, + "id": "4a1f4198-e143-48ba-a0f5-1a7ef2df23aa", + "contentType": "contactPage", + "properties": { + "title": "Contact Us", + "contactForm": { + "id": "3623b232-9296-4bf0-b16c-57801dc4f296", + "form": null + } + } +} +``` + +With [expanded output](https://docs.umbraco.com/umbraco-cms/v/12.latest/reference/content-delivery-api#output-expansion) for the property, the full details of the form will be available. The structure and content of the form representation will be exactly the same as that provided by the Forms API itself. + +```json +{ + "name": "Contact Us", + "route": { + "path": "/contact-us/", + "startItem": { + "id": "ca4249ed-2b23-4337-b522-63cabe5587d1", + "path": "home" + } + }, + "id": "4a1f4198-e143-48ba-a0f5-1a7ef2df23aa", + "contentType": "contactPage", + "properties": { + "title": "Contact Us", + "contactForm": { + "id": "3623b232-9296-4bf0-b16c-57801dc4f296", + "form": { + "id": "3623b232-9296-4bf0-b16c-57801dc4f296", + "name": "Contact Form", + ... + "pages": [ ... ] + } + } + } +} +``` diff --git a/16/umbraco-forms/developer/block-list-labels.md b/16/umbraco-forms/developer/block-list-labels.md new file mode 100644 index 00000000000..1e409fa0e43 --- /dev/null +++ b/16/umbraco-forms/developer/block-list-labels.md @@ -0,0 +1,2 @@ +# Block List Labels + diff --git a/16/umbraco-forms/developer/blocklistlabels.md b/16/umbraco-forms/developer/blocklistlabels.md new file mode 100644 index 00000000000..c522271a943 --- /dev/null +++ b/16/umbraco-forms/developer/blocklistlabels.md @@ -0,0 +1,27 @@ +# Block List Labels + +When working with the Block List editor, [the editor experience is enhanced](https://docs.umbraco.com/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor#editor-appearance) by defining a label for the appearance of the Block. + +These labels can use [Umbraco Flavored Markdown (UFM)](https://docs.umbraco.com/umbraco-cms/reference/umbraco-flavored-markdown). + +An option is available to display a form's name - `umbFormName`. + +It should be rendered as follows, with a reference to the property alias on the block element that uses a form picker. + +``` +{umbFormName: } +``` + +If you add a reference to a property containing a form to the block's label, it will render with the form's Id. + +For example, assuming a property containing a picked form with an alias of `contactForm`: + +``` +{=contactForm} +``` + +By using the markdown as follows, the form's name will be displayed instead. + +``` +{umbFormName: contactForm} +``` diff --git a/16/umbraco-forms/developer/configuration/README.md b/16/umbraco-forms/developer/configuration/README.md new file mode 100644 index 00000000000..051fce82a91 --- /dev/null +++ b/16/umbraco-forms/developer/configuration/README.md @@ -0,0 +1,572 @@ +--- +description: >- + In Umbraco Forms it's possible to customize the functionality with various + configuration values. +--- + +# Configuration + +With Umbraco Forms it's possible to customize the functionality with various configuration values. + +## Editing configuration values + +All configuration for Umbraco Forms is held in the `appSettings.json` file found at the root of your Umbraco website. If the configuration has been customized to use another source, then the same keys and values discussed in this article can be applied there. + +The convention for Umbraco configuration is to have package based options stored as a child structure below the `Umbraco` element, and as a sibling of `CMS`. Forms configuration follows this pattern, i.e.: + +```json +{ + ... + "Umbraco": { + "CMS": { + ... + }, + "Forms": { + ... + } + } +} +``` + +All configuration for Forms is optional. In other words, all values have defaults that will be applied if no configuration is available for a particular key. + +For illustration purposes, the following structure represents the full set of options for configuration of Forms, along with the default values. This will help when you need to provide a different setting to understand where it should be applied. + +```json + "Forms": { + "FormDesign": { + "DisableAutomaticAdditionOfDataConsentField": false, + "DisableDefaultWorkflow": false, + "MaxNumberOfColumnsInFormGroup": 12, + "DefaultTheme": "default", + "DefaultEmailTemplate": "Forms/Emails/Example-Template.cshtml", + "Defaults": { + "ManualApproval": false, + "DisableStylesheet": false, + "MarkFieldsIndicator": "NoIndicator", + "Indicator": "*", + "RequiredErrorMessage": "Please provide a value for {0}", + "InvalidErrorMessage": "Please provide a valid value for {0}", + "ShowValidationSummary": false, + "HideFieldValidationLabels": false, + "NextPageButtonLabel": "Next", + "PreviousPageButtonLabel": "Previous", + "SubmitButtonLabel": "Submit", + "MessageOnSubmit": "Thank you", + "StoreRecordsLocally": true, + "AutocompleteAttribute": "", + "DaysToRetainSubmittedRecordsFor": 0, + "DaysToRetainApprovedRecordsFor": 0, + "DaysToRetainRejectedRecordsFor": 0, + "ShowPagingOnMultiPageForms": "None", + "PagingDetailsFormat": "Page {0} of {1}", + "PageCaptionFormat": "Page {0}", + "ShowSummaryPageOnMultiPageForms": false, + "SummaryLabel": "Summary of Entry" + }, + "RemoveProvidedFormTemplates": false, + "FormElementHtmlIdPrefix": "", + "SettingsCustomization": { + "DataSourceTypes": {}, + "FieldTypes": {}, + "PrevalueSourceTypes": {}, + "WorkflowTypes": {}, + }, + "MandatoryFieldsetLegends": false + }, + "Options": { + "IgnoreWorkFlowsOnEdit": "True", + "AllowEditableFormSubmissions": false, + "AppendQueryStringOnRedirectAfterFormSubmission": false, + "CultureToUseWhenParsingDatesForBackOffice": "", + "TriggerConditionsCheckOn": "change", + "ScheduledRecordDeletion": { + "Enabled": false, + "FirstRunTime": "", + "Period": "1.00:00:00" + }, + "DisableRecordIndexing": false, + "EnableFormsApi": false, + "EnableRecordingOfIpWithFormSubmission": false, + "UseSemanticFieldsetRendering": false, + "DisableClientSideValidationDependencyCheck": false, + "DisableRelationTracking": false, + "TrackRenderedFormsStorageMethod": "HttpContextItems", + "EnableMultiPageFormSettings": true, + "EnableAdvancedValidationRules": false + }, + "Security": { + "DisallowedFileUploadExtensions": "config,exe,dll,asp,aspx", + "AllowedFileUploadExtensions": "", + "EnableAntiForgeryToken": true, + "SavePlainTextPasswords": false, + "DisableFileUploadAccessProtection": false, + "DefaultUserAccessToNewForms": "Grant", + "ManageSecurityWithUserGroups": false, + "GrantAccessToNewFormsForUserGroups": "admin,editor", + "FormsApiKey": "", + "EnableAntiForgeryTokenForFormsApi": true, + }, + "FieldTypes": { + "DatePicker": { + "DatePickerYearRange": 10, + "DatePickerFormat": "LL", + "DatePickerFormatForValidation": "" + }, + "Recaptcha2": { + "PublicKey": "", + "PrivateKey": "" + }, + "Recaptcha3": { + "SiteKey": "", + "PrivateKey": "", + "Domain": "Google", + "VerificationUrl": "https://www.google.com/recaptcha/api/siteverify", + "ShowFieldValidation": true + }, + "RichText": { + "DataTypeId": "ca90c950-0aff-4e72-b976-a30b1ac57dad" + }, + "TitleAndDescription": { + "AllowUnsafeHtmlRendering": false + } + } + } +``` + +## Form design configuration + +### DisableAutomaticAdditionOfDataConsentField + +This configuration value expects a `true` or `false` value and can be used to disable the feature where all new forms are provided with a default "Consent for storing submitted data" field on creation. Defaults to `false`. + +### DisableDefaultWorkflow + +This configuration value expects a `true` or `false` value and can be used to toggle if new forms that are created adds an email workflow to send the result of the form to the current user who created the form. Defaults to `false`. + +### MaxNumberOfColumnsInFormGroup + +This setting controls the maximum number of columns that can be created by editors when they configure groups within a form. The default value used if the setting value is not provided is 12. + +### DefaultTheme + +This setting allows you to configure the name of the theme to use when an editor has not specifically selected one for a form. If empty or missing, the default value of "default" is used. If a custom default theme is configured, it will be used for rendering forms where the requested file exists, and where not, will fall back to the out of the box default theme. + +### DefaultEmailTemplate + +When creating an empty form, a single workflow is added that will send an email to the current user's address. By default, the template shipped with Umbraco Forms is available at `Forms/Emails/Example-Template.cshtml` is used. + +If you have created a custom template and would like to use that as the default instead, you can set the path here using this configuration setting. + +### RemoveProvidedFormTemplates + +Similarly, the provided form templates available from the form creation dialog can be removed from selection. To do this, set this configuration value to `true`. + +### FormElementHtmlIdPrefix + +By default the value of HTML `id` attribute rendered for fieldsets and fields using the default theme is the GUID associated with the form element. Although [this is valid](https://developer.mozilla.org/en-US/docs/Web/HTML/Global\_attributes/id), some browsers, particularly Safari, may report issues with this if the identifier begins with a number. To avoid such issues, the attribute values can be prefixed with the value provided in this configuration element. + +For example, providing a value of `"f_"` will apply a prefix of "f\_" to each fieldset and field `id` attribute. + +### SettingsCustomization + +Forms introduced the ability to configure settings for the field, workflow, data source, and prevalue sources. The default behavior, when a new field or workflow is added to a form, is for each setting to be empty. The values are then completed by the editor. All settings defined on the type are displayed for entry. + +In some situations, you may want to hide certain settings from entry, so they always take an empty value. In others, you may want to provide a default value that the editor can accept or amend. And lastly, you may have a requirement for a fixed, non-empty value, that's enforced by the organization and not editable. Each of these scenarios can be supported by this configuration setting. + +It consists of four dictionaries, one for each type: + +* `DataSourceTypes` +* `FieldTypes` +* `PrevalueSourceTypes` +* `WorkflowTypes` + +Each dictionary can be identified using the GUID or alias of the type as the key. The value is set to the following structure that contains three settings: + +```json +{ + "IsHidden": true|false, + "DefaultValue": "", + "IsReadOnly": true|false +} +``` + +* `IsHidden` - if provided and set to true the setting will be hidden and will always have an empty value. +* `DefaultValue` - if provided the value will be pre-filled when a type using it is created. +* `IsReadOnly` - used in conjunction with the above, if set the field won't be editable and hence whatever is set as the `DefaultValue` won't be able to be changed. If set to false (or omitted) the editor can change the value from the default. + +In this example, the sender address field on a workflow for sending emails can be hidden, such that the system configured value is always used: + +```json + "SettingsCustomization": { + "WorkflowTypes": { + "sendEmailWithRazorTemplate": { + "SenderEmail": { + "IsHidden": true + } + } + }, + } +``` + +Here an organization-approved reCAPTCHA score threshold is defined, that can't be changed by editors: + +```json + "SettingsCustomization": { + "FieldTypes": { + "recaptcha3": { + "ScoreThreshold": { + "DefaultValue": "0.8", + "IsReadOnly": true + } + } + }, + } +``` + +In order to configure this setting, you will need to know the GUID or alias for the type and the property name for each setting. You can find [these values for the built-in Forms types her](type-details.md)e. + +Take care to not hide any settings that are required for the particular field or workflow type (for example, the `Subject` field for email workflows). If you do that, the item will fail validation when an editor tries to create it. + +The default value and read-only settings apply to most setting types. There is an exception for complex ones where a default string value isn't appropriate. An example of one of these is the field mapper used in the "Send to URL" workflow. + +### MandatoryFieldsetLegends + +When creating a form with Umbraco Forms, adding captions to the groups for fields is optional. To follow accessibility best practices, these fields should be completed. When they are, the group of fields are presented within a `
` element that has a populated ``. + +If you want to ensure form creators always have to provide a caption, you can set the value of this setting to `true`. + +### Form default settings configuration + +The following configured values are applied to all forms as they are created. They can then be amended on a per-form basis via the Umbraco backoffice. + +Once the form has been created, the values are set explicitly on the form, so subsequent changes to the defaults in configuration won't change the settings used on existing forms. + +#### ManualApproval + +This setting needs to be a `true` or `false` value and will allow you to toggle if a form allows submissions to be post moderated. Most use cases are for publicly shown entries such as blog post comments or submissions for a social campaign. Defaults to `false`. + +#### DisableStylesheet + +This setting needs to be a `true` or `false` value and will allow you to toggle if the form will include some default styling with the Umbraco Forms CSS stylesheet. Defaults to `false`. + +#### MarkFieldsIndicator + +This setting can have the following values to allow you to toggle the mode of marking mandatory or optional fields: + +* `NoIndicator` (default) +* `MarkMandatoryFields` +* `MarkOptionalFields` + +#### Indicator + +This setting is used to mark the mandatory or optional fields based on the setting above. By default this is an asterisk `*`. + +#### RequiredErrorMessage + +This allows you to configure the required error validation message. By default this is `Please provide a value for {0}` where the `{0}` is used to replace the name of the field that is required. + +#### InvalidErrorMessage + +This allows you to configure the invalid error validation message. By default this is `Please provide a valid value for {0}` where the `{0}` is used to replace the name of the field that is invalid. + +#### ShowValidationSummary + +This setting needs to be a `true` or `false` value and will allow you to toggle if the form will display all form validation error messages in a validation summary together. Defaults to `false`. + +#### HideFieldValidationLabels + +This setting needs to be a `true` or `false` value and will allow you to toggle if the form will show inline validation error messages next to the form field that is invalid. Defaults to `false`. + +#### NextPageButtonLabel, PreviousPageButtonLabel, SubmitButtonLabel + +These settings configure the default next, previous, and submit button labels. By default, these are `Next`, `Previous`, and `Submit` respectively. These labels can be amended on a form-by-form basis via the form's **Settings** section. + +#### MessageOnSubmit + +This allows you to configure what text is displayed when a form is submitted and is not being redirected to a different content node. Defaults to `Thank you`. + +#### StoreRecordsLocally + +This setting needs to be a `True` or `False` value and will allow you to toggle if form submission data should be stored in the Umbraco Forms database tables. By default this is set to `True`. + +#### AutocompleteAttribute + +This setting provides a value to be used for the `autocomplete` attribute for newly created forms. By default the value is empty, but can be set to `on` or `off` to have that value applied as the attribute value used when rendering the form. + +#### DaysToRetainSubmittedRecordsFor + +Introduced in 10.2, this setting controls the initial value of the number of days to retain form submission records for newly created forms. By default the value is 0, which means records will not be deleted at any time and are retained forever. + +If set to a positive number, a date value calculated by taking away the number of days configured from the current date is found. Records in the 'submitted' state, that are older than this date, will be flagged for removal. + +#### DaysToRetainApprovedRecordsFor + +Applies as per `DaysToRetainSubmittedRecordsFor` but for records in the 'approved' state. + +#### DaysToRetainRejectedRecordsFor + +Applies as per `DaysToRetainSubmittedRecordsFor` but for records in the 'rejected' state. + +### ShowPagingOnMultiPageForms + +Defines whether and where paging details are displayed for multi-page forms. + +### PagingDetailsFormat + +Defines the paging details format for multi-page forms. + +### PageCaptionFormat + +Defines the page caption format for multi-page forms. + +### ShowSummaryPageOnMultiPageForms + +Defines whether summary pages are on by default for multi-page forms. + +### SummaryLabel + +Defines the default summary label for multi-page forms. + +## Package options configuration + +### IgnoreWorkFlowsOnEdit + +This configuration expects a `True` or `False` string value, or a comma-separated list of form names, and allows you to toggle if a form submission is edited again, that the workflows on the form will re-fire after an update to the form submission. This is used in conjunction with the `AllowEditableFormSubmissions` configuration value. Defaults to `True`. + +### AllowEditableFormSubmissions + +This configuration value expects a `true` or `false` value and can be used to toggle the functionality to allow a form submission to be editable and re-submitted. When the value is set to `true` it allows Form Submissions to be edited using the following querystring for the page containing the form on the site. `?recordId=GUID` Replace `GUID` with the GUID of the form submission. Defaults to `false`. + +{% hint style="info" %} +There was a typo in this setting where it had been named as `AllowEditableFormSubmissions`. This is the name that needs to be used in configuration for Forms 9. In Forms 10 this was be corrected to the now documented value of `AllowEditableFormSubmissions`. +{% endhint %} + +{% hint style="warning" %} +Enable this feature ONLY if you understand the security implications. +{% endhint %} + +### AppendQueryStringOnRedirectAfterFormSubmission + +When redirecting following a form submission, a `TempData` value is set that is used to ensure the submission message is displayed rather than the form itself. In certain situations, such as hosting pages with forms in IFRAMEs from other websites, this value is not persisted between requests. + +By setting the following value to True, a querystring value of `formSubmitted=`, will be used to indicate a form submitted on the previous request. + +### CultureToUseWhenParsingDatesForBackOffice + +This setting has been added to help resolve an issue with multi-lingual setups. + +When Umbraco Forms stores data for a record, it saves the values submitted for each field into a dedicated table for each type (string, date etc.). It also saves a second copy of the record in a JSON structure which is more suitable for fast look-up and display in the backoffice. Date values are serialized using the culture used by the front-end website when the form entry is stored. + +When displaying the data in the backoffice, the date value needs to be parsed back into an actual date object for formatting. And this can cause a problem if the backoffice user is using a different language, and hence culture setting, than that used when the value was stored. + +The culture used when storing the form entry is recorded, thus we can ensure the correct value is used when parsing the date. However, this doesn't help for historically stored records. To at least partially mitigate the problem, when you have editors using different languages to a single language presented on the website front-end, you can set this value to match the culture code used on the website. This ensures the date fields in the backoffice are correctly presented. + +Taking an example of a website globalization culture code setting of "en-US" (and a date format of `m/d/y`), but an editor uses "en-GB" (which formats dates as of `d/m/y`). By setting the value of this configuration key to "en-US", you can ensure that the culture when parsing dates for presentation in the backoffice will match that used when the value was stored. + +If no value is set, and no culture value was stored alongside the form entry, the culture based on the language associated with the current backoffice user will be used. + +### TriggerConditionsCheckOn + +This configuration setting provides control over the client-side event used to trigger conditions. The `change` event is the default used if this setting is empty. It can also be set to a value of `input`. The main difference seen here relates to text fields, with the "input" event firing on each key press, and the "change" only when the field loses focus. + +### ScheduledRecordDeletion + +Scheduled deletion of records older than a specified number of days. It uses a background task to run the cleanup operation, which can be customized with the following settings. + +#### Enabled + +By default this value is `false` and no data will be removed. Even if forms are configured to have submitted data cleaned up, no records will be deleted. A note will be displayed in the backoffice indicating this status. + +Set to `true` to enabled the background task. + +#### FirstRunTime + +This will configure when the record deletion process will run for the first time. If the value is not configured the health checks will run after a short delay following the website start. The value is specified as a string in crontab format. For example, a value of `"* 4 * * *"` will first run the operation at 4 a.m. + +#### Period + +Defines how often the record deletion process will run. The default value is `1.00:00:00` which is equivalent to once every 24 hours. Shorter or longer periods can be set using different datetime strings. + +### DisableRecordIndexing + +Set this value to `true` to disable the default behavior of indexing the form submissions into the Examine index. + +If indexing has already occurred, you will still need to manually remove the files (found in `App_Data\TEMP\ExamineIndexes\UmbracoFormsRecords`). They will be recreated if indexing is subsequently re-enabled. + +### EnableFormsApi + +Set this value to `true` to enable the Forms API supporting headless and AJAX forms. + +### EnableRecordingOfIpWithFormSubmission + +By default, the user's IP address is not recorded when a form is submitted and stored in the `UFRecords` database table. + +To include this information in the saved data, set this value to `true`. + +If recording IPs and your site is behind a proxy, load balancer or CDN, we recommend using [ASP.NET's forwarded headers middleware](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-7.0) to ensure the correct value for the client IP is resolved. + +### UseSemanticFieldsetRendering + +In Forms 12.1 amends were made to the default theme for Forms that improved accessibility. Specifically we provide the option to use alternative markup for rendering checkbox and radio button lists. These use the more semantically correct `fieldset` and `legend` elements, instead of the previously used `div` and `label`. + +Although this semantic markup is preferred, it could be a presentational breaking change for those styling the default theme. As such we have made this markup improvement optional. You can opt into using it by setting this configuration value to `true`. + +In Umbraco 13 this configuration option will be removed and the semantic rendering made the only option. + +### DisableClientSideValidationDependencyCheck + +When a form is rendered on the front-end website, a check is run to ensure that client-side validation framework is available and registered. + +You can disable this check by setting the value of this configuration key to `true`. + +If you are rendering your forms dependency scripts using the `async` attribute, you will need to disable this check. + +### DisableRelationTracking + +Forms will by default track relations between forms and the content pages they are used on. This allows editors to see where forms are being used in their Umbraco website. + +If you would like to enable this feature, you can set the value of this setting to `true`. + +## TrackRenderedFormsStorageMethod + +Forms tracks the forms rendered on a page in order that the associated scripts can be placed in a different location within the HTML. Usually this is used to [render the scripts](../rendering-scripts.md) at the bottom of the page. + +By default, `HttpContext.Items` is used as the storage mechanism for this tracking. + +You can optionally revert to the legacy behavior of using `TempData` by changing this setting from the default of `HttpContextItems` to `TempData`. + +## EnableMultiPageFormSettings + +This setting determines whether [multi-page form settings](../../editor/creating-a-form/form-settings.md#multi-page-forms) are available to editors. + +By default the value is `true`. To disable the feature, set the value to `false`. + +## EnableAdvancedValidationRules + +This setting determines whether [advanced form validation rules](../../editor/creating-a-form/form-advanced.md) are available to editors. + +By default, the value is `false`. This is partly because the feature is only considered for "power users", comfortable with crafting rules using the required JSON syntax. And partly as validating the rules on the client requires an additional front-end dependency. + +To make the feature available to editors and include the dependency when using `@Html.RenderUmbracoFormDependencies(Url)`, set the value to `true`. + + +## Security configuration + +### DisallowedFileUploadExtensions + +When using the File Upload field in a form, editors can choose which file extensions they want to accept. When an image is expected, they can for example specify that only `.jpg` or `.png` files are uploaded. + +There are certain file extensions that in almost all cases should never be allowed, which are held in this configuration value. This means that even if an editor has selected to allow all files, any files that match the extensions listed here will be blocked. + +By default, .NET related code files like `.config` and `.aspx` are included in this deny list. You can add or - if you are sure - remove values from this list to meet your needs. + +### AllowedFileUploadExtensions + +For further control, an "allow list" of extension can be provided via this setting. If provided, only the extensions entered as a comma separated list here will be accepted in file uploads through forms. + +### EnableAntiForgeryToken + +This setting needs to be a `true` or `false` value and will enable the ASP.NET Anti Forgery Token and we recommend that you enable this option. Defaults to `true`. + +In certain circumstances, including hosting pages with forms in IFRAMEs from other websites, this may need to be set to `false`. + +### SavePlainTextPasswords + +This setting needs to be a `true` or `false` value and controls whether password fields provided in forms will be saved to the database. Defaults to `false`. + +### DisableFileUploadAccessProtection + +Protection was added to uploaded files to prevent users from accessing them if they aren't logged into the backoffice and have permission to manage the form for which the file was submitted. As a policy of being "secure by default", the out of the box behavior is that this access protection is in place. + +If for any reason you need to revert to the previous behavior, or have other reasons where you want to permit unauthenticated users from accessing the files, you can turn off this protection by setting this configuration value to `true`. + +### DefaultUserAccessToNewForms + +This setting was added to add control over access to new forms. The default behavior is for all users to be granted access to newly created forms. To amend that to deny access, the setting can be updated to a value of `Deny`. A value of `Grant` or configuration with the setting absent preserves the default behavior. + +### ManageSecurityWithUserGroups + +Ability to administer access to Umbraco Forms using Umbraco's user groups. This can be used instead or in addition to the legacy administration which is at the level of the individual user. Set this option to `true` to enable the user group permission management functionality. + +### GrantAccessToNewFormsForUserGroups + +This setting takes a comma-separated list of user group aliases which will be granted access automatically to newly created forms. This setting only takes effect when `ManageSecurityWithUserGroups` is set to `true`. + +There are two "special" values that can be applied within or instead of the comma-separated list. + +A value of `all` will give access to the form to all user groups. + +A value of `form-creator` will give access to all the user groups that the user who created the form is part of. + +### FormsApiKey and EnableAntiForgeryTokenForFormsApi + +Available from Forms 10.2.1, the `FormsApiKey` configuration setting can be used to secure the Forms Headless API in server-to-server integrations. When set, API calls will be rejected unless the value of this setting is provided in an HTTP header. + +Setting the value of `EnableAntiForgeryTokenForFormsApi` to `false` will disable the anti-forgery protection for the Forms Headless/AJAX API. You need to do this for server-to-server integrations where it's not possible to provide a valid anti-forgery token in the request. + +For more information, see the [Headless/AJAX Forms](../ajaxforms.md) article. + +## Field type specific configuration + +### Date picker field type configuration + +#### DatePickerYearRange + +This setting is used to configure the Date Picker form field range of years that is available in the date picker. By default this is a small range of 10 years. + +#### DatePickerFormat + +A custom date format can be provided in [momentjs format](https://momentjscom.readthedocs.io/en/latest/moment/01-parsing/03-string-format/) if you want to override the default. + +#### DatePickerFormatForValidation + +If a custom date format is provided it will be used on the client side. A matching string in [C# date format](https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings) should be provided, so that server-side validation will match the expected format of the entry. + +### reCAPTCHA v2 field type configuration + +#### PublicKey & PrivateKey + +Both of these configuration values are needed in order to use the "_Recaptcha2_" field type implementing legacy ReCaptcha V2 from Google. You can obtain both of these values after signing up to create a ReCaptcha key here - [https://www.google.com/recaptcha/admin](https://www.google.com/recaptcha/admin) + +Google has renamed these recently and the `Site Key` refers to `RecaptchaPublicKey` and `Secret Key` is to be used for `RecaptchaPrivateKey` + +### reCAPTCHA v3 field type configuration + +#### SiteKey & PrivateKey + +Both of these configuration values are needed in order to use the "_reCAPTCHA V3 with Score_" field type implementing ReCaptcha V3 from Google. + +You can obtain both of these values after signing up to create a ReCaptcha key here: [https://www.google.com/recaptcha/admin](https://www.google.com/recaptcha/admin). + +#### Domain + +This setting defines the domain from which the client-side assets for using the reCAPTCHA service are requested. + +Valid options are `Google` (the default) or `Recaptcha`. You may want to use the latter for control of which domains are setting cookies on your site. [Read more at the reCAPTCHA documentation](https://developers.google.com/recaptcha/docs/faq#does-recaptcha-use-cookies). + +#### VerificationUrl + +By default, the server-side validation of the reCAPTCHA response is sent to Google's servers at `https://www.google.com/recaptcha/api/siteverify`. + +Some customers with a locked-down production environment cannot configure the firewall to allow these requests and instead use a proxy server. They can use this setting to configure the URL to their proxy server, which will relay the request to and response from Google. + +#### ShowFieldValidation + +The validation message returned from a failed reCAPTCHA 3 request will be displayed in the form level validation summary and alongside the field. + +To remove rendering at the field level, set this value to `false`. + +### Rich text field type configuration + +#### DataTypeId + +Sets the Data Type Guid to use to obtain the configuration for the rich text field type. If the setting is absent, the value of the default rich text Data Type created by Umbraco on a new install is used. + +### Title and description field type configuration + +#### AllowUnsafeHtmlRendering + +When using the "title and description" field type, if editors provide HTML in the "description" field it will be encoded when rendering on the website. + +If you understand the risks and want to allow HTML to be displayed, you can set this value to `false`. diff --git a/16/umbraco-forms/developer/configuration/type-details.md b/16/umbraco-forms/developer/configuration/type-details.md new file mode 100644 index 00000000000..e8c869dfa58 --- /dev/null +++ b/16/umbraco-forms/developer/configuration/type-details.md @@ -0,0 +1,526 @@ +--- +description: "Provides details of the built-in provider types available with Umbraco Forms" +--- + +# Forms Provider Type Details + +This page provides some details of the provider types available in Umbraco Forms. + +The intention is to be able to make available details such as IDs, aliases and property names, that may be necessary when configuring the product. + +## Field Types + +
+ +Checkbox + +**ID:** `D5C0C390-AE9A-11DE-A69E-666455D89593` + +**Alias:** `checkbox` + +**Settings:** + +* `Caption` +* `DefaultValue` +* `ShowLabel` + +
+ +
+ +Data Consent + +**ID:** `A72C9DF9-3847-47CF-AFB8-B86773FD12CD` + +**Alias:** `dataConsent` + +**Settings:** + +* `AcceptCopy` +* `ShowLabel` + +
+ +
+ +Date + +**ID:** `F8B4C3B8-AF28-11DE-9DD8-EF5956D89593` + +**Alias:** `date` + +**Settings:** + +* `Placeholder` + +
+ +
+ +Dropdown List + +**ID:** `0DD29D42-A6A5-11DE-A2F2-222256D89593` + +**Alias:** `dropdown` + +**Settings:** + +* `DefaultValue` +* `AllowMultipleSelections` +* `ShowLabel` +* `AutocompleteAttribute` +* `SelectPrompt` + +
+ +
+ +File Upload + +**ID:** `84A17CF8-B711-46a6-9840-0E4A072AD000` + +**Alias:** `fileUpload` + +**Settings:** + +* `SelectedFilesListHeading` + +
+ +
+ +Long Answer + +**ID:** `023F09AC-1445-4bcb-B8FA-AB49F33BD046` + +**Alias:** `longAnswer` + +**Settings:** + +* `DefaultValue` +* `Placeholder` +* `ShowLabel` +* `AutocompleteAttribute` +* `NumberOfRows` +* `MaximumLength` + +
+ +
+ +Hidden Field + +**ID:** `DA206CAE-1C52-434E-B21A-4A7C198AF877` + +**Alias:** `hidden` + +**Settings:** + +* `DefaultValue` + +
+ +
+ +Multiple Choice + +**ID:** `FAB43F20-A6BF-11DE-A28F-9B5755D89593` + +**Alias:** `multipleChoice` + +**Settings:** + +* `DisplayLayout` +* `DefaultValue` +* `ShowLabel` + +
+ +
+ +Password + +**ID:** `FB37BC60-D41E-11DE-AEAE-37C155D89593` + +**Alias:** `password` + +**Settings:** + +* `Placeholder` + +
+ +
+ +reCAPTCHA 2 + +**ID:** `B69DEAEB-ED75-4DC9-BFB8-D036BF9D3730` + +**Alias:** `recaptcha2` + +**Settings:** + +* `Theme` +* `Size` +* `ErrorMessage` + +
+ +
+ +reCAPTCHA 3 + +**ID:** `663AA19B-423D-4F38-A1D6-C840C926EF86` + +**Alias:** `recaptcha3` + +**Settings:** + +* `ScoreThreshold` +* `ErrorMessage` +* `SaveScore` + +
+ +
+ +Rich Text + +**ID:** `1F8D45F8-76E6-4550-A0F5-9637B8454619` + +**Alias:** `richText` + +**Settings:** + +* `Html` +* `ShowLabel` + +
+ +
+ +Single Choice + +**ID:** `903DF9B0-A78C-11DE-9FC1-DB7A56D89593` + +**Alias:** `singleChoice` + +**Settings:** + +* `DisplayLayout` +* `DefaultValue` +* `ShowLabel` + +
+ +
+ +Short Answer + +**ID:** `3F92E01B-29E2-4a30-BF33-9DF5580ED52C` + +**Alias:** `shortAnswer` + +**Settings:** + +* `DefaultValue` +* `Placeholder` +* `ShowLabel` +* `MaximumLength` +* `FieldType` +* `AutocompleteAttribute` + +
+ +
+ +Title and Description + +**ID:** `e3fbf6c4-f46c-495e-aff8-4b3c227b4a98` + +**Alias:** `titleAndDescription` + +**Settings:** + +* `CaptionTag` +* `Caption` +* `BodyText` +* `ShowLabel` + +
+ +## Workflow Types + +
+ +Change Record State + +**ID:** `4C40A092-0CB5-481d-96A7-A02D8E7CDB2F` + +**Alias:** `changeRecordState` + +**Settings:** + +* `Words` +* `Action` + +
+ +
+ +Post as XML + +**ID:** `470EEB3A-CB15-4b08-9FC0-A2F091583332` + +**Alias:** `postAsXml` + +**Settings:** + +* `Url` +* `Method` +* `XsltFile` +* `Fields` +* `Username` +* `Password` + +
+ +
+ +Save As Umbraco Content Node + +**ID:** `89FB1E31-9F36-4e08-9D1B-AF1180D340DB` + +**Alias:** `saveAsUmbracoContentNode` + +**Settings:** + +* `Fields` +* `Publish` +* `RootNode` + +
+ +
+ +Save As XML File + +**ID:** `9CC5854D-61A2-48f6-9F4A-8F3BDFAFB521` + +**Alias:** `saveAsAnXmlFile` + +**Settings:** + +* `Path` +* `Extension` +* `XsltFile` + +
+ +
+ +Send Email + +**ID:** `E96BADD7-05BE-4978-B8D9-B3D733DE70A5` + +**Alias:** `sendEmail` + +**Settings:** + +* `Email` +* `CcEmail` +* `BccEmail` +* `SenderEmail` +* `ReplyToEmail` +* `Subject` +* `Message` +* `Attachment` + +
+ +
+ +Send Email With Razor Template + +**ID:** `17c61629-d984-4e86-b43b-a8407b3efea9` + +**Alias:** `sendEmailWithRazorTemplate` + +**Settings:** + +* `Email` +* `CcEmail` +* `BccEmail` +* `SenderEmail` +* `ReplyToEmail` +* `Subject` +* `RazorViewFilePath` +* `Attachment` + +
+ +
+ +Send Email With Extensible Stylesheet Language Transformations (XSLT) Template + +**ID:** `616edfeb-badf-414b-89dc-d8655eb85998` + +**Alias:** `sendEmailWithXsltTemplate` + +**Settings:** + +* `Email` +* `CcEmail` +* `BccEmail` +* `SenderEmail` +* `ReplyToEmail` +* `Subject` +* `XsltFile` + +
+ +
+ +Send Form To URL + +**ID:** `FD02C929-4E7D-4f90-B9FA-13D074A76688` + +**Alias:** `sendFormToUrl` + +**Settings:** + +* `Url` +* `Method` +* `StandardFields` +* `Fields` +* `Username` +* `Password` + +
+ +
+ +Slack + +**ID:** `bc52ab28-d3ff-42ee-af75-a5d49be83040` + +**Alias:** `slack` + +**Settings:** + +* `WebhookUrl` + +
+ +
+ +Slack (Legacy) + +**ID:** `ccbfb0d5-adaa-4729-8b4c-4bb439dc0202` + +**Alias:** `slackLegacy` + +**Settings:** + +* `Token` +* `Channel` +* `Username` +* `AvatarUrl` + +
+ +## Prevalue Source Types + +
+ +Datasource + +**ID:** `cc9f9b2a-a746-11de-9e17-681b56d89593` + +**Alias:** `dataSource` + +
+ +
+ +Get Values From Text File + +**ID:** `35C2053E-CBF7-4793-B27C-6E97B7671A2D` + +**Alias:** `getValuesFromTextFile` + +**Settings:** + +* `TextFile` + +
+ +
+ +SQL Database + +**ID:** `F1F5BD4D-E6AE-44ed-86CB-97661E4660B2` + +**Alias:** `sqlDatabase` + +**Settings:** + +* `Connection` +* `ConnectionString` +* `Table` +* `KeyColumn` +* `ValueColumn` +* `CaptionColumn` + +
+ +
+ +Umbraco Datatype Prevalues + +**ID:** `EA773CAF-FEF2-491B-B5B7-6A3552B1A0E2` + +**Alias:** `umbracoDataTypePreValues` + +**Settings:** + +* `DataTypeId` + +
+ +
+ +Umbraco Documents + +**ID:** `de996870-c45a-11de-8a39-0800200c9a66` + +**Alias:** `umbracoDocuments` + +**Settings:** + +* `RootNode` +* `UseCurrentPage` +* `DocType` +* `ValueField` +* `CaptionField` +* `ListGrandChildren` +* `OrderBy` + +
+ +## Data Source Types + +
+ +SQL Database + +**ID:** `F19506F3-EFEA-4b13-A308-89348F69DF91` + +**Alias:** `sqlDatabase` + +**Settings:** + +* `Connection` +* `Table` + +
diff --git a/16/umbraco-forms/developer/custom-markup.md b/16/umbraco-forms/developer/custom-markup.md new file mode 100644 index 00000000000..65d29f0059a --- /dev/null +++ b/16/umbraco-forms/developer/custom-markup.md @@ -0,0 +1,86 @@ +--- +description: >- + This article teaches you how to customize how your Umbraco Forms are + outputted. +--- + +# Custom Markup + +With Umbraco Forms, it is possible to customize the output markup of a Form, which means you have complete control over what Forms will display. + +{% hint style="warning" %} +We recommend using [Themes](themes.md) to customize your Forms. This will ensure that nothing is overwritten when you upgrade Forms to a newer version. +{% endhint %} + +## Customizing the Default Views + +The razor macro uses some razor views to output the Form: + +* 1 view for each fieldtype +* 1 view for the scripts +* 1 view for the rest of the Form + +You can find the default views in the `~\Views\Partials\Forms\Themes\default` folder. + +To avoid your custom changes to the default views from being overwritten, you need to copy the view you want to customize into your theme folder, e.g. `~\Views\Partials\Forms\Themes\YourTheme`, and edit the file in `YourTheme` folder. + +### Form.cshtml + +This is the main view responsible for rendering the Form markup. + +The view is separated into two parts, one is the actual Form and the other will be shown if the Form is submitted. + +This view can be customized, if you do so it will be customized for all your Forms. + +### Script.cshtml + +This view renders the JavaScript that will take care of the conditional logic, customization won't be needed here. + +### FieldType.\*.cshtml + +The rest of the views start with FieldType, like `FieldType.Textfield.cshtml` and those will output the fields. There is a view for each default fieldtype like _textfield_, _textarea_, _checkbox_, etc) + +Contents of the `FieldType.Textfield.cshtml` view (from the default theme): + +```csharp +@model Umbraco.Forms.Mvc.Models.FieldViewModel +@using Umbraco.Forms.Mvc + +placeholder="@Model.PlaceholderText"}} + @{if(Model.Mandatory || Model.Validate){data-val="true"}} + @{if (Model.Mandatory) { data-val-required="@Model.RequiredErrorMessage"}} + @{if (Model.Validate) { data-val-regex="@Model.InvalidErrorMessage" data-val-regex-pattern="@Html.Raw(Model.Regex)"}} +/> +``` + +Umbraco Forms uses ASP.NET Unobtrusive Validation which is why you see attributes like `data-val` and `data-val-required`. + +This can be customized but it's important to keep the ID of the control to `@Model.Id` since that is used to match the value to the Form field. For fields that are conditionally hidden, without an ID of `@Model.Id` the control won't be shown when the conditions to show the field are met. An ID needs to be added to text controls such as headings and paragraphs. + +The view model for the partial view for a field is `FieldViewModel`. This defines properties that may be useful when creating new themes or custom fields, some of which are shown in the code samples above. Others include: + +* `AdditionalSettings` - a dictionary of the settings keys and values populated for the form field. These can be retrieved in typed form by key using e.g. `Model.GetSettingValue("MaximumLength", 255);`. + +The following are available on the model but only populated for fields that support file upload: + +* `AllowAllUploadExtensions`- a boolean indicating whether all file extensions are permitted for upload. +* `AllowedUploadExtensions`- a collection of strings indicating the file extensions that are permitted for upload. +* `AllowMultipleFileUploads`- a boolean indicating whether selecting multiple files for upload is allowed. + +### Customizing for a Specific Form + +It is also possible to customize the markup for a specific Form. + +You will need to create folder using the ID of the Form: `~\Views\Partials\Forms\{FormId}` (find the id of the Form in the URL when you are viewing the Form in the backoffice.) + +![Form GUID](../../../10/umbraco-forms/developer/images/form-guid.png) + +As an example if your Form ID is 0d3e6b2d-db8a-43e5-8f28-36241d712487 then you can overwrite the Form view by adding the `Form.cshtml` file to the directory. Start by copying the default one and then making your custom changes: `~\Views\Partials\Forms\0d3e6b2d-db8a-43e5-8f28-36241d712487\Form.cshtml`. + +You can also overwrite views for one or more fieldtypes by adding the views to the `Fieldtypes` folder: `~\Views\Partials\Forms\0d3e6b2d-db8a-43e5-8f28-36241d712487\Fieldtypes\Fieldtype.Textfield.cshtml`. diff --git a/16/umbraco-forms/developer/email-templates.md b/16/umbraco-forms/developer/email-templates.md new file mode 100644 index 00000000000..6e175528457 --- /dev/null +++ b/16/umbraco-forms/developer/email-templates.md @@ -0,0 +1,245 @@ +--- +description: "Creating an email template for Umbraco Forms." +--- + +# Email Templates + +We include a Workflow **Send email with template (Razor)** that allows you to pick a Razor view file that can be used to send out a _pretty HTML email_ for Form submissions. + +## Creating an Email Template + +If you wish to have one or more templates to choose from the **Send email with template (Razor)**, you will need to place all email templates into the `~/Views/Partials/Forms/Emails/` folder. + +The Razor view must inherit from FormsHtmlModel: + +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage +``` + +You now have a model that contains your Form fields which can be used in your email HTML markup, along with the UmbracoHelper methods such as `Umbraco.TypedContent` and `Umbraco.TypedMedia` etc. + +Below is an example of an email template from the `~/Views/Partials/Forms/Emails/` folder: + +```csharp +@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage + +@{ + //This is an example email template where you can use Razor Views to send HTML emails + + //You can use Umbraco.TypedContent & Umbraco.TypedMedia etc to use Images & content from your site + //directly in your email templates too + + //Strongly Typed + //@Model.GetValue("aliasFormField") + //@foreach (var color in Model.GetValues("checkboxField")){} + + //Dynamics + //@Model.DynamicFields.aliasFormField + //@foreach(var color in Model.DynamicFields.checkboxField + + //Images need to be absolute - so fetching domain to prefix with images + var siteDomain = Context.Request.Scheme + "://" + Context.Request.Host; + var assetUrl = siteDomain + "/App_plugins/UmbracoForms/Assets/Email-Example"; + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + Logo + +
+ +
+ + + + + +
+

Umbraco Forms

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+ This is an example email template from Umbraco Forms Razor based email templates. You can build forms using any HTML markup you wish. +
+ + CodeGarden16 Attendees + +
+

Form Results

+
+ + @foreach (var field in Model.Fields) + { +

@field.Name

+ + switch (field.FieldType) + { + case "FieldType.FileUpload.cshtml": +

@field.GetValue()

+ break; + + case "FieldType.DatePicker.cshtml": + DateTime dt; + var fieldValue = field.GetValue(); + var dateValid = DateTime.TryParse(fieldValue != null ? fieldValue.ToString() : string.Empty, out dt); + var dateStr = dateValid ? dt.ToString("f") : ""; +

@dateStr

+ break; + + case "FieldType.CheckBoxList.cshtml": +

+ @foreach (var color in field.GetValues()) + { + @color
+ } +

+ break; + default: +

@field.GetValue()

+ break; + } + } + +
+ +
+ + + + + + +
+

Need more help?

+

Find our documentation here

+
+ +
+ + +``` diff --git a/16/umbraco-forms/developer/extending/README.md b/16/umbraco-forms/developer/extending/README.md new file mode 100644 index 00000000000..635b9fd8f8e --- /dev/null +++ b/16/umbraco-forms/developer/extending/README.md @@ -0,0 +1,83 @@ +# Extending + +Umbraco Forms functionality can be extended in different ways. In this section we focus on techniques available to a back-end/C# developer. + +For front-end extensions, specifically via theming, see the [Themes](../themes.md) section. + +## Developing Custom Providers + +Although the Forms package comes with many fields, workflows and other built-in types, you can still create and develop your own if needed. + +### [Provider model](adding-a-type.md) + +Many features of Forms use a provider model, which makes it quicker to add new parts to the application. + +The model uses the notion that everything must have a type to exist. The type defines the capabilities of the item. For instance a Textfield on a form has a FieldType, this particular field type enables it to render an input field and save text strings. The same goes for workflows, which have a workflow type, datasources which have a datasource type and so on. Using the model you can seamlessly add new types and thereby extend the application. + +It is possible to add new Field types, Data Source Types, Prevalue Source Types, Export Types, and Workflow Types. + +### [Field types](adding-a-fieldtype.md) + +A field type handles rendering of the UI for a field in a form. It renders a standard ASP.NET Razor partial view and is able to return a list of values when the form is saved. + +The concept of provider settings, common to the field and other types, is also discussed in this section. + +### Data Source Types + +A data source type enables Umbraco Forms to connect to a custom source of data. A data source consists of any kind of storage if it is possible to return a list of fields Umbraco Forms can map values to. For example: a Database data source can return a list of columns Forms can send data to. This enables Umbraco Forms to map a form to a data source. A data source type is responsible for connecting Forms to external storage. + +### [Prevalue Source Types](adding-a-prevaluesourcetype.md) + +A prevalue source type connects to 3rd party storage to retrieve values. These values are used on fields supporting prevalues. The source fetches the collection of values. + +### [Workflow Types](adding-a-workflowtype.md) + +A workflow can be executed each time a form changes state (when it is submitted for instance). A workflow is responsible for executing logic which can modify the record or notify 3rd party systems. + +### [Export Types](adding-a-exporttype.md) + +Export types are responsible for turning form records into any other data format, which is then returned as a file. + +### [Magic String Format Functions](adding-a-magic-string-format-function.md) + +Custom magic string format functions to add to the [ones shipped with Umbraco Forms](../magic-strings.md#formatting-magic-strings) can be created in code. + +### [Validation Patterns](adding-a-validation-pattern.md) + +When creating a text field in Umbraco Forms, a validation pattern in the form of a regular expression can be applied. Default patterns can be removed or re-ordered, and custom ones created and added. + +## Handling Forms Events + +Another option for extension via custom code is to hook into one of the many events available. + +### [Validation](adding-an-event-handler.md) + +Form events are raised during the submission life cycle and can be handled for executing custom logic. + +### [Default Fields and Workflows](customize-default-workflows.md) + +When a new form is created, the default behavior is to add a single workflow. This workflow will send a copy of the form to the current backoffice user's email address. + +A single "data consent" field will also be added unless it has been disabled via configuration. + +It's possible to amend this behavior and change it to fit your needs. + +## Responding to State Values + +In the course of submitting a form, Umbraco Forms will set values in `TempData` and/or `HttpContext.Items`, that you can use to customize the website functionality. + +### Customizing Post-Submission Behavior + +Whether displaying a message or redirecting, a developer can customize the page viewed after the form is submitted based on the presence of `TempData` variables. + +One variable with a key of `UmbracoFormSubmitted` has a value containing the Guid identifier for the submitted form. + +A second variable contains the Guid identifier of the record created from the form submission. You can find this using the `Forms_Current_Record_id` key. + +In order to redirect to an external URL rather than a selected page on the Umbraco website, you will need to use a [custom workflow](adding-a-workflowtype.md). Within this workflow you can set the required redirect URL on the `HttpContext.Items` dictionary using the key `FormsRedirectAfterFormSubmitUrl` (defined in the constant `Umbraco.Forms.Core.Constants.ItemKeys.RedirectAfterFormSubmitUrl`). + +For example, using an injected instance of `IHttpContextAccessor`: + +``` +_httpContextAccessor.HttpContext.Items[Constants.ItemKeys.RedirectAfterFormSubmitUrl] = "https://www.umbraco.com"; +``` diff --git a/16/umbraco-forms/developer/extending/adding-a-exporttype.md b/16/umbraco-forms/developer/extending/adding-a-exporttype.md new file mode 100644 index 00000000000..22495e7db8b --- /dev/null +++ b/16/umbraco-forms/developer/extending/adding-a-exporttype.md @@ -0,0 +1,243 @@ +# Adding An Export Type To Umbraco Forms + +_This builds on the "_[_adding a type to the provider model_](adding-a-type.md)_" chapter._ + +Add a new class to your project and have it inherit from `Umbraco.Forms.Core.ExportType`. You have two options when implementing the class, as shown in the following examples. + +## Basic Example + +You can implement the method `public override string ExportRecords(RecordExportFilter filter)` in your export provider class. You need to return a string you wish to write to a file. For example, you can generate a `.csv` (comma-separated values) file. You would perform your logic to build up a comma-separated string in the `ExportRecords` method. + +{% hint style="info" %} +In the constructor of your provider, you will need a further two properties, `FileExtension` and `Icon`. +{% endhint %} + +`FileExtension` is the extension such as `zip`, `txt` or `csv` of the file you will be generating and serving from the file system. + +In this example below we will create a single HTML file which takes all the submissions/entries to be displayed as a HTML report. We will do this in conjunction with a Razor partial view to help build up our HTML and thus merge it with the form submission data to generate a string of HTML. + +### Provider Class + +```csharp +using System; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Forms.Core; +using Umbraco.Forms.Core.Models; +using Umbraco.Forms.Core.Searchers; +using Umbraco.Forms.Web.Helpers; + +namespace MyFormsExtensions +{ + public class ExportToHtml : ExportType + { + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IFormRecordSearcher _formRecordSearcher; + + public ExportToHtml( + IHostEnvironment hostEnvironment, + IHttpContextAccessor httpContextAccessor, + IFormRecordSearcher formRecordSearcher) + : base(hostEnvironment) + { + _httpContextAccessor = httpContextAccessor; + _formRecordSearcher = formRecordSearcher; + + Name = "Export as HTML"; + Description = "Export entries as a single HTML report"; + Id = new Guid("4117D352-FB41-4A4C-96F5-F6EF35B384D2"); + FileExtension = "html"; + Icon = "icon-article"; + } + + public override string ExportRecords(RecordExportFilter filter) + { + var view = "~/Views/Partials/Forms/Export/html-report.cshtml"; + EntrySearchResultCollection model = _formRecordSearcher.QueryDataBase(filter); + return ViewHelper.RenderPartialViewToString(_httpContextAccessor.GetRequiredHttpContext(), view, model); + } + } +} +``` + +### Razor Partial View + +```csharp +@model Umbraco.Forms.Core.Searchers.EntrySearchResultCollection + +@{ + var submissions = Model.Results.ToList(); + var schemaItems = Model.Schema.ToList(); +} + +

Form Submissions

+ +@foreach (var submission in submissions) +{ + var values = submission.Fields.ToList(); + + for (int i = 0; i < schemaItems.Count; i++) + { + @schemaItems[i].Name @values[i].Value +
+ } + +
+} +``` + +### Registration + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Forms.Core.Providers.Extensions; +using Umbraco.Forms.TestSite.Business.ExportTypes; + +namespace MyFormsExtensions +{ + public class TestComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.FormsExporters().Add(); + } + } +} +``` + +## Advanced Example + +This approach gives us more flexibility in creating the file we wish to serve as the exported file. We do this for the export to Excel file export provider we ship in Umbraco Forms. With this we can use a library to create the Excel file and store it in a temporary location before we send back the filepath for the browser to stream down the export file. + +In this example we will create a collection of text files, one for each submission which is then zipped up into a single file and served as the export file. + +```csharp +using System; +using System.IO; +using System.IO.Compression; +using System.Linq; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Forms.Core; +using Umbraco.Forms.Core.Models; +using Umbraco.Forms.Core.Searchers; + +namespace MyFormsExtensions +{ + public class ExportToTextFiles : ExportType + { + private readonly IFormRecordSearcher _formRecordSearcher; + + public ExportToTextFiles( + IHostingEnvironment hostingEnvironment, + IFormRecordSearcher formRecordSearcher) + : base(hostingEnvironment) + { + _formRecordSearcher = formRecordSearcher; + + this.Name = "Export as text files"; + this.Description = "Export entries as text files inside a zip file"; + this.Id = new Guid("171CABC9-2207-4575-83D5-2A77E824D5DB"); + this.FileExtension = "zip"; + this.Icon = "icon-zip"; + } + + /// + /// We do not implement this method from the interface + /// As this method is called from ExportToFile that we also override here & is expecting the file contents as a string to be written as a stream to a file + /// Which would be OK if we were creating a CSV or a single based file that can have a simple string written as a string such as one large HTML report or XML file perhaps + /// + public override string ExportRecords(RecordExportFilter filter) => throw new NotImplementedException(); + + /// + /// This gives us greater control of the export process + /// + /// + /// This filter contains the date range & other search parameters to limit the entries we are exporting + /// + /// + /// The filepath that the export file is expecting to be served from + /// So ensure that the zip of text files is saved at this location + /// + /// The final file path to serve up as the export - this is unlikely to change through the export logic + public override string ExportToFile(RecordExportFilter filter, string filepath) + { + // Before Save - Check Path, Directory & Previous File export does not exist + string pathToSaveZipFile = filepath; + + // Check our path does not contain \\ + // If not, use the filePath + if (filepath.Contains('\\') == false) + { + pathToSaveZipFile = HostingEnvironment.MapPathContentRoot(filepath); + } + + // Get the directory (strip out \\ if it exists) + var dir = filepath.Substring(0, filepath.LastIndexOf('\\')); + var tempFileDir = Path.Combine(dir, "text-files"); + + + // If the path does not end with our file extension, ensure it's added + if (pathToSaveZipFile.EndsWith("." + FileExtension) == false) + { + pathToSaveZipFile += "." + FileExtension; + } + + // Check that the directory where we will save the ZIP file temporarily exists + // If not just create it + if (Directory.Exists(tempFileDir) == false) + { + Directory.CreateDirectory(tempFileDir); + } + + // Check if the zip file exists already - if so delete it, as we have a new update + if (File.Exists(pathToSaveZipFile)) + { + File.Delete(pathToSaveZipFile); + } + + // Query the DB for submissions to export based on the filter + EntrySearchResultCollection submissions = _formRecordSearcher.QueryDataBase(filter); + + // Get the schema objects to a list so we can get items using position index + var schemaItems = submissions.schema.ToList(); + + // We will use this to store our contents of our file to save as a text file + var fileContents = string.Empty; + + // For each submission we have build up a string to save to a text file + foreach (EntrySearchResult submission in submissions.Results) + { + // The submitted data for the form submission + var submissionData = submission.Fields.ToList(); + + // For loop to match the schema position to the submission data + for (int i = 0; i < schemaItems.Count; i++) + { + // Concat a string of the name of the field & its stored data + fileContents += schemaItems[i].Name + ": " + submissionData[i] + Environment.NewLine; + } + + // Now save the contents to a text file + // Base it on the format of the record submission unique id + var textFileName = Path.Combine(tempFileDir, submission.UniqueId + ".txt"); + File.WriteAllText(textFileName, fileContents); + + // Reset fileContents to be empty again + fileContents = string.Empty; + } + + // Now we have a temp folder full of text files + // Generate a zip file containing them & save that + ZipFile.CreateFromDirectory(tempFileDir, pathToSaveZipFile); + + // Tidy up after ourselves & delete the temp folder of text files + if (Directory.Exists(tempFileDir)) + { + Directory.Delete(tempFileDir, true); + } + + // Return the path where we saved the zip file containing the text files + return pathToSaveZipFile; + } + } +} +``` diff --git a/16/umbraco-forms/developer/extending/adding-a-fieldtype.md b/16/umbraco-forms/developer/extending/adding-a-fieldtype.md new file mode 100644 index 00000000000..8ab71b312c6 --- /dev/null +++ b/16/umbraco-forms/developer/extending/adding-a-fieldtype.md @@ -0,0 +1,515 @@ +# Adding A Field Type To Umbraco Forms + +_This builds on the "_[_adding a type to the provider model_](adding-a-type.md)_" chapter_ + +In this article, we will illustrate how to add a custom form field type using server-side and client-side components. We will use the example of rendering a "slider" field type that allows the user to select a number within a specific range of values. + +## Server-side Field Type Definition + +Add a new class to the Visual Studio solution. Inherit from `Umbraco.Forms.Core.FieldType` and complete as follows: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Forms.Core.Attributes; +using Umbraco.Forms.Core.Enums; +using Umbraco.Forms.Core.Providers; + +namespace MyProject; + +public class SliderFieldType : Core.FieldType +{ + public SliderFieldType() + { + Id = new Guid("6dff0075-598c-4345-89d7-e0db8684c819"); + Name = "Slider"; + Alias = "slider"; + Description = "Render a UUI Slider field."; + Icon = "icon-autofill"; + DataType = FieldDataType.String; + SortOrder = 10; + + FieldTypeViewName = "FieldType.Slider.cshtml"; + EditView = "My.PropertyEditorUi.InputNumber"; + PreviewView = "My.FieldPreview.Slider"; + } + + [Setting("Minimum", Description = "Minimum value", View = "Umb.PropertyEditorUi.Integer", DisplayOrder = 10)] + public virtual string? Min { get; set; } = "1"; + + [Setting("Maximum", Description = "Maximum value", View = "Umb.PropertyEditorUi.Integer", DisplayOrder = 20)] + public virtual string? Max { get; set; } = "1"; + + [Setting("Step", Description = "Step size", View = "Umb.PropertyEditorUi.Integer", DisplayOrder = 30)] + public virtual string? Step { get; set; } = "1"; + + [Setting("Default Value", Description = "Default value", View = "Umb.PropertyEditorUi.Integer", DisplayOrder = 40)] + public virtual string? DefaultValue { get; set; } = "1"; + + [Setting("Hide step values", Description = "Hides the numbers representing the value of each steps. Dots will still be visible", View = "Umb.PropertyEditorUi.Toggle", DisplayOrder = 50)] + public virtual string? HideStepValues { get; set; } + + [Setting("Background color", Description = "Background color for the input field", View = "My.PropertyEditorUi.InputColor", DisplayOrder = 60)] + public virtual string? BgColor { get; set; } = "1"; +} +``` + +In the constructor or via overridden properties, we can specify details of the field type: + +* `Id` - should be set to a unique GUID. +* `Alias` - an internal alias for the field, used for localized translation keys. +* `Name` - the name of the field presented in the backoffice. +* `Description` - the description of the field presented in the backoffice. +* `Icon` - the icon of the field presented in the backoffice form builder user interface. +* `DataType` - specifies the type of data stored by the field. Options are `String`, `LongString`, `Integer`, `DataTime` or `Bit` (boolean). +* `SupportsMandatory` - indicates whether mandatory validation can be used with the field (defaults to `true`). +* `MandatoryByDefault` - indicates whether the field will be mandatory by default when added to a form (defaults to `false`). +* `SupportsRegex` - indicates whether pattern-based validation using regular expressions can be used with the field (defaults to `false`). +* `SupportsPreValues` - indicates whether prevalues are supported by the field (defaults to `false`). +* `RenderInputType`- indicates how the field should be rendered within the theme as defined with the `RenderInputType` enum. + * The default is `Single` for a single input field. + * `Multiple` should be used for multiple input fields such as checkbox lists. + * `Custom` is used for fields without visible input fields. +* `FieldTypeViewName` - indicates the name of the partial view used to render the field on the website. +* `EditView` - indicates the name of a property editor UI that is used for editing the field in the backoffice. If nothing is provided, the built-in label will be used and the field won't be editable. +* `PreviewView` - indicates the name of a manifest registered client-side resource that is used for previewing the field in the backoffice. If nothing is provided, the name of the field type will be used as the preview. + +You now need to register this new field as a dependency: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Forms.Core.Providers; + +namespace MyProject; + +public class Startup : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.WithCollectionBuilder() + .Add(); + } +} +``` + +## Partial View + +We will start building the view for the default theme of the Form at `Views\Partials\Forms\Themes\default\FieldTypes\FieldType.Slider.cshtml`. + +The file name for the partial view should match the value set on the `FieldTypeViewName` property. + +```csharp +@using Umbraco.Forms.Web +@model Umbraco.Forms.Web.Models.FieldViewModel +@{ + var min = Model.GetSettingValue("Min", 1); + var max = Model.GetSettingValue("Max", 10); + var step = Model.GetSettingValue("Step", 1); + var bgColor = Model.GetSettingValue("BgColor", "#fff"); +} +
This is a custom "slider" field type. We'll just use an input to mock this up.
+ +``` + +This will be rendered when the default theme is used. + +If working with Umbraco 9 or earlier versions, you'll find the `Views\Partials\Forms\Themes\default\` folder on disk and can create the files there. + +For Umbraco 10 and above, we've moved to [distributing the theme as part of a Razor Class Library](../../upgrading/version-specific/#views-and-client-side-files) so the folder won't exist. However, you can create it for your custom field type. If you would like to reference the partial views of the default theme, you can download them as mentioned in the [Themes](../themes.md) article. + +### Read-only partial view + +When rendering a multi-page form, editors have the option to display a summary page where the entries can be viewed before submitting. + +To support this, a read-only view of the field is necessary. + +For most fields, nothing is required here, as the default read-only display defined in the built-in `ReadOnly.cshtml` file suffices. + +However, if you want to provide a custom read-only display for your field, you can do so by creating a second partial view. This should be named with a `.ReadOnly` suffix. For this example, you would create `FieldType.Slider.ReadOnly.cshtml`. + +## Field Settings + +Field settings will be managed in the backoffice by editors who will create forms using the custom field type. These settings can be added to the C# class as properties with a `Setting` attribute: + +```csharp +[Setting("Minimum", Description = "Minimum value", View = "Umb.PropertyEditorUi.Integer", DisplayOrder = 10)] +public virtual string? Min { get; set; } = "1"; +``` + +The property `Name` names the setting in the backoffice with the `Description` providing the help text. Both of these can be translated, as discussed in the backoffice components section below. + +The `View` property indicates a property editor UI used for editing the setting value. You can use a built-in property editor UI, one from a package, or a custom one registered with your solution. The default value if not provided is `Umb.PropertyEditorUi.TextBox`, which will use the standard Umbraco text box property editor UI. + +`SupportsPlaceholders` is a flag indicating whether the setting can contain ["magic string" placeholders](../magic-strings.md) and controls whether they are parsed on rendering. + +`HtmlEncodeReplacedPlaceholderValues` takes effect only if `SupportsPlaceholders` is `true`. It controls whether the replaced placeholder values should be HTML encoded (as is necessary for rendering within content from a rich text editor). + +`SupportsHtml` is a flag indicating whether the setting can contain HTML content. When set to `true` it will be treated as HTML content when the value is read from the Forms delivery API. + +`IsMandatory` if set to `true` will provide client-side validation in the backoffice to ensure the value is completed. + +When creating a field or other provider type, you might choose to inherit from an existing class. This could be if one of the types provided with Umbraco Forms almost meets your needs but you want to make some changes. + +All setting properties for the Forms provider types are marked as `virtual`, so you can override them and change the setting values: + +## Umbraco Backoffice Components + +With Forms 14+, aspects of the presentation and functionality of the custom field are handled by client-side components, registered via manifests: + +* The preview, displayed on the form definition editor. +* The property editor UI used for editing the the submitted values via the backoffice. +* The property editor UI used for editing settings. +* A settings converter, that handles configuring the property editor and translating between the editor and persisted values. +* Translations for setting labels and descriptions. + +To create custom backoffice components for Umbraco 14, it's recommended to use a front-end build setup using Vite, TypeScript, and Lit. For more information, see the [Extension with Vite, TypeScript, and Lit](https://app.gitbook.com/s/G1Byxw7XfiZAj8zDMCTD/tutorials/creating-your-first-extension#extension-with-vite-typescript-and-lit) article. + +To display a name and description on a custom field, you need to register a JavaScript file as shown in the [Localization](https://app.gitbook.com/s/7MBVdnTbFiAgWuRsHpNS/customizing/extending-overview/extension-types/localization) article. + +### Field Preview + +The alias of the preview to use is defined on the field type via the `PreviewView` property. + +A preview for our slider, representing the selected setting values could look as follows: + +```javascript +import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api"; +import { + LitElement, + css, + customElement, + html, + property, +} from "@umbraco-cms/backoffice/external/lit"; + +const elementName = "my-field-preview-slider"; + +@customElement(elementName) +export class MyFieldPreviewSliderElement extends UmbElementMixin(LitElement) { + @property() + settings = {}; + + @property({ type: Array }) + prevalues = []; + + getSettingValue(key: string) { + return this.settings[key]; + } + + render() { + return html`
+ +
`; + } + + static styles = css` + div { + padding: var(--uui-size-4); + } + `; +} + +export default MyFieldPreviewSliderElement; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: MyFieldPreviewSliderElement; + } +} +``` + +And it is registered via a manifest: + +```javascript +import MyFieldPreviewSliderElement from './slider-preview.element.js'; + +const sliderPreviewManifest = { + type: "formsFieldPreview", + alias: "My.FieldPreview.Slider", + name: "Forms UUI Slider Field Preview", + api: MyFieldPreviewSliderElement, + element: () => import('./slider-preview.element.js') + }; + + export const manifests = [sliderPreviewManifest]; +``` + +### Field Editor + +Umbraco Forms supports editing of the entries submitted by website visitors via the backoffice. The property editor interface to use for this is defined in the field type's `EditView` property. + +If not using a built-in property editor, you can create your own. The following example shows how the numerical entries could be edited using an input control. + +```javascript +import { + html, + customElement, +} from "@umbraco-cms/backoffice/external/lit"; +import type { UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/property-editor"; +import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element"; +import { + UmbChangeEvent, +} from "@umbraco-cms/backoffice/event"; +import { UmbFormControlMixin } from "@umbraco-cms/backoffice/validation"; + +const elementName = "my-property-editor-ui-number"; + +@customElement(elementName) +export class MyPropertyEditorUINumberElement + extends UmbFormControlMixin(UmbLitElement, undefined) + implements UmbPropertyEditorUiElement +{ + private onChange(e: Event) { + const newValue = (e.target as HTMLInputElement).value; + if (newValue === this.value) return; + this.value = newValue; + this.dispatchEvent(new UmbChangeEvent()); + } + + override render() { + return html``; + } +} + +export default MyPropertyEditorUINumberElement; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: MyPropertyEditorUINumberElement; + } +} +``` + +Again, it's registered via a manifest. + +```javascript +const numberPropertyEditorManifest = { + type: 'propertyEditorUi', + alias: 'My.PropertyEditorUi.InputNumber', + name: 'Number Input Property Editor UI', + element: () => import('./property-editor-ui-number.element.js'), + meta: { + label: 'Number Input', + icon: 'icon-autofill', + }, +}; +export const manifests = [numberPropertyEditorManifest]; +``` + +### Setting Value Editor + +Field type settings also use a property editor UI for editing the values in the backoffice. The one to use is defined via the `View` property on the `Setting` attribute. + +In our example we use a custom one, allowing the value for the background color to the field to be selected via an input control. + +```javascript +import { + html, + customElement, + type PropertyValueMap, +} from "@umbraco-cms/backoffice/external/lit"; +import type { UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/property-editor"; +import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element"; +import { + UmbChangeEvent, +} from "@umbraco-cms/backoffice/event"; +import { UmbFormControlMixin } from "@umbraco-cms/backoffice/validation"; + +const elementName = "my-property-editor-ui-color"; + +@customElement(elementName) +export class MyPropertyEditorUIColorElement + extends UmbFormControlMixin(UmbLitElement, undefined) + implements UmbPropertyEditorUiElement +{ + protected firstUpdated( + _changedProperties: PropertyValueMap | Map + ): void { + super.firstUpdated(_changedProperties); + this.addFormControlElement(this.shadowRoot!.querySelector("input")!); + } + + private onChange(e: Event) { + const newValue = (e.target as HTMLInputElement).value; + if (newValue === this.value) return; + this.value = newValue; + this.dispatchEvent(new UmbChangeEvent()); + } + + override render() { + return html``; + } +} + +export default MyPropertyEditorUIColorElement; + +declare global { + interface HTMLElementTagNameMap { + [elementName]: MyPropertyEditorUIColorElement; + } +} +``` + +And register it via a manifest: + +```javascript +const colorPropertyEditorManifest = { + type: 'propertyEditorUi', + alias: 'My.PropertyEditorUi.InputColor', + name: 'Color Input Property Editor UI', + element: () => import('./property-editor-ui-color.element.js'), + meta: { + label: 'Color Input', + icon: 'icon-autofill', + }, +}; + +export const manifests = [colorPropertyEditorManifest]; +``` + +### Setting Value Converter + +You may want to consider registering a settings value converter. This is another client-side component that is registered in a manifest. It converts between the setting value required for the editor and the value persisted with the form definition. A converter defines three methods: + +* `getSettingValueForEditor` - converts the persisted string value into one suitable for the editor +* `getSettingValueForPersistence` - converts the editor value into the string needed for persistence +* `getSettingPropertyConfig` - creates the configuration needed for the property editor + +The following code shows the structure for these converter elements. + +```javascript +import type { UmbPropertyValueData } from "@umbraco-cms/backoffice/property"; + +export class SliderSettingValueConverter { + + async getSettingValueForEditor(setting, alias: string, value: string) { + return Promise.resolve(value); + } + + async getSettingValueForPersistence(setting, valueData: UmbPropertyValueData) { + return Promise.resolve(valueData.value); + } + + async getSettingPropertyConfig(setting, alias: string, values: UmbPropertyValueData[]) { + return Promise.resolve([]); + } +} +``` + +It's registered as follows. The `propertyEditorUiAlias` matches with the property editor UI that requires the conversions. + +```javascript +import { SliderSettingValueConverter } from "./slider-setting-value-converter.api"; + +const sliderValueConverterManifest = { + type: "formsSettingValueConverter", + alias: "My.SettingValueConverter.Slider", + name: "Slider Value Converter", + propertyEditorUiAlias: "My.PropertyEditorUi.Slider", + api: SliderSettingValueConverter, +}; + +export const manifests = [sliderValueConverterManifest]; +``` + +### Language Files + +Setting labels and descriptions can be translated via language files. If no client-side localization is provided, the values provided server-side in the `Setting` attribute's `Name` and `Description` properties will be used. + +The following example shows how this is created for the settings on our example field type: + +```javascript +import type { UmbLocalizationDictionary } from "@umbraco-cms/backoffice/localization-api"; + +export default { + formProviderFieldTypes: { + sliderMinLabel: `Minimum`, + sliderMinDescription: `Minimum value`, + sliderMaxLabel: `Maximum`, + sliderMaxDescription: `Maximum value`, + sliderStepLabel: `Step`, + sliderStepDescription: `Step size`, + sliderDefaultValueLabel: `Default Value`, + sliderDefaultValueDescription: `Default value shown when the slider is displayed`, + sliderHideStepValuesLabel: `Hide step values`, + sliderHideStepValuesDescription: `Indicate whether the the field's label should be shown when rendering the form`, + sliderBgColorLabel: `Background color`, + sliderBgColorDescription: `Background color for the field`, + }, +} +``` + +Each different type of extension for Forms uses a different root value: + +* Data sources - `formProviderDataSources` +* Export types - `formProviderExportTypes` +* Field types - `formProviderFieldTypes` +* Prevalue sources - `formProviderPrevalueSources` +* Recordset actions - `formRecordSetActions` +* Workflows - `formProviderWorkflows` + +The language files are registered with: + +```javascript +import type { ManifestLocalization } from '@umbraco-cms/backoffice/localization'; + +const localizationManifests: Array = [ + { + type: "localization", + alias: "My.Localization.En_US", + weight: -100, + name: "English (US)", + meta: { + culture: "en-us", + }, + js: () => import("./en-us.js"), + }, +]; +export const manifests = [...localizationManifests]; +``` + +### Registering the Components + +Finally, you will need an entry point to your client-side components that will register the manifests with Umbraco's extension registry. For example: + +```javascript +import { manifests as propertyEditorManifests } from "./property-editor/manifests.js"; +import { manifests as fieldPreviewManifests } from "./field-preview/manifests.js"; +import { manifests as settingValueConverterManifests } from "./setting-value-converter/manifests.js"; +import { manifests as localizationManifests } from "./lang/manifests.js"; + +const manifests = [ + ...propertyEditorManifests, + ...fieldPreviewManifests, + ...settingValueConverterManifests, + ...localizationManifests +]; + +export const onInit = async (host, extensionRegistry) => { + extensionRegistry.registerMany(manifests); +}; +``` diff --git a/16/umbraco-forms/developer/extending/adding-a-magic-string-format-function.md b/16/umbraco-forms/developer/extending/adding-a-magic-string-format-function.md new file mode 100644 index 00000000000..e7fcd23d89a --- /dev/null +++ b/16/umbraco-forms/developer/extending/adding-a-magic-string-format-function.md @@ -0,0 +1,86 @@ +# Adding a Magic String Format Function + +_This builds on the "_[_adding a type to the provider model_](adding-a-type.md)_" chapter_ + +Umbraco Forms [Magic Strings](../magic-strings.md) can be used to replace placeholders within form elements with values from different sources. Sources include the HTTP request or the Umbraco page where the form is hosted. + +These values can be formatted using [filter functions](../magic-strings.md#formatting-magic-strings). + +Filter functions for common operations such as truncating a string or formatting a date or number are provided. It's also possible to create custom ones in code. + +## Creating a custom format function + +To create a custom format function, create a class that implements `IParsedPlaceholderFormatter`. + +The `FunctionName` property provides the name of the function that will be used within the form's magic string. + +The `FormatValue` property parses the provided value and arguments and returns the formatted value as a string. + +The following example shows the implementation of a function that bounds an integer value. It takes two arguments, a minimum and maximum value. If the value read from the magic string source is numeric, and fits within the two bounds, it is returned. Otherwise, either the minimum or maximum value is returned depending on whether the value is lower or higher than the bounds respectively. + +```csharp +using System.Globalization; +using Umbraco.Forms.Core.Interfaces; + +namespace Umbraco.Forms.Core.Providers.ParsedPlacholderFormatters +{ + public class BoundNumber : IParsedPlaceholderFormatter + { + public string FunctionName => "bound"; + + public string FormatValue(string value, string[] args) + { + if (args.Length != 2) + { + return value; + } + + if (!int.TryParse(args[0], out var min) || !int.TryParse(args[1], out var max)) + { + return value; + } + + if (int.TryParse(value, out int valueAsInteger) || + int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out valueAsInteger)) + { + if (valueAsInteger < min) + { + return min.ToString(); + } + + if (valueAsInteger > max) + { + return max.ToString(); + } + + return valueAsInteger.ToString(); + } + + return value; + } + } +} +``` + +## Registering the custom format function + +As with other provider types, the custom function needs to be registered. An example registration using the `IUmbracoBuilder` is shown below: + +```csharp +public static IUmbracoBuilder AddCustomProviders(this IUmbracoBuilder builder) +{ + builder.FormsParsedPlaceholderFormatters() + .Add(); + return builder; +} +``` + +## Using the custom format function + +The format function can be used within a form's magic string in the same way as the ones provided with Umbraco Forms. + +For the example provided, it would be used like this: + +``` +[#field | bound: 1: 10] +``` diff --git a/16/umbraco-forms/developer/extending/adding-a-prevaluesourcetype.md b/16/umbraco-forms/developer/extending/adding-a-prevaluesourcetype.md new file mode 100644 index 00000000000..e7535c9526d --- /dev/null +++ b/16/umbraco-forms/developer/extending/adding-a-prevaluesourcetype.md @@ -0,0 +1,219 @@ +# Adding A Prevalue Source Type To Umbraco Forms + +_This builds on the "_[_Adding a type to the provider model_](adding-a-type.md)_" article_ + +Add a new class to your project - inherit it from `Umbraco.Forms.Core.FieldPreValueSourceType` and implement the class. + +The following example shows an illustrative custom prevalue source type that returns a hard-coded list of values. It can be extended for your needs via injection of services via the constructor. (See additional example at the bottom.) + +Dynamic settings can be applied and validated as shown in the [Validate type settings with ValidateSettings()](adding-a-type.md#validate-type-settings-with-validatesettings) article. + +```csharp +using System; +using System.Collections.Generic; +using Umbraco.Forms.Core; +using Umbraco.Forms.Core.Models; + +namespace MyFormsExtensions +{ + public class FixedListPrevalueSource : FieldPreValueSourceType + { + public FixedListPrevalueSource() + { + Id = new Guid("42C8158D-2AA8-4621-B653-6A63C7545768"); + Name = "Fixed List"; + Description = "Example prevalue source providing a fixed list of values."; + } + + public override List GetPreValues(Field field, Form form) => + new List + { + new PreValue + { + Id = 1, + Value = "item-one", + Caption = "Item One" + }, + new PreValue + { + Id = 2, + Value = "item-two", + Caption = "Item Two" + } + }; + + /// + public override List ValidateSettings() + { + // this is used to validate any dynamic settings you might apply to the PreValueSource + // if there are no dynamic settings, return an empty list of Exceptions: + var exceptions = new List(); + return exceptions; + } + } +} +``` + +You will then need to register this new prevalue source type as a dependency. + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Forms.Core.Providers; + +namespace MyFormsExtensions +{ + public class Startup : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.WithCollectionBuilder() + .Add(); + } + } +} +``` + +{% hint style="info" %} +The `PreValue` model in Umbraco Forms Versions 8.13.0, 9.5.0, 10.1.0, and above includes a `.Caption` property. This property is set separately from the `.Value` property. In the previous versions, the `Value` is generally used as the caption when rendered on the form. +{% endhint %} + +## Another Example Using Dependency Injection to Access Additional Services + +This example will take a user-provided Content Node and create a custom Prevalue list from the property data on that node. Your own `FieldPreValueSourceType` can get its data from wherever you like - an API call, custom functions, etc. + +```csharp +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Web; +using Umbraco.Forms.Core; +using Umbraco.Forms.Core.Models; +namespace MyFormsExtensions + public class FormPrevaluesSourceNode : FieldPreValueSourceType + { + private readonly ILogger _logger; + private readonly IUmbracoContextFactory _UmbracoContextFactory; + //DEFINE ANY CONFIGURATION SETTING HERE + [Umbraco.Forms.Core.Attributes.Setting(name: "Source Node", + Alias = "SourceNodeId", + Description = "Node holding the Options desired.", + View = "pickers.content")] + public string SourceNodeId { get; set; } + public FormPrevaluesSourceNode( + ILogger logger + , IUmbracoContextFactory umbracoContextFactory + ) + { + _logger = logger; + _UmbracoContextFactory = umbracoContextFactory; + this.Id = new Guid("0E4D4E2B-56E1-4E86-84E4-9A0A6051B57C"); //MAKE THIS UNIQUE! + this.Name = "Content-defined Form Prevalues Source Node"; + this.Description = "Select a node of type 'FormPrevaluesSourceNode'"; + this.Group = "Custom"; + this.Icon = "icon-science"; + } + /// + /// The main method where the PreValues are defined and returned. + /// + /// + /// + /// List of 'Umbraco.Forms.Core.Models.PreValue' + public override List GetPreValues(Field field, Form form) + { + List result = new List(); + try + { + // Access the Configuration Setting and check that is is valid + if (!string.IsNullOrEmpty(SourceNodeId)) + { + var nodeId = 0; + var isValidId = Int32.TryParse(SourceNodeId, out nodeId); + if (isValidId) + { + IPublishedContent iPub; + using (var umbracoContextReference = _UmbracoContextFactory.EnsureUmbracoContext()) + { + iPub = umbracoContextReference.UmbracoContext.Content.GetById(nodeId); + } + if (iPub != null) + { + int sort = 0; + //This is using a ModelsBuilder Model to strongly-type the selected node + var preValSourceNode = new Models.FormPrevaluesSourceNode(iPub, null); + foreach (var prevalue in preValSourceNode.PreValues) + { + PreValue pv = new PreValue(); + pv.Id = $"{iPub.Id}-{sort}"; + pv.Value = prevalue.StoredValue; + pv.Caption = prevalue.DisplayText; //.Caption only available in Forms Versions 8.13.0+, 9.5.0+, & 10.1.0+ + pv.SortOrder = sort; + result.Add(pv); + sort++; + } + } + } + } + } + catch (Exception ex) + { + _logger.LogError($"Unable to get options from FormPrevaluesSourceNode #{SourceNodeId}", ex); + } + return result; + } + /// + /// This is where any checks for Configuration validity are done. + /// The exceptions will be displayed in the back-office UI to the user. + /// + /// List of 'System.Exception' + public override List ValidateSettings() + { + List exceptions = new List(); + if (string.IsNullOrEmpty(SourceNodeId)) + { + exceptions.Add(new Exception("'Source Node' setting not filled out")); + } + else + { + var nodeId = 0; + var isValidId = Int32.TryParse(SourceNodeId, out nodeId); + if (isValidId) + { + IPublishedContent iPub; + using (var umbracoContextReference = _UmbracoContextFactory.EnsureUmbracoContext()) + { + iPub = umbracoContextReference.UmbracoContext.Content.GetById(nodeId); + } + if (iPub != null && iPub.ContentType.Alias != Models.FormPrevaluesSourceNode.ModelTypeAlias) + { + exceptions.Add(new Exception("'Source Node' needs to be of type 'FormPrevaluesSourceNode'")); + } + } + } + return exceptions; + } + } +} +``` + +You will then need to register this new type as a dependency (either in `Program.cs` or in your own IComposer, as shown here). + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Forms.Core.Providers; +namespace MyFormsExtensions +{ + public class FormsComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + //Adding Custom Form PreValueSource + builder.WithCollectionBuilder() + .Add(); + } + } +} +``` diff --git a/16/umbraco-forms/developer/extending/adding-a-type.md b/16/umbraco-forms/developer/extending/adding-a-type.md new file mode 100644 index 00000000000..c1b1784e3dc --- /dev/null +++ b/16/umbraco-forms/developer/extending/adding-a-type.md @@ -0,0 +1,222 @@ +# Adding A Type To The Provider Model + +To add a new type, no matter if it's a workflow, field, data source, etc, there is a number of tasks to perform to connect to the Forms provider model. This chapter walks through each step and describes how each part works. This chapter will reference the creation of a workflow type. It is, however, the same process for all types. + +## Preparations + +Create a new class library project in Visual Studio add references to the `Umbraco.Forms.Core.dll` (available via referencing the [NuGet package](https://www.nuget.org/packages/Umbraco.Forms.Core/)). You might also need to reference [Umbraco.Forms.Core.Providers](https://www.nuget.org/packages/Umbraco.Forms.Core.Providers/). + +## Adding the type to Forms + +The Forms API contains a collection of classes that can be registered at startup or in an Umbraco component. So to add a new type to Forms you inherit from the right class. In the sample below we use the class for the workflow type. + +```csharp +public class LogWorkflow : Umbraco.Forms.Core.WorkflowType +{ + private readonly ILogger _logger; + + public LogWorkflow(ILogger logger) + { + _logger = logger; + } + + public override WorkflowExecutionStatus Execute(WorkflowExecutionContext context) + { + throw new NotImplementedException(); + } + + public override List ValidateSettings() { + throw new NotImplementedException(); + } +} +``` + +When you implement this class you get two methods added. One of them is Execute which performs the execution of the workflow and the other is a method which validates the workflow settings, we will get back to these settings later on. + +Any dependencies required that are registered with the dependency injection container can be provided via the constructor. + +Even though we have the class inheritance in place, we still need to add a bit of default information. + +## Setting up basic type information + +Even though we have the class inheritance in place, we still need to add a bit of default information. This information is added in the class's constructor like this: + +```csharp +public LogWorkflow(ILogger logger) { + + _logger = logger; + + this.Name = "The logging workflow"; + this.Id = new Guid("D6A2C406-CF89-11DE-B075-55B055D89593"); + this.Description = "This will save an entry to the log"; +} +``` + +All three are mandatory and the ID must be unique, otherwise the type might conflict with an existing one. + +## Adding settings to a type + +Now that we have a basic class setup, we would like to pass setting items to the type. So we can reuse the type on multiple items but with different settings. To add a setting to a type, we add a property to the class, and give it a specific attribute like this: + +```csharp +[Umbraco.Forms.Core.Attributes.Setting("Log Header", + Description = "Log item header", + View = "TextField")] +public string LogHeader { get; set; } +``` + +The Umbraco.Forms.Core.Attributes.Setting registers the property in Umbraco Forms and there will automatically be UI and storage generated for it. In the attribute, a name, description and the view to be rendered is defined. + +With the attribute in place, the property value is set every time the class is instantiated by Umbraco Forms. This means you can use the property in your code like this: + +```csharp +[Umbraco.Forms.Core.Attributes.Setting("Document ID", + Description = "Node the log entry belongs to", + View = "Pickers.Content")] +public string Document { get; set; } + +public override WorkflowExecutionStatus Execute(WorkflowExecutionContext context) { + _logger.LogInformation("Record submitted from: {IP}", context.Record.IP); + return WorkflowExecutionStatus.Completed; +} +``` + +For all types that use the provider model, settings work this way. By adding the Setting attribute Forms automatically registers the property in the UI and sets the value when the class is instantiated. + +Each setting value is stored as a string with the user interface for generating the value defined via the `View` property. + +Umbraco Forms ships with [setting types and you can also create your own](./setting-types.md). + +## Validate type settings with ValidateSettings() + +The `ValidateSettings()` method which can be found on all types supporting dynamic settings, is used for making sure the data entered by the user is valid and works with the type. + +```csharp +public override List ValidateSettings() { + List exceptions = new List(); + int docId = 0; + if (!int.TryParse(Document, out docId)) + exceptions.Add(new Exception("Document is not a valid integer")); + return exceptions; +} +``` + +## Registering the class with Umbraco and Forms + +To register the type, ensure your web application project has a reference to the class library, either via a project or NuGet reference. +Then add the following code into the startup pipeline. In this example, the registration is implemented as an extension method to `IUmbracoBuilder` and should be called from `Program.cs`: + +```csharp +public static IUmbracoBuilder AddUmbracoFormsCustomProviders(this IUmbracoBuilder builder) +{ + builder.WithCollectionBuilder() + .Add(); +} +``` + +An alternative approach is to use a composer, as per this example: + +```csharp +public class UmbracoFormsCustomProvidersComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.WithCollectionBuilder() + .Add(); + } +} +``` + +There are further convenience methods you can use for registering custom types. These are found in the namespace `Umbraco.Forms.Core.Providers.Extensions`. + +For example, instead of the following: + +```csharp + builder.WithCollectionBuilder() + .Add(); +``` + +Your workflow can be registered using: + +```csharp + builder.AddFormsWorkflow(): +``` + +Or: + +```csharp + builder.FormsWorkflows().Add(); +``` + +Existing items that are not required in a particular installation can be removed with: + +```csharp + builder.FormsWorkflows().Exclude(); +``` + +Also look in the reference chapter for complete class implementations of workflows, fields and export types. + +## Overriding default providers in Umbraco Forms + +It is possible to override and inherit the original provider, be it a Field Type or Workflow etc. The only requirement when inheriting a fieldtype that you wish to override is to ensure you do not override/change the Id set for the provider, and make sure your class is public. + +Here is an example of overriding the Textarea field aka Long Answer. + +```csharp +public class TextareaWithCount : Umbraco.Forms.Core.Providers.FieldTypes.Textarea +{ + // Added a new setting when we add our field to the form + [Umbraco.Forms.Core.Attributes.Setting("Max length", + Description = "Max length", + View = "TextField")] + public string MaxNumberOfChars { get; set; } + + public TextareaWithCount() + { + // Set a different view for this fieldtype + this.FieldTypeViewName = "FieldType.TextareaWithCount.cshtml"; + + // We can change the default name of 'Long answer' to something that suits us + this.Name = "Long Answer with Limit"; + } + + public override IEnumerable ValidateField(Form form, Field field, IEnumerable postedValues, HttpContext context, IPlaceholderParsingService placeholderParsingService, List errors) + { + var baseValidation = base.ValidateField(form, field, postedValues, context, placeholderParsingService, errors); + var value = postedValues.FirstOrDefault(); + + if (value != null && value.ToString().Length < int.Parse(MaxNumberOfChars)) + { + return baseValidation; + } + + var custom = new List(); + custom.AddRange(baseValidation); + custom.Add("String is way way way too long!"); + + return custom; + } +} +``` + +As discussed in the previous section, you must also register the extended field type within a composer. You also need to create the the backoffice field type view. + +**Composer:** + +```csharp +public class UmbracoFormsCustomProvidersComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.FormsFields().Add(); + } +} +``` + +**Backoffice View:** + +Add a new HTML file as per the name of the field class (e.g. `textareawithcount.html`) to `\wwwroot\App_Plugins\umbracoforms\Backoffice\Common\FieldTypes\` within your project. For this example, we can copy the original `textarea.html` file used by the standard 'Long Answer' field. + +The AngularJS client-side files are shipped with Umbraco Forms as part of a Razor Class Library. So you won't find these files on disk when you install the package. + +However if you do want to reference them you can view and extract them from the [`Umbraco.Forms.StaticAssets` NuGet package](https://nuget.info/packages/Umbraco.Forms.StaticAssets). diff --git a/16/umbraco-forms/developer/extending/adding-a-validation-pattern.md b/16/umbraco-forms/developer/extending/adding-a-validation-pattern.md new file mode 100644 index 00000000000..dc7ace93bb3 --- /dev/null +++ b/16/umbraco-forms/developer/extending/adding-a-validation-pattern.md @@ -0,0 +1,61 @@ +--- +description: >- + Customize the regular expression based validation patterns available for text fields. +--- + +# Adding a Validation Pattern + +When creating a text field in Umbraco Forms, a validation pattern in the form of a regular expression can be applied. Default patterns can be removed or re-ordered, and custom ones created and added. + +## Provided patterns + +Umbraco Forms ships with three patterns: number, email, and URL. The class names are `Number`, `Email`, and `Url` respectively, and all are found in the +`Umbraco.Forms.Core.Providers.ValidationPatterns` namespace. + +## Creating a custom validation pattern + +To create a custom format function, create a class that implements `IValidationPattern`. You will need to initialize five properties: + +- `Alias` - an alias that should be unique across the patterns and is typically camel-cased with no spaces. +- `Name` - the name of the pattern that will be visible in the backoffice. +- `LabelKey` - as an alternative to providing a name, a translation key can be provided. This will be used to look-up the name in the correct language for the backoffice user. +- `Pattern` - the regular expression pattern. +- `ReadOnly` - a flag indicating whether the pattern can be edited in the backoffice. + +The following example shows the implementation of a pattern for a United Kingdom postcode (credit for the [pattern](https://stackoverflow.com/a/69806181/489433) to [Mecanik](https://stackoverflow.com/users/6583298/mecanik) at StackOverflow). + +```csharp +using Umbraco.Forms.Core.Interfaces; +namespace Umbraco.Forms.TestSite.Business.ValidationPatterns +{ + public class UkPostCode : IValidationPattern + { + public string Alias => "ukPostCode"; + public string Name => "UK Post Code"; + public string LabelKey => string.Empty; + public string Pattern => @"^([a-zA-Z]{1,2}[a-zA-Z\d]{1,2})\s(\d[a-zA-Z]{2})$"; + public bool ReadOnly => true; + } +} +``` + +## Registering the validation pattern + +As with other provider types, the validation pattern needs to be registered. There are options to add, remove, and re-order patterns. + +An example registration using the `IUmbracoBuilder` is shown below: + +```csharp +public static IUmbracoBuilder AddCustomProviders(this IUmbracoBuilder builder) +{ + builder.FormsValidationPatterns() + .Append(); + return builder; +} +``` + +## Using the pattern + +With the pattern registered it will be available for selection by editors in the backoffice when they create validation for fields supporting this feature. + +![Validation pattern](../images/validation-pattern.png) \ No newline at end of file diff --git a/16/umbraco-forms/developer/extending/adding-a-workflowtype.md b/16/umbraco-forms/developer/extending/adding-a-workflowtype.md new file mode 100644 index 00000000000..019f24f030d --- /dev/null +++ b/16/umbraco-forms/developer/extending/adding-a-workflowtype.md @@ -0,0 +1,119 @@ +# Adding a workflow type to Umbraco Forms + +*This builds on the "[adding a type to the provider model](adding-a-type.md)" chapter* + +Add a new class to your project and have it inherit from `Umbraco.Forms.Core.WorkflowType`, and implement the class. For this sample, we will focus on the execute method. This method processes the current record (the data submitted by the form) and have the ability to change data and state. + +```csharp +using Serilog; +using System; +using System.Collections.Generic; +using Umbraco.Forms.Core; +using Umbraco.Forms.Core.Data.Storage; +using Umbraco.Forms.Core.Enums; +using Umbraco.Forms.Core.Persistence.Dtos; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Composing; + +namespace MyFormsExtensions +{ + public class TestWorkflow : WorkflowType + { + private readonly ILogger _logger; + + public TestWorkflow(ILogger logger) + { + _logger = logger; + + this.Id = new Guid("ccbeb0d5-adaa-4729-8b4c-4bb439dc0202"); + this.Name = "TestWorkflow"; + this.Description = "This workflow is just for testing"; + this.Icon = "icon-chat-active"; + this.Group = "Services"; + } + + public override Task ExecuteAsync(WorkflowExecutionContext context) + { + // first we log it + _logger.LogDebug("the IP " + context.Record.IP + " has submitted a record"); + + // we can then iterate through the fields + foreach (RecordField rf in context.Record.RecordFields.Values) + { + // and we can then do something with the collection of values on each field + List vals = rf.Values; + + // or get it as a string + rf.ValuesAsString(false); + } + + //Change the state + context.Record.State = FormState.Approved; + + _logger.LogDebug("The record with unique id {RecordId} that was submitted via the Form {FormName} with id {FormId} has been changed to {RecordState} state", + context.Record.UniqueId, context.Form.Name, context.Form.Id, "approved"); + + return Task.FromResult(WorkflowExecutionStatus.Completed); + } + + public override List ValidateSettings() + { + return new List(); + } + } +} +``` + +## Information available to the workflow + +### Record information + +The `ExecuteAsync()` method gets a `WorkflowExecutionContext` which has properties for the related `Form`, `Record`, and `FormState`. This parameter contains all information related to the workflow. + +The `Record` contains all data and metadata submitted by the form. As shown in the example above, you can iterate over all `RecordField` values in the form. You can also retrieve a specific record field by alias using the following method: + +```csharp +RecordField? recordField = context.Record.GetRecordFieldByAlias("myalias"); +``` + +Having obtained a reference to a record field, the submitted value can be retrieved via: + +```csharp +var fieldValue = recordField.ValuesAsString(false); +``` + +The `ValuesAsString` will JSON escape the result by default. If you do not want this escaping to occur, pass `false` as the parameter. + +If the field stores multiple values, they are delimited with a comma. In many cases, you can safely split on that delimiter to obtain the individual values. However, this can lead to issues if the prevalues being selected also contain commas. If that's a concern, the following extension method is available in `Umbraco.Forms.Core.Extensions` to correctly parse the selected prevalues: + +```csharp +IEnumerable selectedPrevalues = recordField.GetSelectedPrevalues(); +``` + +### Form and state information + +The `Form` references the form the record is from and `FormState` provides its state (submitted or approved). + +Other context, such as the current `HttpContext`, if needed can be passed as constructor parameters (for example: the `HttpContext` can be accessed by injecting `IHttpContextAccessor`). + +## Registering the workflow type + +To use the new workflow type, you will need to register it as part of application startup. + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Forms.Core.Providers; + +namespace MyFormsExtensions +{ + public class Startup : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.WithCollectionBuilder() + .Add(); + } + } +} +``` diff --git a/16/umbraco-forms/developer/extending/adding-an-event-handler.md b/16/umbraco-forms/developer/extending/adding-an-event-handler.md new file mode 100644 index 00000000000..0a6736dcdd9 --- /dev/null +++ b/16/umbraco-forms/developer/extending/adding-an-event-handler.md @@ -0,0 +1,181 @@ +--- +description: "See an example of validating a form server-side" +--- + +# Adding A Server-Side Notification Handler To Umbraco Forms + +## Form validation notification + +Add a new class to your project as a handler for the `FormValidateNotification` notification: + +```csharp +using System.Linq; +using Microsoft.AspNetCore.Http; +using Umbraco.Cms.Core.Events; +using Umbraco.Forms.Core.Models; +using Umbraco.Forms.Core.Services.Notifications; + +namespace MyFormsExtensions +{ + /// + /// Catch form submissions before being saved and perform custom validation. + /// + public class FormValidateNotificationHandler : INotificationHandler + { + public void Handle(FormValidateNotification notification) + { + // If needed, be selective about which form submissions you affect. + if (notification.Form.Name == "Form Name") + { + // Check the ModelState + if (notification.ModelState.IsValid == false) + { + return; + } + + // A sample validation + var email = GetPostFieldValue(notification.Form, notification.Context, "email"); + var emailConfirm = GetPostFieldValue(notification.Form, notification.Context, "verifyEmail"); + + // If the validation fails, return a ModelError + if (email.ToLower() != emailConfirm.ToLower()) + { + notification.ModelState.AddModelError(GetPostField(notification.Form, "verifyEmail").Id.ToString(), "Email does not match"); + } + } + } + + private static string GetPostFieldValue(Form form, HttpContext context, string key) + { + Field field = GetPostField(form, key); + if (field == null) + { + return string.Empty; + } + + + return context.Request.HasFormContentType && context.Request.Form.Keys.Contains(field.Id.ToString()) + ? context.Request.Form[field.Id.ToString()].ToString().Trim() + : string.Empty; + } + + private static Field GetPostField(Form form, string key) => form.AllFields.SingleOrDefault(f => f.Alias == key); + } +} +``` + +The handler will check the `ModelState` and `Form` field values provided in the notification. If validation fails, we add a `ModelError`. + +To register the handler, add the following code into the startup pipeline. In this example, the registration is implemented as an extension method to `IUmbracoBuilder` and should be called from `Program.cs`: + +```csharp +public static IUmbracoBuilder AddUmbracoFormsCoreProviders(this IUmbracoBuilder builder) +{ + builder.AddNotificationHandler(); +} +``` + +## Service notifications + +The services available via interfaces `IFormService`, `IFolderService`, `IDataSourceService` and `IPrevalueSourceService` trigger following notifications before or after an entity handled by the service is modified. + +The "-ing" events allow for the entity being changed to be modified before the operation takes place, or to cancel the operation. The "-ed" events fire after the update is complete. + +Both can be wired up using a composer and component: + +```csharp + public class TestSiteComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.AddNotificationHandler(); + } + } + + public class FormSavingNotificationHandler : INotificationHandler + { + public void Handle(FormSavingNotification notification) + { + foreach (Form form in notification.SavedEntities) + { + foreach (Page page in form.Pages) + { + foreach (FieldSet fieldset in page.FieldSets) + { + foreach (FieldsetContainer fieldsetContainer in fieldset.Containers) + { + foreach (Field field in fieldsetContainer.Fields) + { + field.Caption += " (updated)"; + } + } + } + } + } + } + } +``` + +When a form or folder is _moved_ there is no specific service event. However, information available in the `State` dictionary on the notification object can be used to determine whether the item was moved. If so, it can show where it was moved from: + +```csharp + public class TestSiteComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.AddNotificationHandler(); + } + } + + public class FormSavingNotificationHandler : INotificationHandler + { + private readonly ILogger _logger; + + public FormSavingNotificationHandler(ILogger logger) => _logger = logger; + + public void Handle(FormSavingNotification notification) + { + foreach (Form savedEntity in notification.SavedEntities) + { + _logger.LogInformation($"Form updated. New parent: {savedEntity.FolderId}. Old parent: {notification.State["MovedFromFolderId"]}"); + } + } + } +``` + +If a folder is being moved, the key within the `State` dictionary is `"MovedFromParentId"`. + +## Backoffice entry rendering events + +When an entry for a form is rendered in the backoffice, an event is available to allow modification of the record detail. This event is available before the record details are presented to the user. This is shown in the following example: + +```csharp + public class TestSiteComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.AddNotificationHandler(); + } + } + + public class EntrySearchResultFetchingNotificationHandler : INotificationHandler + { + public void Handle(EntrySearchResultFetchingNotification notification) + { + var transformedFields = new List(); + foreach (var field in notification.EntrySearchResult.Fields) + { + if (field?.ToString() == "Test") + { + transformedFields.Add("Test (updated)"); + } + else + { + transformedFields.Add(field); + } + } + + notification.EntrySearchResult.Fields = transformedFields; + } + } +``` diff --git a/16/umbraco-forms/developer/extending/customize-default-workflows.md b/16/umbraco-forms/developer/extending/customize-default-workflows.md new file mode 100644 index 00000000000..cd420da3ca3 --- /dev/null +++ b/16/umbraco-forms/developer/extending/customize-default-workflows.md @@ -0,0 +1,257 @@ +--- +description: "How to amend the built-in behavior of adding fields and associating workflows with new forms" +--- + +# Customize Default Fields and Workflows For a Form + +By default, a single workflow is added when a new form is created. This workflow will send a copy of the form to the email address of the current backoffice user. + +A single "data consent" field will also be added unless it has been disabled via configuration. + +It's possible to amend this behavior and change it to fit your needs. + +## Implementing a Custom Behavior + +Two interfaces are used to abstract the logic for setting default fields and workflows for a form. They are `IApplyDefaultFieldsBehavior` and `IApplyDefaultWorkflowsBehavior` respectively. + +The default behaviors are defined using built-in, internal classes that implement this interface. + +You can create your own implementation of these interfaces. + +### Example - Providing a Custom Apply Workflows Behavior + +An illustrative example, adding a custom workflow that writes to the log, is shown below. + +Firstly, the custom workflow: + +```csharp +using System; +using System.Collections.Generic; +using Umbraco.Core.Composing; +using Umbraco.Core.Logging; +using Umbraco.Forms.Core.Attributes; +using Umbraco.Forms.Core.Enums; +using Umbraco.Forms.Core.Persistence.Dtos; + +namespace MyNamespace +{ + public class LogMessageWorkflow : WorkflowType + { + public const string LogMessageWorkflowId = "7ca500a7-cb34-4a82-8ae9-2acac777382d"; + private readonly ILogger _logger; + + public LogMessageWorkflow(ILogger logger) + { + Id = new Guid(LogMessageWorkflowId); + Name = "Test Workflow"; + Description = "A test workflow that writes a log line"; + Icon = "icon-edit"; + + _logger = logger; + } + + [Setting("Message", Description = "The log message to write", View = "TextField")] + public string Message { get; set; } + + public override List ValidateSettings() + { + var exs = new List(); + if (string.IsNullOrEmpty(Message)) + { + exs.Add(new Exception("'Message' setting has not been set")); + } + + return exs; + } + + public override WorkflowExecutionStatus Execute(WorkflowExecutionContext context) + { + _logger.LogInformation($"'{Message}' written at {DateTime.Now}"); + return WorkflowExecutionStatus.Completed; + } + } +} +``` + +Secondly, the custom implementation of `IApplyDefaultWorkflowsBehavior`: + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Forms.Core; +using Umbraco.Forms.Core.Enums; +using Umbraco.Forms.Core.Providers; +using Umbraco.Forms.Web.Behaviors; +using Umbraco.Forms.Web.Models.Backoffice; + +namespace MyNamespace +{ + public class CustomApplyDefaultWorkflowsBehavior : IApplyDefaultWorkflowsBehavior + { + private readonly WorkflowCollection _workflowCollection; + private readonly IHostingEnvironment _hostingEnvironment; + + public CustomApplyDefaultWorkflowsBehavior( + WorkflowCollection workflowCollection, IHostingEnvironment hostingEnvironment) + { + _workflowCollection = workflowCollection; + _hostingEnvironment = hostingEnvironment; + } + + public void ApplyDefaultWorkflows(FormDesign form) + { + // Retrieve the type of the default workflow to add. + WorkflowType testWorkflowType = _workflowCollection[new Guid(LogMessageWorkflow.LogMessageWorkflowId)]; + + // Create a workflow object based on the workflow type. + var defaultWorkflow = new FormWorkflowWithTypeSettings + { + Id = Guid.Empty, + Name = "Log a message", + Active = true, + IncludeSensitiveData = IncludeSensitiveData.False, + SortOrder = 1, + WorkflowTypeId = testWorkflowType.Id, + WorkflowTypeName = testWorkflowType.Name, + WorkflowTypeDescription = testWorkflowType.Description, + WorkflowTypeGroup = testWorkflowType.Group, + WorkflowTypeIcon = testWorkflowType.Icon, + + // Optionally set the default workflow to be mandatory (which means editors won't be able to remove it + // via the back-office user interface). + IsMandatory = true + }; + + // Retrieve the settings from the type. + Dictionary workflowTypeSettings = testWorkflowType.Settings(); + + // Create a collection for the specific settings to be applied to the workflow. + // Populate with the setting details from the type. + var workflowSettings = new List(); + foreach (KeyValuePair setting in workflowTypeSettings) + { + Core.Attributes.Setting settingItem = setting.Value; + + var settingItemToAdd = new SettingWithValue + { + Name = settingItem.Name, + Alias = settingItem.Alias, + Description = settingItem.Description, + Prevalues = settingItem.GetPreValues(), + View = _hostingEnvironment.ToAbsolute(settingItem.GetSettingView()), + Value = string.Empty + }; + + workflowSettings.Add(settingItemToAdd); + } + + // For each setting, provide a value for the workflow instance (in this example, we only have one). + SettingWithValue messageSetting = workflowSettings.SingleOrDefault(x => x.Alias == "Message"); + if (messageSetting != null) + { + messageSetting.Value = "A test log message"; + } + + // Apply the settings to the workflow. + defaultWorkflow.Settings = workflowSettings; + + // Associate the workflow with the appropriate form submission event. + form.FormWorkflows.OnSubmit.Add(defaultWorkflow); + } + } +} +``` + +Finally, to register the custom implementation in place of the default one: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Extensions; +using Umbraco.Forms.Core.Providers; +using Umbraco.Forms.Testsite.Business.Workflows; +using Umbraco.Forms.Web.Behaviors; + +namespace MyNamespace +{ + public class TestSiteComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.WithCollectionBuilder() + .Add(); + + builder.Services.AddUnique(); + } + } +} +``` + +#### Setting a Mandatory Default Workflow + +When adding a default workflow in code, it's possible to make it mandatory, which will prevent editors from removing it from a form. + +You can see this in the example above, where the `IsMandatory` property of the created `FormWorkflowWithTypeSettings` instance is set to `true`. + +### Example - Providing a Custom Apply Fields Behavior + +The following class shows the default implementation provided with Forms. You can copy this and customize it to your needs. + +```csharp +using Microsoft.Extensions.Options; +using Umbraco.Forms.Core.Configuration; +using Umbraco.Forms.Core.Models; +using Umbraco.Forms.Web.Extensions; +using Umbraco.Forms.Web.Models.Backoffice; + +namespace Umbraco.Forms.Web.Behaviors +{ + internal class CustomApplyDefaultFieldsBehavior : IApplyDefaultFieldsBehavior + { + private readonly FormDesignSettings _formDesignSettings; + + public CustomApplyDefaultFieldsBehavior(IOptions formDesignSettings) => + _formDesignSettings = formDesignSettings.Value; + + public virtual void ApplyDefaultFields(FormDesign form) + { + // Add one page as a starting point. + var page = new Page(); + form.Pages.Add(page); + + // Add one empty fieldset to the page to start with. + var fieldset = new FieldSet + { + Id = Guid.NewGuid() + }; + page.FieldSets.Add(fieldset); + + // Add one full-width (12cols) container/row to the fieldset. + var container = new FieldsetContainer + { + Width = 12 + }; + fieldset.Containers.Add(container); + + // As all forms default to having StoreRecordsLocally we need to add the data consent field to the the form + // (unless this feature has been explicitly disabled). + if (_formDesignSettings.DisableAutomaticAdditionOfDataConsentField) + { + return; + } + + container.AddDataConsentField(_formDesignSettings, _fieldCollection); + + // Add any further fields you require. + } + } +} +``` + +Again, you will need to register your custom class, for example, in a composer with: + +```csharp +builder.Services.AddUnique(); +``` diff --git a/16/umbraco-forms/developer/extending/excluding-a-built-in-field.md b/16/umbraco-forms/developer/extending/excluding-a-built-in-field.md new file mode 100644 index 00000000000..9714474a3e0 --- /dev/null +++ b/16/umbraco-forms/developer/extending/excluding-a-built-in-field.md @@ -0,0 +1,28 @@ +# Excluding a Built-in Field + +Umbraco Forms comes with some built-in fields however it is possible to exclude/remove them if necessary. +There might some use cases where you have no use for file upload and don't want editors using them. Or perhaps you want to remove a field to replace it with one with enhanced functionality that you build yourself. + +## Example + +The following class shows how to exclude built-in field types using a custom composer. The `Password`, `Recaptcha2` and `RichText` field types (or "answers") will no longer be available for selection when creating a form in the backoffice. + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Forms.Core.Providers.Extensions; +using Umbraco.Forms.Core.Providers.FieldTypes; + +namespace MyNamespace +{ + public class MyFormFieldsComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder.FormsFields() + .Exclude() + .Exclude() + .Exclude(); + } + } +} +``` diff --git a/16/umbraco-forms/developer/extending/images/text-with-field-picker.png b/16/umbraco-forms/developer/extending/images/text-with-field-picker.png new file mode 100644 index 00000000000..bc822cbc599 Binary files /dev/null and b/16/umbraco-forms/developer/extending/images/text-with-field-picker.png differ diff --git a/16/umbraco-forms/developer/extending/setting-types.md b/16/umbraco-forms/developer/extending/setting-types.md new file mode 100644 index 00000000000..2c816b49142 --- /dev/null +++ b/16/umbraco-forms/developer/extending/setting-types.md @@ -0,0 +1,63 @@ +# Setting Types + +Umbraco Forms field, prevalue source and workflow types are defined in C# and include one or more setting values. + +These settings are completed by the editor when using the type on their form. + +Each setting type can have it's own user interface. So a string can use a text box but a more complicated JSON structure can use a more appropriate user interface. + +From Forms 14, each interface is defined as an Umbraco [property editor UI](https://docs.umbraco.com/umbraco-cms/extending/property-editors/composition/property-editor-ui). + +The user interface used for a particular setting is defined by the `View` property: + +```csharp +[Umbraco.Forms.Core.Attributes.Setting("Message", View = "Umb.PropertyEditorUi.TextBox")] +public string Message { get; set; } +``` + +If not specified, the default `Umb.PropertyEditorUi.TextBox` is used. + +## Built-in setting types + +The following setting types are available and are used for the field, prevalue source and workflow types that ship with the package. + +Some are defined with the Umbraco CMS and some ship with the Forms package. + +| Name | Source | Description | Used in | +|--------------------------------------------------|--------------|-------------------------------------------------------------------|-------------------------------------------------| +| Umb.PropertyEditorUi.ContentPicker.Source | CMS | Uses a content picker with the option for XPath entry | The "Save as Umbraco node" workflow | +| Umb.PropertyEditorUi.Dropdown | CMS | Used for selection from a list of options | | +| Umb.PropertyEditorUi.Integer | CMS | Uses numerical text box for entry | | +| Umb.PropertyEditorUi.MediaEntityPicker | CMS | Uses a media item picker for entry | The "Send email with XSLT template" workflow | +| Umb.PropertyEditorUi.MultipleTextString | CMS | Uses multiple text boxes for entry | Not used in core types | +| Umb.PropertyEditorUi.Slider | CMS | Uses a slider for range input | The "reCAPTCHAv3" field type | +| Umb.PropertyEditorUi.TextArea | CMS | Uses a multiline textbox for entry | | +| Umb.PropertyEditorUi.TextBox | CMS | Uses a single-line textbox for entry | | +| Umb.PropertyEditorUi.TinyMCE | CMS | Uses a rich text editor for input | The "Send email" workflows | +| Umb.PropertyEditorUi.Toggle | CMS | Uses a single checkbox for entry | | +| Umb.PropertyEditorUi.UploadField | CMS | Used for selection of a file | The "Text file" prevalue source | +| Forms.PropertyEditorUi.DataTypePicker | Forms | Uses a datatype picker | The "Umbraco prevalues" prevalue source | +| Forms.PropertyEditorUi.DocumentTypePicker | Forms | Uses a Document Type picker | The "Umbraco nodes" prevalue source | +| Forms.PropertyEditorUi.DocumentTypeFieldPicker | Forms | Uses to select fields from a Document Type | The "Umbraco nodes" prevalue source | +| Forms.PropertyEditorUi.DocumentMapper | Forms | Used for mapping of fields from a Document Type | The "Save as Umbraco node" workflow | +| Forms.PropertyEditorUi.EmailTemplatePicker | Forms | Used for selection of an email template | The "Send email with Razor template" workflow | +| Forms.PropertyEditorUi.FieldMapper | Forms | Used to map fields from a form to required aliases | The "Send to URL" workflow | +| Forms.PropertyEditorUi.Password | Forms | Uses password text box for entry | | +| Forms.PropertyEditorUi.StandardFieldMapper | Forms | Used to map system fields from a form to required aliases | The "Send to URL" workflow | +| Forms.PropertyEditorUi.TextWithFieldPicker | Forms | Uses a single-line textbox/form field list for entry | Not used in core types | + +Most of the above setting types are used in one or more field, prevalue source and workflow types available with Umbraco Forms. For the less common ones, a usage has been indicated in the table. + +## Additional setting types + +Some types we don't use within the package, but we make available for developers to use when creating their own types. + +For example `Forms.PropertyEditorUi.TextWithFieldPicker`. This offers the option of text field entry or the selection of a field from the form. This can be useful in workflows where you need to reference the value of a specific field. + +![Text with field picker](./images/text-with-field-picker.png) + +## Creating a setting type + +It's also possible to define your own setting type using a combination of server and client-side code. + +Read how do this in the article on [adding a field type](./adding-a-fieldtype.md#field-settings). diff --git a/16/umbraco-forms/developer/field-types.md b/16/umbraco-forms/developer/field-types.md new file mode 100644 index 00000000000..e6f058dd377 --- /dev/null +++ b/16/umbraco-forms/developer/field-types.md @@ -0,0 +1,31 @@ +# Field Types + +Umbraco Forms comes with a number of Field Types to allow you to request certain data in the forms that you design & build. This documentation is to guide specific details about field types that we ship that require some detail in how they work. + +## Date Picker + +The date picker uses a front-end library called [PikaDay.js](https://github.com/dbushell/Pikaday) to display a UI to pick dates from. We have added the support for the Pikaday date picker to be localized based on the page the form is rendered on. This displays the picked date in the correct locale. In JavaScript, we update a hidden field with a standard date format. This is done to send the date to the server, ensuring the record submission is stored in a standard format. This is to avoid locale mixing up dates. + +To achieve this a new Razor partial view is included `/Views/Partials/Forms/DatePicker.cshtml`. Once on a page with a form that includes a Date Picker, it also includes the MomentJS library to assist with date locale formatting. Additionally, there are appropriate changes to Pikaday.js to support the locales. If you wish to use a different DatePicker component this is the file that you would customize to your needs. + +### Date Picker configuration of the year range + +The `DatePicker` has one configuration setting to control the number of year shown. The default is 10 years which makes the picker unusable for picking birth dates. + +Go to your `appsettings.json` and add: +```json + "Umbraco": { + "CMS": { + ... + }, + "Forms": { + "FieldTypes": { + "DatePicker": { + "DatePickerYearRange": 12 + } + } + } + } +``` + +You can then change the `DatePickerYearRange` to a higher number (for example 100). diff --git a/16/umbraco-forms/developer/forms-in-the-database.md b/16/umbraco-forms/developer/forms-in-the-database.md new file mode 100644 index 00000000000..e49ef383ec9 --- /dev/null +++ b/16/umbraco-forms/developer/forms-in-the-database.md @@ -0,0 +1,53 @@ +# Umbraco Forms in the Database + +In Umbraco Forms, it is _only_ possible to store Form data in the database. + +If you are upgrading to Umbraco 9 or later and using Forms, you should first migrate the Forms to the database using Forms 8. As of Umbraco Forms version 8.5.0 it is possible to persist all Forms data in the Umbraco database. This includes definitions for each Form and their fields, as well as workflow definitions and prevalues. + +{% hint style="info" %} +**Custom file system providers** + +If [custom file system providers are used on your project for storing Umbraco Forms data](https://docs.umbraco.com/umbraco-cms/extending/filesystemproviders#custom-providers), the migration will not be able to run. + +To persist your Umbraco Forms data in the database, you will need to revert to a **standard Umbraco Forms configuration**. Use the default provider to store the Forms definition files in the default location. + +You need to ensure that your Forms definition files are moved from their previous location. This is a non-default file path, blob storage, or similar to the default location, `App_Data/UmbracoForms`, that Forms will now be using. + +Your configuration is now considered a standard configuration and you can perform the steps required for a normal migration. +{% endhint %} + +## Enable storing Forms definitions in the database + +To persist Umbraco Forms definitions in the database, follow these steps: + +1. Upgrade to at least Umbraco Forms version 8.5.2. +2. Open the configuration file `App_Plugins\UmbracoForms\UmbracoForms.config`. +3. Locate the `StoreUmbracoFormsInDb` key in the `` section, and make sure it has the following value: + + ```xml + + ``` + +4. Save the file. + +If you are working with a Umbraco Cloud project, make sure you follow the migration steps outlined in the [Umbraco Forms on Cloud](https://docs.umbraco.com/umbraco-cloud/deployments/umbraco-forms-on-cloud) article. + +{% hint style="warning" %} +Enabling the persisting of Umbraco Forms in the database is irreversible. Once you've made the change, reverting to the file approach will not be an option. +{% endhint %} + +When you save the file, the site will restart and run a migration step, migrating the files to the Umbraco database. + +## Migrating Forms in files into a site + +You can force Forms to rerun the migration of the file-format Forms if you have a Umbraco 8 site storing Forms in the database. + +First of all, you should ensure that you have enabled the setting that persists Forms in the database, as the migration requires this (`StoreUmbracoFormsInDb`) key. We highly recommend testing this on a local setup before applying it to your live site. + +1. Copy over the Forms, workflows, prevaluesources, and datasource files to the site into `~\App_Data\UmbracoForms\Data`. +2. Go to the database and find the `[umbracoKeyValue]` table. +3. Find the Form's row and check that the value is `1d084819-84ba-4ac7-b152-2c3d167d22bc` (if not you are not currently working with Forms in the database, changing the setting should be enough). +4. Change that value to `{forms-init-complete}`. +5. Restart the site. + +The site will now try to migrate the Forms files into the database. In the umbracoTraceLog, you can follow the progress. It will throw errors if anything goes wrong. Additionally, it will log out "The Umbraco Forms DB table {TableName} already exists" for the 4 Forms tables before starting the migration. diff --git a/16/umbraco-forms/developer/healthchecks/README.md b/16/umbraco-forms/developer/healthchecks/README.md new file mode 100644 index 00000000000..d9b34c2e10b --- /dev/null +++ b/16/umbraco-forms/developer/healthchecks/README.md @@ -0,0 +1,115 @@ +# Health Checks + +In this article, you will find information about Umbraco Forms-related health checks that can be run from the Umbraco backoffice to ensure that your installation is running seamlessly. + +Read the [Health Check](https://docs.umbraco.com/umbraco-cms/extending/health-check) article to learn more about the feature in general. + +## Database Integrity Health Check + +Running this health check will verify whether the database tables for the Umbraco Forms installation are all set up correctly with the proper data integrity checks. + +In this section, you can learn more about the background for adding this check, as well as how to use and understand the results. + +### Background + +A health check was introduced to confirm the Umbraco Forms database tables are all set up with the expected data integrity checks - i.e. primary keys, foreign keys and unique constraints. + +In most cases, you can expect them all to be in place without any developer intervention. For new installs, the database schema is initialized with all the necessary integrity constraints. And for upgrades, any new schema changes are automatically applied. + +There remains the possibility though that not all will be in place for a particular installation. For example, this could happen if a constraint is added in a new version. It can't be added via an automated migration due to existing data integrity issues. + +In particular, prior to version 8.7, there were a number of tables that weren't defined as strictly as they should be in this area. So we've added some primary key, foreign key and unique constraints with this version. If you've been running a version prior to this and are upgrading, these schema updates will be applied automatically _unless_ there is existing data in the tables that prevent them from being added. + +There shouldn't be - but without these constraints in place it's always possible for an application bug to exist that allows for example the creation of duplicate records, or the orphaning of records, that aren't correct. This is the reason for the constraints to exist, and why we want to ensure they are in place. + +### Running The Health Check + +To run the health check: + +1. Navigate to the **Health Check** dashboard in the **Settings** section in the Umbraco backoffice. + +
+2. Click on the **Forms** button and select **Perform checks**. You'll see a result that looks something like this: + +
+ +If you have a full set of green ticks, then you're all good - and no need to read on! + +If you have one or more red crosses though, that means a particular constraint wasn't able to be applied via the automatic schema migrations when you installed a new version of Umbraco Forms, due to existing data issues. + +It isn't essential that they are resolved - the package can and does function correctly without them - but for reasons of ensuring data integrity and performance, it is recommended that they are. + +### Resolving Reported Problems + +When Umbraco Forms installs an upgrade, it will attempt to apply any schema changes. If though, the update isn't essential, and it can't proceed due to existing data integrity issues, the failed update will be logged and then the rest of the migration will continue. + +As well as in the log files, such issues will be visible via the health check and will need to be resolved by applying scripts directly to the database. + +To support this, we provide the following SQL scripts: + +* Apply database integrity schema changes for 8.7.0+ - [8.7.0-apply-keys-and-indexes](apply-keys.md) +* Apply database integrity schema changes for 8.7.0+ (Forms in database tables) - [8.7.0-apply-keys-and-indexes-forms-in-db](forms-in-the-database-apply-keys.md) + +The first of these provides the SQL statements required to apply the schema updates for 8.7.0+ to the common Umbraco Forms tables. The second applies to those tables used for when Forms are stored in the database, and hence only need to be applied if that option is configured. + +{% hint style="info" %} +Before running any scripts or queries, please be sure to have a database backup in place. +{% endhint %} + +To take an example, let's say that via the health check results you can see that the _"Unique constraint on table 'UFForms', column 'Key' is missing."_ + +If you look in the SQL script you'll see that in order to apply this directly to the database, you would need to run the following SQL statement: + +```sql +-- Adds unique constraint to UFForms. +ALTER TABLE dbo.UFForms +ADD CONSTRAINT UK_UFForms_Key UNIQUE NONCLUSTERED +( + [Key] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO +``` + +If you run it though, you'll see the reason why the migration that ran when Umbraco Forms was upgraded couldn't apply the change: + +```sql +The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'dbo.UFForms' and the index name 'UK_UFForms_Key'. The duplicate key value is (...). +``` + +The constraint can't be applied if there are existing duplicate values, so first they need to be found and removed. + +To find duplicate values in the 'Key' field in this table you can run the following SQL statement: + +```sql +SELECT [Key] +FROM UFForms +GROUP BY [Key] +HAVING COUNT(*) > 1 +``` + +Running the statement above will list out the 'Key' fields that are duplicated in the table. + +To see the full details of the duplicate records, you can use this query: + +```sql +SELECT * +FROM UFForms +WHERE [Key] IN (SELECT [Key] + FROM UFForms + GROUP BY [Key] + HAVING COUNT(*) > 1 +) +``` + +From the `Id` field you can identify the Form records that are duplicated and should be removed, and delete the records. To check you have found them all, run one of the above queries again, and confirm you find no records returned. + +Finally you can run the `ALTER TABLE...` statement shown above to apply the constraint, and confirm via the health check that it's now in place. + +By repeating similar steps as required, you'll be able to ensure that all recommended keys, constraints and indexes are in place. + +If for any reason you wish to revert the changes - perhaps when testing these updates in a non-production environment - reversion scripts for all the 8.7 updates are also provided: + +To support this, we provide the following SQL scripts: + +* Revert database integrity schema changes for 8.7.0+ - [8.7.0-apply-keys-and-indexes\_revert](apply-keys.md#revert-application-of-keys-and-indexes) +* Revert database integrity schema changes for 8.7.0+ (Forms in database tables) - [8.7.0-apply-keys-and-indexes-forms-in-db\_revert](forms-in-the-database-apply-keys.md#reverting-the-application-of-keys-and-indexes) diff --git a/16/umbraco-forms/developer/healthchecks/apply-keys.md b/16/umbraco-forms/developer/healthchecks/apply-keys.md new file mode 100644 index 00000000000..2a1213bd225 --- /dev/null +++ b/16/umbraco-forms/developer/healthchecks/apply-keys.md @@ -0,0 +1,231 @@ +# Apply keys and indexes + +```sql +/* + Applies recommended primary keys, foreign keys and indexes to core Umbraco Forms tables. + This replicates for SQL Server the migration AddRecordKeysAndIndexes. + */ + +-- Adds relationship between UFRecords and UFRecordFields. +ALTER TABLE dbo.UFRecordFields +ADD CONSTRAINT + FK_UFRecordFields_UFRecords_Record FOREIGN KEY + ( + Record + ) REFERENCES dbo.UFRecords + ( + Id + ) ON UPDATE NO ACTION + ON DELETE NO ACTION +GO + +-- Adds primary keys to UFRecordData* tables. +ALTER TABLE dbo.UFRecordDataBit +ADD CONSTRAINT + PK_UFRecordDataBit PRIMARY KEY CLUSTERED + ( + Id + ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +ALTER TABLE dbo.UFRecordDataDateTime +ADD CONSTRAINT + PK_UFRecordDataDateTime PRIMARY KEY CLUSTERED + ( + Id + ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +ALTER TABLE dbo.UFRecordDataInteger +ADD CONSTRAINT + PK_UFRecordDataInteger PRIMARY KEY CLUSTERED + ( + Id + ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +ALTER TABLE dbo.UFRecordDataLongString +ADD CONSTRAINT + PK_UFRecordDataLongString PRIMARY KEY CLUSTERED + ( + Id + ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +-- Adds relationship between UFRecordFields and UFREcordData* tables. +ALTER TABLE dbo.UFRecordDataBit +ADD CONSTRAINT + FK_UFRecordDataBit_UFRecordFields_Key FOREIGN KEY + ( + [Key] + ) REFERENCES dbo.UFRecordFields + ( + [Key] + ) ON UPDATE NO ACTION + ON DELETE NO ACTION +GO + +ALTER TABLE dbo.UFRecordDataDateTime +ADD CONSTRAINT + FK_UFRecordDataDateTime_UFRecordFields_Key FOREIGN KEY + ( + [Key] + ) REFERENCES dbo.UFRecordFields + ( + [Key] + ) ON UPDATE NO ACTION + ON DELETE NO ACTION +GO + +ALTER TABLE dbo.UFRecordDataInteger +ADD CONSTRAINT + FK_UFRecordDataInteger_UFRecordFields_Key FOREIGN KEY + ( + [Key] + ) REFERENCES dbo.UFRecordFields + ( + [Key] + ) ON UPDATE NO ACTION + ON DELETE NO ACTION +GO + +ALTER TABLE dbo.UFRecordDataLongString +ADD CONSTRAINT + FK_UFRecordDataLongString_UFRecordFields_Key FOREIGN KEY + ( + [Key] + ) REFERENCES dbo.UFRecordFields + ( + [Key] + ) ON UPDATE NO ACTION + ON DELETE NO ACTION +GO + +-- Adds index on foreign key fields in UFREcordData* tables. +CREATE NONCLUSTERED INDEX IX_UFRecordDataBit_Key ON dbo.UFRecordDataBit +( + [Key] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX IX_UFRecordDataDateTime_Key ON dbo.UFRecordDataDateTime +( + [Key] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX IX_UFRecordDataInteger_Key ON dbo.UFRecordDataInteger +( + [Key] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX IX_UFRecordDataLongString_Key ON dbo.UFRecordDataLongString +( + [Key] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +-- Adds primary key to UFUserSecurity. +ALTER TABLE dbo.UFUserSecurity +ADD CONSTRAINT + PK_UFUserSecurity PRIMARY KEY CLUSTERED + ( + [User] + ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +-- Adds primary key to UFUserFormSecurity. +ALTER TABLE dbo.UFUserFormSecurity +ADD CONSTRAINT + PK_UFUserFormSecurity PRIMARY KEY CLUSTERED + ( + Id + ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +-- Adds unique constraint to UFUserFormSecurity across user/form fields. +ALTER TABLE dbo.UFUserFormSecurity +ADD CONSTRAINT UK_UFUserFormSecurity_User_Form UNIQUE NONCLUSTERED +( + [User] ASC, + [Form] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO +``` + +## Revert application of keys and indexes + +```sql +/* + Reverts application of recommended primary keys, foreign keys and indexes to core Umbraco Forms tables. + This reverts for SQL Server the migration AddRecordKeysAndIndexes and can be used for rolling that back in testing. + */ + +-- Reverts addition of relationship between UFRecords and UFRecordFields. +ALTER TABLE dbo.UFRecordFields +DROP CONSTRAINT IF EXISTS FK_UFRecordFields_UFRecords_Record +GO + +-- Reverts addition of primary keys to UFRecordData* tables. +ALTER TABLE dbo.UFRecordDataBit +DROP CONSTRAINT IF EXISTS PK_UFRecordDataBit +GO + +ALTER TABLE dbo.UFRecordDataDateTime +DROP CONSTRAINT IF EXISTS PK_UFRecordDataDateTime +GO + +ALTER TABLE dbo.UFRecordDataInteger +DROP CONSTRAINT IF EXISTS PK_UFRecordDataInteger +GO + +ALTER TABLE dbo.UFRecordDataLongString +DROP CONSTRAINT IF EXISTS PK_UFRecordDataLongString +GO + +-- Reverts addition of relationship between UFRecordFields and UFREcordData* tables. +ALTER TABLE dbo.UFRecordDataBit +DROP CONSTRAINT IF EXISTS FK_UFRecordDataBit_UFRecordFields_Key +GO + +ALTER TABLE dbo.UFRecordDataDateTime +DROP CONSTRAINT IF EXISTS FK_UFRecordDataDateTime_UFRecordFields_Key +GO + +ALTER TABLE dbo.UFRecordDataInteger +DROP CONSTRAINT IF EXISTS FK_UFRecordDataInteger_UFRecordFields_Key +GO + +ALTER TABLE dbo.UFRecordDataLongString +DROP CONSTRAINT IF EXISTS FK_UFRecordDataLongString_UFRecordFields_Key +GO + +-- Reverts addition of index on foreign key fields in UFREcordData* tables. +DROP INDEX IF EXISTS IX_UFRecordDataBit_Key ON dbo.UFRecordDataBit +GO + +DROP INDEX IF EXISTS IX_UFRecordDataDateTime_Key ON dbo.UFRecordDataDateTime +GO + +DROP INDEX IF EXISTS IX_UFRecordDataInteger_Key ON dbo.UFRecordDataInteger +GO + +DROP INDEX IF EXISTS IX_UFRecordDataLongString_Key ON dbo.UFRecordDataLongString +GO + +-- Reverts addition of primary key to UFUserSecurity +ALTER TABLE dbo.UFUserSecurity +DROP CONSTRAINT IF EXISTS PK_UFUserSecurity +GO + +-- Reverts addition of primary key to UFUserFormSecurity +ALTER TABLE dbo.UFUserFormSecurity +DROP CONSTRAINT IF EXISTS PK_UFUserFormSecurity +GO + +-- Reverts addition of unique constraint to UFUserFormSecurity across user/form fields. +ALTER TABLE dbo.UFUserFormSecurity +DROP CONSTRAINT IF EXISTS UK_UFUserFormSecurity_User_Form +GO +``` diff --git a/16/umbraco-forms/developer/healthchecks/forms-in-the-database-apply-keys.md b/16/umbraco-forms/developer/healthchecks/forms-in-the-database-apply-keys.md new file mode 100644 index 00000000000..814bf15930d --- /dev/null +++ b/16/umbraco-forms/developer/healthchecks/forms-in-the-database-apply-keys.md @@ -0,0 +1,86 @@ +# Apply keys and indexes for forms in the database + +```sql +/* + Applies recommended primary keys, foreign keys and indexes to Umbraco Forms tables relating to "forms in the database" (i.e. + when configuration key StoreUmbracoFormsInDb = true). + This replicates for SQL Server the migration AddFormKeysAndIndexes. + */ + +-- Adds unique constraint to UFForms. +ALTER TABLE dbo.UFForms +ADD CONSTRAINT UK_UFForms_Key UNIQUE NONCLUSTERED +( + [Key] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +-- Adds unique constraint to UFDataSource. +ALTER TABLE dbo.UFDataSource +ADD CONSTRAINT UK_UFDataSource_Key UNIQUE NONCLUSTERED +( + [Key] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +-- Adds unique constraint to UFPrevalueSource. +ALTER TABLE dbo.UFPrevalueSource +ADD CONSTRAINT UK_UFPrevalueSource_Key UNIQUE NONCLUSTERED +( + [Key] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +-- Adds unique constraint to UFWorkflows. +ALTER TABLE dbo.UFWorkflows +ADD CONSTRAINT UK_UFWorkflows_Key UNIQUE NONCLUSTERED +( + [Key] ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO + +-- Adds index on join field in UFWorkflows. +CREATE NONCLUSTERED INDEX IX_UFWorkflows_FormId ON dbo.UFWorkflows +( + FormId ASC +) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +GO +``` + +## Reverting the application of keys and indexes + +```sql +/* + Reverts application of recommended primary keys, foreign keys and indexes to Umbraco Forms tables relating to "forms in the database" (i.e. + when configuration key StoreUmbracoFormsInDb = true). + This reverts for SQL Server the migration AddFormKeysAndIndexes and can be used for rolling that back in testing. + */ + +-- Reverts addition of unique constraint to UFForms. +ALTER TABLE dbo.UFForms +DROP CONSTRAINT IF EXISTS UK_UFForms_Key +GO + +-- Reverts addition of unique constraint to UFPrevalueSource. +ALTER TABLE dbo.UFDataSource +DROP CONSTRAINT IF EXISTS UK_UFDataSource_Key +GO + +-- Reverts addition of unique constraint to UFPrevalueSource. +ALTER TABLE dbo.UFPrevalueSource +DROP CONSTRAINT IF EXISTS UK_UFPrevalueSource_Key +GO + +-- Reverts addition of unique constraint to UFWorkflows. +ALTER TABLE dbo.UFWorkflows +DROP CONSTRAINT IF EXISTS UK_UFWorkflows_Key +GO + +-- Reverts addition of index on foreign key fields in UFWorkflows. +DROP INDEX IF EXISTS IX_UFWorkflows_FormId ON dbo.UFWorkflows +GO + +-- Reverts addition of index on foreign key fields in UFWorkflows. +DROP INDEX IF EXISTS IX_UFWorkflows_FormId ON dbo.UFWorkflows +GO +``` diff --git a/16/umbraco-forms/developer/healthchecks/images/Umb-backoffice.png b/16/umbraco-forms/developer/healthchecks/images/Umb-backoffice.png new file mode 100644 index 00000000000..7c006f92ca1 Binary files /dev/null and b/16/umbraco-forms/developer/healthchecks/images/Umb-backoffice.png differ diff --git a/16/umbraco-forms/developer/healthchecks/images/healthcheck-v14.png b/16/umbraco-forms/developer/healthchecks/images/healthcheck-v14.png new file mode 100644 index 00000000000..eb16cd812d5 Binary files /dev/null and b/16/umbraco-forms/developer/healthchecks/images/healthcheck-v14.png differ diff --git a/16/umbraco-forms/developer/healthchecks/images/healthcheck.png b/16/umbraco-forms/developer/healthchecks/images/healthcheck.png new file mode 100644 index 00000000000..c701f83f778 Binary files /dev/null and b/16/umbraco-forms/developer/healthchecks/images/healthcheck.png differ diff --git a/16/umbraco-forms/developer/images/assign-sensitive-data-to-user.png b/16/umbraco-forms/developer/images/assign-sensitive-data-to-user.png new file mode 100644 index 00000000000..a1cafe90d27 Binary files /dev/null and b/16/umbraco-forms/developer/images/assign-sensitive-data-to-user.png differ diff --git a/16/umbraco-forms/developer/images/content-app.png b/16/umbraco-forms/developer/images/content-app.png new file mode 100644 index 00000000000..2ebbfbbf08a Binary files /dev/null and b/16/umbraco-forms/developer/images/content-app.png differ diff --git a/16/umbraco-forms/developer/images/exclude-scripts-v9.png b/16/umbraco-forms/developer/images/exclude-scripts-v9.png new file mode 100644 index 00000000000..d592b5e73d6 Binary files /dev/null and b/16/umbraco-forms/developer/images/exclude-scripts-v9.png differ diff --git a/16/umbraco-forms/developer/images/exclude-scripts.png b/16/umbraco-forms/developer/images/exclude-scripts.png new file mode 100644 index 00000000000..571bd847008 Binary files /dev/null and b/16/umbraco-forms/developer/images/exclude-scripts.png differ diff --git a/16/umbraco-forms/developer/images/form-guid.png b/16/umbraco-forms/developer/images/form-guid.png new file mode 100644 index 00000000000..71a21c7618c Binary files /dev/null and b/16/umbraco-forms/developer/images/form-guid.png differ diff --git a/16/umbraco-forms/developer/images/mark-field-as-sensitive.png b/16/umbraco-forms/developer/images/mark-field-as-sensitive.png new file mode 100644 index 00000000000..06f2496feab Binary files /dev/null and b/16/umbraco-forms/developer/images/mark-field-as-sensitive.png differ diff --git a/16/umbraco-forms/developer/images/select-a-theme.png b/16/umbraco-forms/developer/images/select-a-theme.png new file mode 100644 index 00000000000..985dd572041 Binary files /dev/null and b/16/umbraco-forms/developer/images/select-a-theme.png differ diff --git a/16/umbraco-forms/developer/images/sensitive-data-field.png b/16/umbraco-forms/developer/images/sensitive-data-field.png new file mode 100644 index 00000000000..82243d3840d Binary files /dev/null and b/16/umbraco-forms/developer/images/sensitive-data-field.png differ diff --git a/16/umbraco-forms/developer/images/swagger-ui.png b/16/umbraco-forms/developer/images/swagger-ui.png new file mode 100644 index 00000000000..51358f36b64 Binary files /dev/null and b/16/umbraco-forms/developer/images/swagger-ui.png differ diff --git a/16/umbraco-forms/developer/images/user-group-permissions.png b/16/umbraco-forms/developer/images/user-group-permissions.png new file mode 100644 index 00000000000..43e7df5cb94 Binary files /dev/null and b/16/umbraco-forms/developer/images/user-group-permissions.png differ diff --git a/16/umbraco-forms/developer/images/user-start-folders-v14.png b/16/umbraco-forms/developer/images/user-start-folders-v14.png new file mode 100644 index 00000000000..d0df3ca2c23 Binary files /dev/null and b/16/umbraco-forms/developer/images/user-start-folders-v14.png differ diff --git a/16/umbraco-forms/developer/images/user-start-folders.png b/16/umbraco-forms/developer/images/user-start-folders.png new file mode 100644 index 00000000000..ff01a21c28c Binary files /dev/null and b/16/umbraco-forms/developer/images/user-start-folders.png differ diff --git a/16/umbraco-forms/developer/images/validation-pattern.png b/16/umbraco-forms/developer/images/validation-pattern.png new file mode 100644 index 00000000000..e90ec8642dc Binary files /dev/null and b/16/umbraco-forms/developer/images/validation-pattern.png differ diff --git a/16/umbraco-forms/developer/images/wehbook-events-v14.png b/16/umbraco-forms/developer/images/wehbook-events-v14.png new file mode 100644 index 00000000000..5d737e3c0c9 Binary files /dev/null and b/16/umbraco-forms/developer/images/wehbook-events-v14.png differ diff --git a/16/umbraco-forms/developer/images/wehbook-events.png b/16/umbraco-forms/developer/images/wehbook-events.png new file mode 100644 index 00000000000..c8ad67f92a3 Binary files /dev/null and b/16/umbraco-forms/developer/images/wehbook-events.png differ diff --git a/16/umbraco-forms/developer/iprevaluetextfilestorage.md b/16/umbraco-forms/developer/iprevaluetextfilestorage.md new file mode 100644 index 00000000000..d25103de140 --- /dev/null +++ b/16/umbraco-forms/developer/iprevaluetextfilestorage.md @@ -0,0 +1,69 @@ +# Storing Prevalue Text Files With IPreValueTextFileStorage + +Umbraco Forms contains a built-in `Get value from textfile` [Prevalue Source Type](extending/adding-a-prevaluesourcetype.md) that stores the uploaded text file into the physical file system (by default in `umbraco\Data\UmbracoForms\PreValueTextFiles`). + +You can replace the default implementation by writing your own `IPreValueTextFileStorage` and registering that using e.g. `builder.Services.AddUnique()` (in `Program.cs` or a composer). + +You can also use/inherit from `PreValueTextFileSystemStorage` to change the underlying `IFileSystem` that's used to store the prevalue text files. + +## Move files to Media file system + +You can use the following composer to move the prevalue text files into the media file system. If the media file system is using Azure Blob Storage, this will remove the files from the local physical file system. + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Forms.Core.Data; + +public class PreValueTextFileSystemStorageComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.Services.AddUnique(factory => new PreValueTextFileSystemStorage( + factory.GetRequiredService().FileSystem, + factory.GetRequiredService(), + "PreValueTextFiles")); +} +``` + +You need to manually move the existing files from `umbraco\Data\UmbracoForms\PreValueTextFiles` to your media storage. The final file path/URL will look like `~/media/PreValueTextFiles/{GUID}/{filename.txt}` and be accessible from the browser. + +## Move files to Azure Blob Storage + +First, install [Umbraco.StorageProviders.AzureBlob](https://github.com/umbraco/Umbraco.StorageProviders) and configure the Forms storage container, for example by adding the following to your `appsettings.json`: + +```json +{ + "Umbraco": { + "Storage": { + "AzureBlob": { + "Forms": { + "ConnectionString": "UseDevelopmentStorage=true", + "ContainerName": "sample-container" + } + } + } + } +} +``` + +Next, add the following composer that adds the Forms storage container and stores the prevalue text files into Azure Blob Storage (in `forms/PreValueTextFiles/{GUID}/{filename.txt}`): + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Infrastructure.Scoping; +using Umbraco.Forms.Core.Data; +using Umbraco.StorageProviders.AzureBlob.IO; + +public class PreValueTextFileSystemStorageComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.AddAzureBlobFileSystem("Forms", options => options.VirtualPath = "~/forms") + .Services.AddUnique(factory => new PreValueTextFileSystemStorage( + factory.GetRequiredService().GetFileSystem("Forms"), + factory.GetRequiredService(), + "PreValueTextFiles")); +} +``` + +You need to manually move the existing files from `umbraco\Data\UmbracoForms\PreValueTextFiles` to your storage container. If you've disabled public access, the stored files are not accessible from the browser. diff --git a/16/umbraco-forms/developer/localization.md b/16/umbraco-forms/developer/localization.md new file mode 100644 index 00000000000..ace9fb09a0c --- /dev/null +++ b/16/umbraco-forms/developer/localization.md @@ -0,0 +1,47 @@ +--- +meta.Title: Localization +--- + +# Localization + +The labels, descriptions, and buttons that make up the backoffice screens for Umbraco Forms can be translated into different languages. + +When an editor chooses a language for their account, Umbraco CMS will render appropriate translations. The translations will contain a file for that language and a key for the label in question. If either of these can't be found, the label will be displayed in English (US). + +## Language Files + +Umbraco Forms ships with translations for the following languages: + + - Czech (`cs-cz.js`) + - Danish (`da-dk.js`) + - Dutch (`nl-nl.js`) + - French (`fr-fr.js`) + - Italian (`it-it.js`) + - Polish (`pl-pl.js`) + - Spanish (`es-es.js`) + - UK English (`en-gb.js`) + - US English (`en.js`) + +If the language you require does not exist, it's possible to create your own by duplicating the default `en.js` file. You can then save it with the appropriate culture code for the language you need and replace the English text with the translated version. + +As of Forms 10, the file no longer exists on disk and is shipped as part of the `Umbraco.Forms.StaticAssets` NuGet package. You can open this package, either locally using [Nuget Package Explorer](https://apps.microsoft.com/store/detail/nuget-package-explorer/9WZDNCRDMDM3?hl=en-gb&gl=gb&rtc=1), or [online](https://www.nuget.org/packages/Umbraco.Forms.StaticAssets/) by clicking the "Open in NuGet Package Explorer" link. You'll find the file at `staticwebassets/en.js`. + +Once translated, the new file should be saved somewhere in the `App_Plugins` folder for example `App_Plugins/UmbracoFormsLocalization/`. The final step is to register the localization file. This can be done by creating a `umbraco-package.json` like so: + +```json +{ + "$schema": "../../umbraco-package-schema.json", + "name": "Umbraco.Forms.Extensions", + "extensions": [ + { + "type": "localization", + "alias": "UmbracoForms.Localize.DeDE", + "name": " German (Germany)", + "meta": { + "culture": "de-de" + }, + "js": "/App_Plugins/UmbracoFormsLocalization/de-de.js" + } + ] +} +``` diff --git a/16/umbraco-forms/developer/magic-strings.md b/16/umbraco-forms/developer/magic-strings.md new file mode 100644 index 00000000000..5e8d9da683f --- /dev/null +++ b/16/umbraco-forms/developer/magic-strings.md @@ -0,0 +1,123 @@ +# Magic Strings + +Umbraco Forms has some magic strings that enable you to render values from various sources, such as session, cookies and Umbraco page fields. + +## Where can I use magic strings? + +Magic strings can be used in form fields as a label, description or default value. As an example they can be used in default values in hidden fields - normally in the form of referral codes from a session, cookie or request item. + +These values can also be used for properties and settings in workflows. This means you can use name and email fields from a form to create a personal 'Thank you' email. + +## Sources of magic string values + +### Request + +`[@SomeRequestItem]` this allows you to display an item from the current `HttpContext.Request` with the key of 'SomeRequestItem'. + +Some examples of variables that are normally available in `HttpContext.Request`: + +* `[@Url]`: Insert the current URL +* `[@Http_Referer]`: The previous visited URL (if available) +* `[@Remote_Addr]`: The IP address of the visitor (stored by default by Umbraco) +* `[@Http_User_Agent]`: The browser of the visitor + +The variables are not case-sensitive. + +You can use it for any available query string variable in the URL as well. If your URL has the query string `?email=foobar@umbraco.com`, you can get the value of the query string into your field by using `[@email]`. + +### Dictionary Items + +For multi-lingual websites, rather than hard-coding labels like form field captions, a dictionary key can be entered as, for example, `#MyKey`. When the form is rendered, the placeholder will be replaced by the value of the dictionary item identified by the key, according to the current language. + +In most cases, the field must contain only the magic string for the replacement to be carried out. This makes sense for translated values, as you will want the whole phrase replaced when, for example, using one for a field's placeholder. + +We also translate dictionary keys found within the rich text field, which will be contained within HTML tags. Here we look for dictionary keys making up the full inner text of a tag. So for example, `

#myKey

` would be translated, but `

Lorem ipsum #myKey dolor sit amet.

` would not. + +### Session & Cookies + +`[%SomeSessionOrCookieItem]` this allows you to display an item from the current `HttpContext.Session` with the key of 'SomeSessionOrCookieItem'. The session key can only contain alphanumeric chars and you cannot use dots for example. `[%Member.Firstname]` cannot be used, but `[%MemberFirstname]` can be used. You would have to fill these session keys yourself. + +If the item cannot be found in the collection of session keys, it will then try to find the item from the `HttpContext.Cookies` collection with the same key. + +### Umbraco Page field + +`[#myUmbracoField]` this allows you to insert a property of that page and is based on the alias of the field. If your page has a property with the alias 'title', you can use `[#title]` in your form. + +Some extra variables are: + +* `[#pageName]`: The nodename of the current page +* `[#pageID]`: The node ID of the current page + +### Recursive Umbraco Page field + +`[$myRecursiveItem]` this allows you to parse the Umbraco Document Type property myRecursiveItem. So if the current page does not contain a value for this then it will request it from the parent up until the root or until it finds a value. + +### Additional data + +When rendering a form, additional data can be provided in the form of a dictionary. As well as being associated with the created record and available within workflows, they can be used for "magic string" replacements. + +They are accessed using this syntax: `[+additionalDataKey]`. + +### Umbraco Form field + +`{myAliasForFormField}` this allows you to display the entered value for that specific field from the form submission. Used in workflows to send an automated email back to the customer based on the email address submitted in the form. The value here needs to be the alias of the field, and not the name of the field. + +Some extra variables are: + +* `{record.id}`: The ID of the current record - this is only accessible on workflows triggered "on approve" or "on reject" rather than "on submit" +* `{record.updated}`: The updated date/time of the current record +* `{record.created}`: The created date/time of the current record +* `{record.umbracopageid}`: The Umbraco Page ID the form was submitted on +* `{record.uniqueid}`: The unique ID of the current record +* `{record.ip}`: The IP address that was used when the form was submitted +* `{record.memberkey}`: The member key that was used when the form was submitted + +### Member properties from a form submission + +`{member.FOO}` with the prefix of member, the same syntax will allow you to retrieve information about the submission if it was submitted by a logged-in member. + +## Formatting magic strings + +Using a magic string such as in the examples above will output the values exactly as read from the source. It's possible to apply a format string to customize the output. + +The syntax follows that of AngularJS filters, i.e. `[ | : : ]`. + +For example, to truncate a string value read from an Umbraco page field with alias `title`, you would use: + +``` +[#title | truncate: 10] +``` + +Umbraco Forms ships with the following filters: + +| Filter | Function | Arguments | Example | +| ------------------------------------------------ | ----------------------- | -------------------- | ---------------------------------------------------- | +| Bound a number | `bound` | min and max bound | `[#field \| bound: 1: 10]` | +| Convert string to lower case | `lower` | | `[#field \| lower]` | +| Convert string to upper case | `upper` | | `[#field \| upper]` | +| Format a number | `number` | format string | `[#field \| number: #0.##%]` | +| Format a number as a currency | `currency` | | `[#field \| currency]` | +| Format a date | `date` | format string | `[#field \| date: dd-MM-yyyy HH:mm]` | +| HTML encode a string | `html` | | `[#field \| html]` | +| Truncate a string | `truncate` | number of characters | `[#field \| truncate: 10]` | + +The format strings used for formatting dates and numbers are the standard or custom .NET [date](https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings) and [numeric](https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings) format strings respectively. + +Further magic string format functions can be [created in code](extending/adding-a-magic-string-format-function.md) for use in forms. + +## How can I parse these values elsewhere in my C# code or Razor Views? + +A service implemented by the `IPlaceholderParsingService` interface is available for use in custom code or views. It's found in the `Umbraco.Forms.Core.Services` namespace. + +In a controller you can inject it via the constructor and it can also be injected into views via: + +```csharp +@using Umbraco.Forms.Core.Services; +@inject IPlaceholderParsingService PlaceholderParsingService +``` + +The interface implements a single method, `ParsePlaceHolders`, that can be used for parsing magic strings. There are a few overloads available for use depending on the context. + +If parameters for the `Record` or `Form` are omitted, magic strings relating to these objects will be removed. + +There is also a public extension method `ParsePlaceHolders()` extending the `string` object in the `Umbraco.Forms.Core.Extensions` namespace, again available with some overloads allowing the provision of a `Form` or `Record` object if available. diff --git a/16/umbraco-forms/developer/prepping-frontend.md b/16/umbraco-forms/developer/prepping-frontend.md new file mode 100644 index 00000000000..61217d57cdb --- /dev/null +++ b/16/umbraco-forms/developer/prepping-frontend.md @@ -0,0 +1,80 @@ +# Preparing your Frontend + +For Umbraco Forms to work correctly, you need to include some client dependencies. + +## Client-Side Validation + +Umbraco Forms ships with client-side form validation features provided by the [ASP.NET Client Validation library](https://github.com/haacked/aspnet-client-validation). + +You can use the following Razor helper to output script tags containing the dependencies. To access this method you will need a reference to `Umbraco.Forms.Web`: + +```csharp +@using Umbraco.Forms.Web + + @Html.RenderUmbracoFormDependencies(Url) + +``` + +Alternatively, you can add the dependencies to the body tag: + +```csharp +@using Umbraco.Forms.Web +... + + + @Html.RenderUmbracoFormDependencies(Url) + +``` + +All dependencies originate from your Umbraco Forms installation, which means that no external references are needed. + +If you want to modify the rendering of the scripts, you can provide a object parameter named `htmlAttributes`. The contents of the object will be written out as HTML attributes on the script tags. + +You can use this to apply `async` or `defer` attributes. For example: + +```csharp +@Html.RenderUmbracoFormDependencies(Url, new { @async = "async" }) +``` + +If using `async`, please make sure to [disable the Forms client-side validation framework check](../developer/configuration/README.md#disableclientsidevalidationdependencycheck). This is necessary as it's not possible to guarantee that the asynchronous script will load in time to be recognized by the check. This can then cause a false positive warning. + +## Validation Using jQuery + +If you want to use jQuery as your validation framework for Umbraco Forms, you can manually add the following client dependencies: + +- `jQuery` (JavaScript library) +- `jQuery validate` (jQuery plugin that provides client-side Form validation) +- `jQuery validate unobtrusive` (Add-on to jQuery Validation that provides unobtrusive validation via data-* attributes) + +You should remove any calls to `@Html.RenderUmbracoFormDependencies(Url)`. + +The easiest way to add the dependencies is to fetch them from a [CDN](https://en.wikipedia.org/wiki/Content_delivery_network). There are various CDN services you can use: + +- For example: [Microsoft CDN](https://docs.microsoft.com/en-us/aspnet/ajax/cdn/overview). +- Other CDN services you might want to look at are https://www.jsdelivr.com/ and https://cdnjs.com/about, which may offer better performance and more reliable service. + +To add the three client dependencies, see the examples below: + +**Example within `head` tags.** + +```html + + + + + +``` + +**Example within `body` tags.** + +When adding the script to the bottom of the page, you will also need to render the scripts. For more information, see [Rendering Forms Scripts](rendering-scripts.md) article. + +```html + + + + + + + +``` diff --git a/16/umbraco-forms/developer/property-editors.md b/16/umbraco-forms/developer/property-editors.md new file mode 100644 index 00000000000..6533d12e5be --- /dev/null +++ b/16/umbraco-forms/developer/property-editors.md @@ -0,0 +1,39 @@ +# Property Editors + +When forms are created, editors will want to add them to pages in Umbraco. To do this they need a Document Type with a property that uses a Data Type based on a Form Picker property editor. + +Umbraco Forms provides three variations of a form picker. + +

Form Pickers

+ +Most commonly used is **Form Picker (single)**. This will allow the editor to select a single form for display on page. + +Rarely but feasibly, you will have a requirement to present multiple forms on a page. Should this be appropriate, you can use **Form Picker (multiple)**. + +{% hint style="info" %} +Internally this is used for presenting the list of "Allowed forms" you can select when setting up a form picker datatype. +{% endhint %} + +Finally you can provide further flexibility for the editor to select not only a form but also the theme and redirect as well. For this you will use the **Form Details Picker**. + +## Configuring the Data Type + +Each property editor allows you to restrict the forms that can be chosen with the Data Type. You do this by setting either or both of the list of "Allowed folders" or "Allowed forms". + +

Form Picker DataType Configuration

+ +The "Form Details Picker" also allows you to select whether a theme or redirect selection is available. + +## Property Value Conversion + +The type of a property based on the Form Picker presented in a Razor class library is as follows: + +| Option | Description | +| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| **Form Picker (single)** | Single GUID representing the form's identifier. | +| **Form Picker (multiple)** | Collection of GUIDs representing the form identifiers. | +| **Form Details Picker** | Instance of the `Umbraco.Forms.Core.PropertyEditors.Models.FormDetails` object, which has properties for the form, theme and redirect. | + +## Content Delivery API Expansion + +Each reference to a form supports expansion via the Umbraco Content Delivery API, as described [here](./ajaxforms.md#working-with-the-cms-content-delivery-api). diff --git a/16/umbraco-forms/developer/rendering-forms.md b/16/umbraco-forms/developer/rendering-forms.md new file mode 100644 index 00000000000..9e5b31ff10f --- /dev/null +++ b/16/umbraco-forms/developer/rendering-forms.md @@ -0,0 +1,84 @@ +--- +description: Learn the different ways of rendering a form on your website when using Umbraco Forms. +--- + +# Rendering Forms + +There are two options available for rendering a form. + +## Rendering Using a View Component + +To display a form in your view, you can make a call to a view component. You can use a forms GUID directly or add a form dynamically by referencing a form selected via a Forms Picker. + +When selecting a theme, it can be added directly as a string or dynamically by referencing a theme picked via a Theme Picker. + +{% tabs %} + +{% tab title="Dynamic" %} + +```csharp +@await Component.InvokeAsync("RenderForm", new { formId = @Model.Form, + theme = @Model.Theme, + includeScripts = false }) +``` + +This example uses a Forms Picker with `form` as alias, and a Theme Picker with `theme` as alias. + +{% endtab %} + +{% tab title="Static" %} + +```csharp +@await Component.InvokeAsync("RenderForm", new { formId = Guid.Parse("
"), + theme = "default", + includeScripts = false }) +``` + +This example hard-codes the GUID of a form and the name of the theme. + +{% endtab %} + +{% endtabs %} + +Six parameters can be provided: + +- `formId` is the GUID of a form. +- `theme` is the name of a theme. If not provided, the default theme is used (see [Themes](./themes.md)). +- `includeScripts` indicates whether scripts should be rendered with the form (see [Rendering Scripts](./rendering-scripts.md). +- `recordId` is an optional existing record GUID, used if editing records via the website is [enabled in configuration](../developer/configuration/README.md#alloweditableformsubmissions) +- `redirectToPageId` is an optional GUID for a content page that, if provided, is redirected to once the form has been submitted. It will be used in preference to post-submission behavior defined on the form itself. +- `additionalData` is an optional dictionary of string values. When provided it will be used as a source for ["magic string" replacements](./magic-strings.md). The data will be associated with the created record and made available for custom logic or update within workflows. + +The following example shows how the `additionalData` parameter is used: + +{% code wrap="true" %} + +```csharp +var additionalData = new Dictionary { { "foo", "bar" }, { "buzz", "baz" } }; +@await Component.InvokeAsync("RenderForm", new { formId = @Model.Form, theme = @Model.Theme, includeScripts = false, additionalData }) +``` + +{% endcode %} + +## Rendering Using a Tag Helper + +If you prefer a tag helper syntax, you can use one that ships with Umbraco Forms. + +Firstly, in your `_ViewImports.cshtml` file, add a reference to the Umbraco Forms tag helpers with: + +```cshtml +@addTagHelper *, Umbraco.Forms.Web +``` + +Then in your view you can use: + +```csharp +@if (Model.Form.HasValue) +{ + var additionalData = new Dictionary { { "foo", "bar" }, { "buzz", "baz" } }; + +} +``` diff --git a/16/umbraco-forms/developer/rendering-scripts.md b/16/umbraco-forms/developer/rendering-scripts.md new file mode 100644 index 00000000000..fc99f1dcfdb --- /dev/null +++ b/16/umbraco-forms/developer/rendering-scripts.md @@ -0,0 +1,74 @@ +# Rendering Forms Scripts + +Forms output some JavaScript which is by default rendered right below the markup. + +In many cases, you might prefer rendering your scripts at the bottom of the page. For example, before the closing `` tag. This generally improves site performance. + +In order to render your scripts where you want, you need to add a snippet to your template. Make sure you add it below your scripts, right before the closing `` tag. + +By default, Forms uses `TempData` for tracking the forms rendered on a page. The stored values are used when rendering the form scripts and associated data. + +The following snippet should be used. + +```csharp +@using Umbraco.Forms.Web.Extensions; + +@if (TempData.Get("UmbracoForms") is Guid[] formIds) +{ + foreach (var formId in formIds) + { + @await Component.InvokeAsync("RenderFormScripts", new { formId, theme = "default" }) + } + + TempData.Remove("UmbracoForms"); +} +``` + +If you have changed the configuration value `TrackRenderedFormsStorageMethod` to use `HttpContext.Items`, the snippet is: + +```csharp +@if (Context.Items.TryGetValue("UmbracoForms", out object? formIdsObject) && formIdsObject is IEnumerable formIds) +{ + foreach (var formId in formIds) + { + @await Component.InvokeAsync("RenderFormScripts", new { formId, theme = "default" }) + } +} +``` + +Read more about this configuration option in the [configuration ](./configuration/README.md#TrackRenderedFormsStorageMethod) article. + +If you prefer to use a tag helper, that's an option too. + +Firstly, in your `_ViewImports.cshtml` file, ensure you have a reference to the Umbraco Forms tag helpers with: + +```cshtml +@addTagHelper *, Umbraco.Forms.Web +``` + +Then instead of reading from `TempData` and invoking the view component directly, you can use: + +```cshtml + +``` + +This will use the appropriate storage method that you have configured. + +## Enabling `ExcludeScripts` + +If you do not want to render the associated scripts with a Form, you need to explicitly say so. You need to make sure `ExcludeScripts` is checked/enabled, whether you are inserting your Form using a macro or adding it directly in your template. + +To enable `ExcludeScripts`: + +* Using the **Insert Form with Theme** macro: + + ![Exclude scripts](../../../10/umbraco-forms/developer/images/exclude-scripts-v9.png) +* While inserting Forms **directly** in your template: + + ```csharp + @await Umbraco.RenderMacroAsync("renderUmbracoForm", new {FormGuid="6c3f053c-1774-43fa-ad95-710a01d9cd12", FormTheme="bootstrap3-horizontal", ExcludeScripts="1"}) + ``` + +{% hint style="info" %} +`ExcludeScripts = "1"` prevents the associated scripts from being rendered. Any other value, an empty value, or if the parameter is excluded, will render the scripts on the Form. +{% endhint %} diff --git a/16/umbraco-forms/developer/security.md b/16/umbraco-forms/developer/security.md new file mode 100644 index 00000000000..0de32d3b399 --- /dev/null +++ b/16/umbraco-forms/developer/security.md @@ -0,0 +1,116 @@ +--- +description: How to secure access to Umbraco Forms data and functionality. +--- + +# Security + +Umbraco Forms has a backoffice security model integrated with Umbraco users. Details are managed in the _Forms_ section of the backoffice, within a tree named _Security_. + +## User-based permissions + +Within the _Forms_ > _Security_ tree, each user with a backoffice account is listed. Clicking on a user allows each functional permission to be set: + +* Manage Forms - user can create and edit form definitions +* View Entries - user can view the submitted entries +* Edit Entries - user can edit the submitted entries +* Delete entries - user can delete the submitted entries +* Manage Workflows - user can create and edit workflow items +* Manage Datasources - user can create and edit datasource definitions +* Manage Prevalue Sources - user can create and edit prevalue source definitions + +For further control, each form is listed and the user can be granted or denied access to each as appropriate. + +As new forms are created, users will automatically be granted access to them, unless the configuration setting `DefaultUserAccessToNewForms` has been set to a value of `Deny`. + +## Start Folders + +When form definitions are configured for storage in the database, it allows for the creation of folders to group forms within. It's also possible to define one or more start folders for a user. This is done in order to limit their access to a subset of the forms available. + +If no start folders are selected, the user will be able to access all forms in the backoffice according to their permissions. + +If a single start folder is selected, that will act as the root of the tree view of forms. The user will have access to all folders and forms below that selected folder. + +If more than one start folder is selected, they will appear underneath the root of the tree view of forms. The user will have access to only those folders and their descendant folders and forms. + +![Start folders](images/user-start-folders-v14.png) + +## User group based permissions + +A new model was introduced allowing for the management of permissions at the level of user groups. Particularly for installations with a large number of users, we expect this to be a more useful setup and require less ongoing administration. + +When user groups are involved in permissions, access to a particular resource or feature is determined by the following: + +* If the user has a specific user permission set, it is used in preference to anything set on the user groups they are a part of. +* If the user doesn't have a specific user permission set, they are granted access if at least one of the user groups they are part of has access. + +To enable the feature, it's necessary to update the `ManageSecurityWithUserGroups` configuration setting to `true`. + +With that in place the _Form Security_ tree divides into three sub-trees: + +* Under _Group Permissions_, each user group is listed and the same settings as described above for individual users can be set here. +* Under _User Permissions_, each user that has a specific user permission record is listed and can be managed. Records for users can be created or deleted via the tree's action menu. + +As new forms are created, user groups with aliases listed in the `GrantAccessToNewFormsForUserGroups` configuration setting will be automatically given access. For example, with a value of `admin, editor`, the built-in Administrators and Editors groups would have access. + +### Start folders for user groups + +Start folders are enabled for User Groups. They work in a similar way as the group based permissions described above: + +* If the user has a specific user permission set, it is used in preference to anything set on the user groups they are a part of. + * This means if the user has no start folders defined and the groups they are part of do, they will have access to the root of the Forms tree and be able to access all folders and Forms. +* If the user doesn't have a specific user permission set, they are granted access to all the unique folders the groups they are part of have access to. + * If they are part of any group that has access to the forms section, permission to manage forms and no start folders defined, they will have access to the root of the Forms tree and be able to access all folders and Forms. + +### Migrating to user group-based permissions + +In introducing the user group based permissions, we've taken care to ensure a migration path. This is available for those existing installations running on older versions of Umbraco Forms. In that situation, we'd recommend the following approach. + +* Upgrade to Umbraco 9.3. +* At this stage nothing will have changed in terms of the permissions model in use. +* Set the `ManageSecurityWithUserGroups` configuration value to `true` and the `GrantAccessToNewFormsForUserGroups` as appropriate for your setup. +* Via the _Users > Form Security_ section, set the required permissions on each user group. +* Again at this point nothing will have changed with regard the effective permissions for each user, as they will currently all have an existing user permission record. +* Via _Users > Form Security > User permissions_, delete the permission records for each user. +* The effective permissions for each user will now be derived from their user groups. +* If you have any exceptions - where a particular user needs a particular combination of permissions that you can't or don't want to provide via the user groups - it's always possible to re-create a user permission record that will take precedence over the group based permissions. + +![User group permissions](../../../10/umbraco-forms/developer/images/user-group-permissions.png) + +## Handling Sensitive Data in Umbraco Forms + +Marking fields and properties as sensitive will hide the data in those fields for backoffice users that are not privy to the data. Built-in features are available to help you secure sensitive information. For more information, see the [Sensitive data](https://docs.umbraco.com/umbraco-cms/reference/security/sensitive-data-on-members) article. + +The following sections covers how to grant or deny access to sensitive data for specific users and how to mark form questions as sensitive. + +### Assigning Users to the Sensitive Data Group + +To allow users to view and handle sensitive data in Umbraco Forms, you must assign them to the _Sensitive Data_ user group: + +1. Navigate to the **Users** section in the Umbraco Backoffice. +2. Select the user you want to grant access to. +3. Click **Choose** in the Groups field under the **Assign access** section. +4. Select **Sensitive Data** from the list of User Groups. +5. Click **Submit**. +6. Click **Save**. + +![Assigning Users to the Sensitive Data Group](images/assign-sensitive-data-to-user.png) + +### Marking Questions in Forms as Sensitive + +Once the users are set up with the appropriate permissions, the next step is to identify which form fields should be marked as sensitive. + +Marking a field as sensitive ensures that only authorized users in the Sensitive Data user group can access data from these fields. + +To mark questions as sensitive, follow these steps: + +1. Navigate to the **Forms** section in the Umbraco Backoffice. +2. Open the form you wish to configure (for example: Contact Form). +3. Click on the cogwheel icon next to the form field you want to secure. +4. Enable the **Sensitive data** setting for the field. + +![Mark Question as Sensitive](images/mark-field-as-sensitive.png) + +5. Click **Submit**. +6. Click **Save**. + +![Sensitive Data on Field](images/sensitive-data-field.png) \ No newline at end of file diff --git a/16/umbraco-forms/developer/themes.md b/16/umbraco-forms/developer/themes.md new file mode 100644 index 00000000000..9a7e83a631e --- /dev/null +++ b/16/umbraco-forms/developer/themes.md @@ -0,0 +1,205 @@ +--- +description: Documentation on how to apply custom themes to Umbraco Forms +--- + +# Themes + +Umbraco Forms supports Themes, allowing forms to be customized in a much simpler manner. + +## Creating a Theme + +To create a theme, you need to create a folder at `/Views/Partials/Forms/Themes/`. The name of the folder is the name of theme that will be visible in the backoffice when choosing it. + +Copy the explicit files you wish to override in your theme, it may be a single file or all files from the `default` theme folder. Make the necessary changes you desire to CSS class names, markup etc. + +### Obtaining the Default Theme Files + +For Umbraco 9 and previous, it's straightforward to copy the files you need from the default theme folder. We highly recommend that you never customize any files found in the `default` themes folder. There is a risk that any customizations to these files will be lost with any future upgrades you do to Umbraco Forms. + +Umbraco 10+ distributes these files as part of a Razor class library, so you won't find them on disk. Instead you should download the appropriate zip file for your Forms version and extract the ones you need. + +You can obtain the latest versions of the default theme for each Forms major version from the following links: + +* [Forms 10 Default Theme](https://umbra.co/umbraco-forms-default-theme) (for 10.5.5 and above) +* [Forms 11 Default Theme](https://umbra.co/umbraco-forms-default-theme-11) (for 11.1.0 and above) +* [Forms 12 Default Theme](https://umbra.co/umbraco-forms-default-theme-12) (for 12.2.4 and above) +* [Forms 13 Default Theme](https://umbra.co/umbraco-forms-default-theme-13) (for 13.2.2 and above) +* [Forms 14 Default Theme](https://umbra.co/umbraco-forms-default-theme-14) (for 14.1.4 and above) + +If you are using a lower minor version of Forms than those listed, you should download an older version of the default theme. + +The default theme for minor versions are available from the "Source Code" tab available at the bottom of [Umbraco Forms Package page](https://our.umbraco.com/packages/developer-tools/umbraco-forms/). Only versions where changes were made are available. + +You should use the theme available for the highest version that's less or equal to the version of Forms you have installed. + +For example, when using Umbraco Forms 10.4, and no file for that version is available use version 10.3 instead. + +### Amending Theme Files + +{% hint style="info" %} +Umbraco Forms conditional JavaScript logic depends on some CSS classes currently and it is advised that you add any additional classes you require but **do not remove those already being set**. +{% endhint %} + +If adding or amending client-side scripts, you need to copy the `Script.cshtml` file from the `default` themes folder. In your copy, amend the `.js` references to reference your own script files. + +### Shipping Themes in a Razor Class Library + +Umbraco Forms provides it's built-in themes as part of a Razor Class Library for ease of distribution. This can be useful for custom themes, particularly those used in multiple solutions or released as an Umbraco package. + +It is also possible to do this for custom themes. + +1. Create a new Razor Class Library project to hold the theme. +2. Create the necessary Partial Views for your theme within `Views\Partials\Forms\Themes\`. +3. Provide the names of the files in your theme via an implementation of `ITheme`. + * For example, if only overriding a single file, your class would look like the code snippet below: + +```csharp +using Umbraco.Forms.Core.Interfaces; + +public class MyCustomTheme : ITheme +{ + private const string FilePathFormat = "{0}/{1}/{2}.cshtml"; + + public virtual string Name => "my-custom-theme"; + + public virtual IEnumerable Files => + [ + string.Format(FilePathFormat, Core.Constants.System.ThemesPath, Name, "FieldTypes/FieldType.Textfield"), + ]; +} +``` + +4. Register the themes you want to use via a composer: + +```csharp +public class MyComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.Themes() + .Add(); + } +} +``` + +Your theme will now be available in the Theme Picker and the partial view files will be used when rendering forms. + +#### Email Templates + +Email templates provided for the send email workflow can be provided in a Razor Class Library similar to the Theme files. + +The partial view will be created in `Views\Partials\Forms\Emails`. + +It's made available via an implementation of `IEmailTemplate`: + +```csharp +using Umbraco.Forms.Core.Interfaces; + +public class MyCustomEmailTemplate : IEmailTemplate +{ + public virtual string FileName => "My-Custom-Email-Template.cshtml"; +} +``` + +And registered with: + +```csharp +public class MyComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.EmailTemplates() + .Add(); + } +} +``` + +##### Removing the Default Email Template + +If providing custom email templates, you may want to remove the one provided with Forms. You can do that via the same `EmailTemplates` collection. + +```csharp +public class MyComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.EmailTemplates() + .Exclude(); + } +} +``` + +## Using a Theme + +When rendering a form in a view file, you can specify which theme to use with the form. + +Learn more about how to render a form with a theme in the [Rendering Forms](./rendering-forms.md) article. + +## Theme Fallbacks + +When using a theme, Umbraco Forms will try to use a view from the theme folder, but then fallback to the same view in the default theme folder if it can't be found. This allows you to create a theme by only modifying the files necessary to make your customizations. + +Files which can be overridden: + +* Render.cshtml (overrides the entire form - usually not needed) +* Form.cshtml (overrides the generation of the fields on the current page) +* Script.cshtml (overrides the way files are included with the form) +* /Fieldtypes/FieldType.\*.cshtml (overrides a specific view for a field) + +## Helper Methods + +### SetFormThemeCssFile + +Sets the primary form theme stylesheet path. This overrides an already assigned stylesheet and will be rendered out when inserting the form into the page + +```csharp +Html.SetFormThemeCssFile(Model, "~/App_Plugins/UmbracoForms/Assets/Themes/Default/style.css") +``` + +### AddFormThemeScriptFile + +Add a JavaScript file path to include on form render + +```csharp +Html.AddFormThemeScriptFile("~/App_Plugins/UmbracoForms/Assets/themes/default/umbracoforms.js"); +``` + +### SetFormFieldClass + +Adds a class to the form field HTML element of a given type. If no type is given, it will add the class to all fields + +```csharp +// Applies the CSS class 'form-control' to all fields that GetFormFieldClass uses in FieldType views +@Html.SetFormFieldClass("form-control") + +// Applies the CSS class 'some-other-class' for the FieldType of the name 'Password' +@Html.SetFormFieldClass("some-other-class", "Password") +``` + +### GetFormFieldClass + +Retrieves all classes for a given field type, used when rendering form fieldtype partial views + +```csharp +class="@Html.GetFormFieldClass(Model.FieldTypeName)" +``` + +### SetFormFieldWrapperClass + +Adds a class to the div element wrapping around form fields of a given type. If no type is given, it will add the class to all fields + +```csharp +// Applies the CSS class 'form-group' around all fields, labels & help texts +@Html.SetFormFieldWrapperClass("form-group") + +// Applies the CSS class 'some-other-class' for the FieldType of the name 'Password' +@Html.SetFormFieldWrapperClass("some-other-class", "Password") +``` + +### GetFormFieldWrapperClass + +Retrieves all wrapper classes for a given field type, used when rendering form fields. This class wraps both label, help-text and the field itself in the default view + +```csharp +class="@Html.GetFormFieldWrapperClass(f.FieldTypeName)" +``` diff --git a/16/umbraco-forms/developer/webhooks.md b/16/umbraco-forms/developer/webhooks.md new file mode 100644 index 00000000000..790d2d77a8d --- /dev/null +++ b/16/umbraco-forms/developer/webhooks.md @@ -0,0 +1,24 @@ +# Webhooks + +Umbraco Forms will register events for workflow operations that you can use with [Umbraco webhooks](https://docs.umbraco.com/umbraco-cms/reference/webhooks). + +Workflows are operations that you can associate with form submission, approval, or rejection actions. You can use these where you need to notify external systems of the success or failure of a workflow. + +On the Umbraco **Settings** > **Advanced** > **Webhooks** dashboard, you can configure webhooks to respond to workflows. + +![Webhook events](images/wehbook-events-v14.png) + +You can amend the registration of workflow events in code. + +To remove the webhooks that are added by default you can use a composer as follows: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Forms.Core.Extensions; + +internal sealed class TestComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.WebhookEvents().AddForms(formsBuilder => formsBuilder.RemoveDefault()); +} +``` \ No newline at end of file diff --git a/16/umbraco-forms/developer/working-with-data.md b/16/umbraco-forms/developer/working-with-data.md new file mode 100644 index 00000000000..eb4ef07555a --- /dev/null +++ b/16/umbraco-forms/developer/working-with-data.md @@ -0,0 +1,112 @@ +--- +description: "Developer documentation on working with Forms record data." +--- + +# Working With Record Data + +Umbraco Forms includes some helper methods that return records of a given Form, which can be used to output records in your templates using razor. + +## Available Methods + +The methods can be found by injecting the `Umbraco.Forms.Core.Services.IRecordReaderService` interface. For performance reasons, all these methods are paged. + +### GetApprovedRecordsFromPage + +```csharp +PagedResult GetApprovedRecordsFromPage(int pageId, int pageNumber, int pageSize) +``` + +Returns all records with the state set to approved from all Forms on the Umbraco page with the id = `pageId` . + +### GetApprovedRecordsFromFormOnPage + +```csharp +PagedResult GetApprovedRecordsFromFormOnPage(int pageId, Guid formId, int pageNumber, int pageSize) +``` + +Returns all records with the state set to approved from the Form with the id = `formId` on the Umbraco page with the id = `pageId` as a `PagedResult`. + +### GetApprovedRecordsFromForm + +```csharp +PagedResult GetApprovedRecordsFromForm(Guid formId, int pageNumber, int pageSize) +``` + +Returns all records with the state set to approved from the Form with the ID = `formId` as a `PagedResult`. + +### GetRecordsFromPage + +```csharp +PagedResult GetRecordsFromPage(int pageId, int pageNumber, int pageSize) +``` + +Returns all records from all Forms on the Umbraco page with the id = `pageId` as a `PagedResult`. + +### GetRecordsFromFormOnPage + +```csharp +PagedResult GetRecordsFromFormOnPage(int pageId, Guid formId, int pageNumber, int pageSize) +``` + +Returns all records from the Form with the id = `formId` on the Umbraco page with the id = `pageId` as a `PagedResult`. + +### GetRecordsFromForm + +```csharp +PagedResult GetRecordsFromForm(Guid formId, int pageNumber, int pageSize) +``` + +Returns all records from the Form with the ID = formId as a `PagedResult`. + +## The returned objects + +All of these methods will return an object of type `PagedResult` so you can iterate through the `Record` objects. + +The properties available on a `Record` are: + +```csharp +int Id +FormState State +DateTime Created +DateTime Updated +Guid Form +string IP +int UmbracoPageId +string MemberKey +Guid UniqueId +Dictionary RecordFields +``` + +In order to access custom Form fields, these are available in the `RecordFields` property. Furthermore there exists an extension method named `ValueAsString` on `Record` in `Umbraco.Forms.Core.Extensions`, such that you can get the value as string given the alias of the field. + +This extension method handle multi value fields by comma separating the values. E.g. "A, B, C" + +## Sample razor script + +Sample script that is outputting comments using a Form created with the default comment Form template. + +```csharp +@using Umbraco.Core; +@using Umbraco.Cms.Core.Composing; +@using Umbraco.Forms.Core.Extensions; +@inject IRecordReaderService _recordReaderService; + +
    + @foreach (var record in _recordReaderService.GetApprovedRecordsFromPage(Model.Id, 1, 10).Items) + { +
  • + @record.Created.ToString("dd MMMM yyy") + @if(string.IsNullOrEmpty(record.ValueAsString("email"))){ + @record.ValueAsString("name") + } + else{ + + @record.ValueAsString("name") + + } + said +

    @record.ValueAsString("comment")

    +
  • + } +
+``` diff --git a/16/umbraco-forms/editor/attaching-workflows/README.md b/16/umbraco-forms/editor/attaching-workflows/README.md new file mode 100644 index 00000000000..2885acb1e55 --- /dev/null +++ b/16/umbraco-forms/editor/attaching-workflows/README.md @@ -0,0 +1,83 @@ +# Attaching Workflows + +In this article, you can learn how to add extra functionality to your Form by attaching **workflows**. + +Workflows are a way of defining actions after your Form is submitted like sending an email or creating a content node. + +## Default Workflow + +By default, when a Form is submitted the record data is stored in the database. This can be configured in the [Store records](../creating-a-form/form-settings.md#settings-options) of the Forms settings. + +The behavior to display a message to the user who submitted the form can be configured by clicking on the built-in first workflow step. This step is labelled **Submit message/Go to page**, and it can also configure the redirection to another page. + +![Submit message/Go to page](images/MessageOnSubmit-v14.png) + +If a value is selected for **Go to page**, it will be used to redirect to that page once the form has been submitted. + +If no value is selected, the message in **Message on submit** is displayed to the user on the same page, instead of the form fields. This is implemented via a redirect to the current page, ensuring that the form can't be accidentally resubmitted. + +By default, the message is created and rendered in plain text. If you need to add formatting to the message, toggle the **Format message in rich text** button. + +![Submit message/Go to page](images/MessageOnSubmitRichText-v14.png) + +## Video Tutorial + +{% embed url="https://www.youtube.com/watch?ab_channel=UmbracoLearningBase&v=qJrf1drw1Bg" %} +Attaching Workflows to Umbraco Forms +{% endembed %} + +## Adding a Workflow + +At the bottom of your Form, a default workflow is already attached to the Form, as well as an option to configure the workflows. + +![Button](images/configure-workflows-v14.png) + +Clicking **Configure workflow** will give you the option to configure existing workflows, as well as setup new ones. + +![Workflow add](images/WorkflowsPage-v14.png) + +### Choose a Workflow + +A new workflow can be of different types and Umbraco Forms ships with a few default ones. You can find an overview of the types in the [Workflow types](workflow-types.md) article. + +![Workflow add modal](images/WorkflowsAddModel-v14.png) + +### Update Type-specific Settings + +Once the Workflow Type has been selected, you will need to configure the workflow. There are different settings depending on the type that has been selected. + +To use data from the submitted Form in your workflow, head over to the [Magic Strings](../../developer/magic-strings.md) article and learn more about how that's done. + +### Configuring Condition on a Workflow + +You can apply conditions to a workflow that trigger it only under specific circumstances. After adding the desired workflow type (for example, sending an email), you can add a condition to the workflow. + +Select **Enable conditions** to open the condition editor. In the condition editor, you will see options to create logic that determines when the workflow should run. The condition is generally based on the values of the form fields. + +For example: You have a form with a dropdown field labeled **Preferred Contact Method** with options such as **Email** and **Phone**. You can set up a workflow that sends an email notification only when the user selects **Email**. + +![Workflow Conditions](images/workflow-conditions.png) + +Now, this email notification will only be sent when the user selects **Email** as their preferred contact method. + +Fill in the rest of the settings and click **Submit**. The workflow is added to your Form and displayed at the bottom of the page. + +## Workflow Processing + +When a form is submitted, any workflows associated with the "submit" stage of the form will run sequentially in the configured order. The record is stored after these workflows are completed, and as such they can make changes to the information recorded. + +Similarly, approval of a form entry, whether automatic or manual, will trigger the execution of the workflows associated with the "approve" stage. + +Rejection of an entry will trigger the execution of the workflows associated with the "reject" stage. + +If a workflow encounters an unexpected error, it will silently fail from the perspective of the user submitting the form. The exception along with the other details of the failed operation is recorded to the log. + +From Umbraco Forms versions 8.13.0 and 10.1, an audit trail has been made available. In the list of entries for a form, a summary is presented that shows how many workflows were executed, and how many were successful: + +![Workflow execution summary](images/workflow-summary.png) + +For each entry, in the backoffice a table can be viewed that shows each of the workflows and the success, or otherwise, of the operation. + +![Workflow execution summary](images/workflow-audit.png) + +For any workflows that did not complete successfully, a "Retry" link is available to trigger the workflow again. This is useful for example if there was a temporary infrastructure issue that perhaps prevented an email going out. You would be able to retrigger the workflow once the issue is resolved. diff --git a/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit-v14.png new file mode 100644 index 00000000000..85a648b5bc1 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit.png b/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit.png new file mode 100644 index 00000000000..60cd7c57306 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText-v14.png new file mode 100644 index 00000000000..1d89cf21e13 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText.png b/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText.png new file mode 100644 index 00000000000..49b67e2cff7 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowOverview.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowOverview.png new file mode 100644 index 00000000000..f156cca1d26 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowOverview.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/Workflownode.png b/16/umbraco-forms/editor/attaching-workflows/images/Workflownode.png new file mode 100644 index 00000000000..c236ee78763 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/Workflownode.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModal.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModal.png new file mode 100644 index 00000000000..3039c8ddd0f Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModal.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel-v14.png new file mode 100644 index 00000000000..5eaa074a6e8 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel.png new file mode 100644 index 00000000000..66598e8f552 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage-v14.png new file mode 100644 index 00000000000..e6c0a82009c Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage.png new file mode 100644 index 00000000000..01815fa21e2 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAdd.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAdd.png new file mode 100644 index 00000000000..d924d7e420a Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAdd.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddAdd.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddAdd.png new file mode 100644 index 00000000000..49468a6b78f Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddAdd.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSelectType.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSelectType.png new file mode 100644 index 00000000000..1de9c4fc42f Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSelectType.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSubmit.PNG b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSubmit.PNG new file mode 100644 index 00000000000..544ea10c7c5 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSubmit.PNG differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddTypeSettings.png b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddTypeSettings.png new file mode 100644 index 00000000000..c34d27e5e45 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddTypeSettings.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/change-record-state-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/change-record-state-v14.png new file mode 100644 index 00000000000..8153682ffde Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/change-record-state-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/change-record-state.png b/16/umbraco-forms/editor/attaching-workflows/images/change-record-state.png new file mode 100644 index 00000000000..85a3e5f177f Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/change-record-state.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/configure-workflows-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/configure-workflows-v14.png new file mode 100644 index 00000000000..7951c5b6f24 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/configure-workflows-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/configure-workflows.png b/16/umbraco-forms/editor/attaching-workflows/images/configure-workflows.png new file mode 100644 index 00000000000..a1419f8c13c Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/configure-workflows.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/create-new-node.png b/16/umbraco-forms/editor/attaching-workflows/images/create-new-node.png new file mode 100644 index 00000000000..fbf73980957 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/create-new-node.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/email-slack-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/email-slack-v14.png new file mode 100644 index 00000000000..202af5757e0 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/email-slack-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/email-slack.png b/16/umbraco-forms/editor/attaching-workflows/images/email-slack.png new file mode 100644 index 00000000000..03c8585713d Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/email-slack.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/post-as-xml-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/post-as-xml-v14.png new file mode 100644 index 00000000000..5d04edbb4ff Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/post-as-xml-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/post-as-xml.png b/16/umbraco-forms/editor/attaching-workflows/images/post-as-xml.png new file mode 100644 index 00000000000..ed22ad754a5 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/post-as-xml.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file-v14.png new file mode 100644 index 00000000000..ff5775ab668 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file.png b/16/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file.png new file mode 100644 index 00000000000..f6f8b1f1b50 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/save-as-content-node-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/save-as-content-node-v14.png new file mode 100644 index 00000000000..f50bdd2487e Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/save-as-content-node-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/save-as-content-node.png b/16/umbraco-forms/editor/attaching-workflows/images/save-as-content-node.png new file mode 100644 index 00000000000..394b3f0c5d0 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/save-as-content-node.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/send-email-razor-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/send-email-razor-v14.png new file mode 100644 index 00000000000..5710b6b84f8 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/send-email-razor-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/send-email-razor.png b/16/umbraco-forms/editor/attaching-workflows/images/send-email-razor.png new file mode 100644 index 00000000000..59cbe74aa75 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/send-email-razor.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/send-email-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/send-email-v14.png new file mode 100644 index 00000000000..b0efad6e23a Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/send-email-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/send-email.png b/16/umbraco-forms/editor/attaching-workflows/images/send-email.png new file mode 100644 index 00000000000..96b67e0ceb5 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/send-email.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/send-to-URL-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/send-to-URL-v14.png new file mode 100644 index 00000000000..3fad02e3ed2 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/send-to-URL-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/send-to-URL.png b/16/umbraco-forms/editor/attaching-workflows/images/send-to-URL.png new file mode 100644 index 00000000000..40b1ff4dfad Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/send-to-URL.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/workflow-audit.png b/16/umbraco-forms/editor/attaching-workflows/images/workflow-audit.png new file mode 100644 index 00000000000..2f4b33b5502 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/workflow-audit.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/workflow-conditions.png b/16/umbraco-forms/editor/attaching-workflows/images/workflow-conditions.png new file mode 100644 index 00000000000..c40623927ca Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/workflow-conditions.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/workflow-summary.png b/16/umbraco-forms/editor/attaching-workflows/images/workflow-summary.png new file mode 100644 index 00000000000..cb1553920b8 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/workflow-summary.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/workflowbutton.png b/16/umbraco-forms/editor/attaching-workflows/images/workflowbutton.png new file mode 100644 index 00000000000..734758ffc9e Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/workflowbutton.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/xslt-email-v14.png b/16/umbraco-forms/editor/attaching-workflows/images/xslt-email-v14.png new file mode 100644 index 00000000000..098799744ba Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/xslt-email-v14.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/images/xslt-email.png b/16/umbraco-forms/editor/attaching-workflows/images/xslt-email.png new file mode 100644 index 00000000000..faa1e070fd8 Binary files /dev/null and b/16/umbraco-forms/editor/attaching-workflows/images/xslt-email.png differ diff --git a/16/umbraco-forms/editor/attaching-workflows/workflow-types.md b/16/umbraco-forms/editor/attaching-workflows/workflow-types.md new file mode 100644 index 00000000000..4142596f260 --- /dev/null +++ b/16/umbraco-forms/editor/attaching-workflows/workflow-types.md @@ -0,0 +1,229 @@ +--- +description: >- + This article will give you an overview of the Workflow Types available in + Umbraco Forms. +--- + +# Workflow Types + +There are multiple built-in Workflow Types that can be used to extend the functionality of your form. Do you want to post the submitted form as XML, send the data as an email, or send a notification through another messaging system? These are a few of the options you can choose when working with Umbraco Forms. + +## Video Tutorial + +{% embed url="https://www.youtube.com/watch?ab_channel=UmbracoLearningBase&v=L9k0yDbV6qo" %} +Workflow Types in Umbraco Forms +{% endembed %} + +## **Change Record State** + +![Change Record state](images/change-record-state-v14.png) + +Used to automatically **Approve Record**, **Reject Record** or **Delete Record** once it is submitted. Configure words that you want to match and select whether these words should trigger an approval or deletion of the record. + +## **Post as XML** + +![Post as XML](images/post-as-xml-v14.png) + +Used to post the Form as an XML to a specified URL. The following configuration can be set: + +* Workflow Name +* URL (required) +* Method +* XsltFile - used to transform the XML +* Headers - map the needed files +* User +* Password + +## **Save as an XML file** + +![Save as XML](images/save-as-an-xml-file-v14.png) + +Saves the result of the Form as an XML file by using XSLT. The following configuration can be set: + +* Workflow Name +* Path (required) - where to save the XML file +* File extension (required) +* XsltFile - used to transform the XML + +The path needs to point to a folder, not a file name. The files are then stored locally, and relative paths are resolved to the content root. + +{% hint style="info" %} +When storing the files within the `wwwroot` or `App_Plugins` folders, the files will be publicly available by default. +{% endhint %} + +## **Save as Umbraco Content Node** + +![Save as content node](images/save-as-content-node-v14.png) + +Saves a submitted Form as a new content node. You need to choose a Document type and match the fields in the Form with the properties on the selected Document Type. + +You can also choose to set a static value to fill in the properties: + +![Save as content node](images/create-new-node.png) + +In the example above, a Document Type called **Blogpost** is selected for creating the new Content node. + +The value from the **Name** field will be added as the **Node Name** property in the new Content node. The value from the **Email** field will be used as the **Content** property. + +The following configuration can be set: + +* Workflow Name +* Publish - choose whether to publish the node on submission +* Where to save - choose a section in the content tree where this new node should be added + +## **Send Email** + +![Send email](images/send-email-v14.png) + +Sends the result of the Form to the specified email address. The following configuration can be set: + +* Workflow Name +* Message (required) +* Attachment - specify whether file uploads should be attached to the email +* Recipient Email (required) +* CC Email +* BCC Email +* SenderEmail +* Reply To Email +* Subject of the email (required) + +For fields that accept multiple email addresses (Recipient Email, CC Email, BCC Email), you can separate addresses using semicolons (';') or commas (','). For example: + +```none +person@umbraco.dk; person@umbraco.com, person@umbraco.de +``` + +If the _Sender Email_ field is not populated, the address used will be read from CMS configuration. + +The [Content Settings](https://docs.umbraco.com/umbraco-cms/reference/configuration/contentsettings) value configured at `Umbraco:CMS:Content:Notifications:Email` will be used if provided. + +```json + "Umbraco": { + "CMS": { + "Content": { + "Notifications": { + "Email": "person@umbraco.dk" + } + } + } + } +``` + +If that is not set, the [Global Settings](https://docs.umbraco.com/umbraco-cms/reference/configuration/globalsettings) value configured at `Umbraco:CMS:Global:Smtp` will be used. + +```json + "Umbraco": { + "CMS": { + "Global": { + "Smtp": { + "From": "person@umbraco.dk" + } + } + } + } +``` + +The fallback behavior also applies to the other email workflows. + +## **Send Email with Template (Razor)** + +![Send email with template](images/send-email-razor-v14.png) + +Uses a template to send the results of the Form to a specified email address. + +You can create your own custom Razor templates to be used to send out emails upon Forms submission. Read more about how to create these templates in the [Email Templates](../../developer/email-templates.md) article. + +The following configuration can be set: + +* Workflow Name +* Email Template (required) - specify which template you want to use +* Header text - formatted text that will be rendered above the form entry details +* Footer text - formatted text that will be rendered below the form entry details +* Attachments - specify whether file uploads should be attached to the email +* Recipient Email (required) +* CC Email +* BCC Email +* SenderEmail +* Reply To Email +* Subject of the email (required) + +## **Send Form to URL** + +![Send to URL](images/send-to-URL-v14.png) + +Sends the Form to a URL either as a HTTP POST or GET. The following configuration can be set: + +* Workflow Name +* URL (required) +* Method (required) - POST, GET, PUT or DELETE +* Standard Fields - optionally include and map standard form information such as name and page URL +* Fields - map the needed fields +* User +* Password + +When mapping fields, if any are selected, only those chosen will be sent in the request to the configured URL. If no fields are mapped, all will be sent. + +The receiving endpoint extracts form fields and values using GET for querystrings and POST for form collections. + +As an illustrative example, the following code can be used to write the posted form information to a text file: + +```csharp +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System.IO; + +namespace RequestSaver.Controllers +{ + [ApiController] + [Route("[controller]")] + public class SaveRequestController : ControllerBase + { + private const string _filePath = "c:\\temp\\request-save.txt"; + + private readonly ILogger _logger; + + public SaveRequestController(ILogger logger) + { + _logger = logger; + } + + [HttpPost] + public string Save() + { + using (StreamWriter outputFile = new StreamWriter(_filePath)) + { + foreach (var key in Request.Form.Keys) + { + outputFile.WriteLine($"{key}: {(Request.Form[key])}"); + } + } + + return "Done"; + } + } +} +``` + +## **Send XSLT Transformed Email** + +![Send XSLT Email](images/xslt-email-v14.png) + +Sends the result of the Form to an email address with full control over the email contents by providing an xslt file. The following configuration can be set: + +* Workflow Name +* XSLT File - specify which file should be used to transform the content +* Recipient Email (required) +* CC Email +* BCC Email +* SenderEmail +* Reply To Email +* Subject of the email (required) + +## **Slack** + +![Send to Slack](images/email-slack-v14.png) + +Allows to post the Form data to a specific channel on Slack. The following configuration can be set: + +* Workflow Name +* Webhook URL (required) diff --git a/16/umbraco-forms/editor/creating-a-form/README.md b/16/umbraco-forms/editor/creating-a-form/README.md new file mode 100644 index 00000000000..70a2086f24a --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/README.md @@ -0,0 +1,161 @@ +# Creating a Form - The Basics + +In this article, we'll take a look at the basic steps of creating a Form and adding the Form to your Umbraco site. + +## Accessing the Forms Section + +You can manage the Forms in the **Forms** section of the Umbraco backoffice. You need to have access to the section in order to see it. + +If you do not see the **Forms** section, you might need to request access from the site Administrator. An Administrator can give permission to view the **Forms** section. This is done from the **Users** section of the backoffice. + +![Forms Section](images/FormsSectionV14.png) + +## Creating a Form + +To create a Form, follow these steps: + +1. Navigate to the **Forms** section. +2. Click **...** next to the Forms folder. + + ![Forms tree](images/FormsTree-v14.png) +3. Select **Create** > **New Form**. + + ![Forms create dialog](images/FormsCreateDialogV14.png) +4. The Form Designer opens in the editor. + + ![Forms designer](images/FormDesignerStartV14.png) +5. By default, there is a page, a fieldset, and a container available. The rest of the Form has to be added using the interface. +6. Enter a **Name** for the Form. Let's call it _Our first form_. + + ![Forms Name](images/FormDesignerFormNamev14.png) +7. *[Optional]* Enter the **Page Name**. We'll call it _The first page_. Click **Add new page** at the bottom of the Forms designer to add more pages. + + ![Forms Page Name](images/FormDesignerPageCaptionV14.png) +8. *[Optional]* Enter the **Group Name**. Click **Add new group** to add another group. + + ![Forms Group Name](images/FormDesignerPageGroupV14.png) +9. Click the **Add Question** button to add a new field. + + ![Forms Add Field](images/FormDesignerAddFieldV14.png) +10. The **Choose field type** dialog opens. + + ![Forms add field dialog](images/FormDesignerAddFieldDialogV14.png) +11. Select **Short Answer**. Enter the following details in the **Edit field** window: + + | Field Name | Value | + | ------------------ | -------------------- | + | Enter question | Name | + | Enter help text | Enter your name here | +12. In the **Sensitive data** field, choose if the field stores sensitive data. Once selected, the data from this field will be prevented from being downloaded and viewed by users who do not have permission to do so. Only members of the sensitive data user group will see this option of downloading. +13. Enter a **Default Value** for the field. +14. Add a **Placeholder** to make it easier for the user to fill in the Form. +15. Select if the field is **Mandatory** and customize the message. +16. Add a **Validation** to the field. There are some predefined validations available but it is possible to add your own custom validation as well. +17. Some form fields allow you to show or hide the label that's associated with the field when it is rendered within the form on the website. The default is always to show the field, but if you prefer to hide it, untick the **Show label** option. +18. Set **Conditions** for the field. For more information on Conditions, see the [Setting-up conditional logic on fields](conditional-logic.md) article. + + Some of the additional settings are dependent on which answer type was chosen. For example, since we selected _Short Answer_ as our answer type we got two additional settings (Default Value and Placeholder). +19. Once the configuration is completed, click **Submit**. You will see that the field has been added to the Form designer. + + ![Forms name field added](images/FormDesignerFieldAddedV14.png) + +To edit a field, click the **cog** icon next to the field to open the dialog. To copy the field and its properties, click the **copy** icon. To delete a field or a group, click the **Recycle Bin** icon. + +### Structuring the Form + +#### Ordering Fields + +Once you've added a few fields to your Form, you might want to change the order of questions. To do so, click **Reorder** in the top-right corner of the Form designer. + +![Reorder Form field](images/Reorder-Form-v14.png) + +When reordering your Form, you can drag and drop the fields to make it look the way you want. Click **I am done reordering** to get back to the Form designer. + +![Form Fields Reordered](images/Reorder-form-fields-done-v14.png) + +#### Form Pages + +Forms can be grouped into pages. When rendered, each page will be presented one at a time to the user. They will need to complete the first page before moving onto the second and can navigate back and forth between pages. + +To add a new page at the start or end of the form, use the buttons in the top right corner of the editing view. + +![Add new page button at the top of Form](images/add-new-page-v14.png) + +You can also add a new page directly to the bottom of the form via the **Add new page** button. This will appear below other pages when at least one exists. + +![Add new page button](images/add-new-page-button-v14.png) + +### Form Groups + +With a page, form fields can be arranged into groups. These will display all together on a single page but can be styled so the fields are appropriately grouped in fieldsets. + +New groups are added via the **Add new group** button. + +![Add new Group button](images/add-new-group-button-v14.png) + +## Form Columns + +The last level of structure are columns that can be created within a group. To set the number of columns, click the **cog** icon next to the Group Name. You can now add or move fields to the new columns created. + +![Form Columns](images/edit-group-columns.png) + +## Saving the Form + +Once have created the Form, save the design by clicking the **Save** button. + +![Form save Form](images/FormDesignerSaveV14.png) + +## Importing a Form + +**Import Form Definition** allows you to import a form into your Umbraco site using a predefined JSON file. This file contains the form’s structure, fields, validations, workflows, and settings. + +When you import a form definition, Umbraco uses the JSON structure to recreate the form as it was defined, enabling you to: + +- Reuse existing forms across multiple projects or environments. +- Migrate forms between development, testing, and production environments. +- Restore forms from backups or previously exported definitions. + +Using the **Import Form Definition** option, you can manage your forms without having to recreate them. + +![Import a Form](images/import-form.png) + +## Organizing Forms in Folders + +If the product installation is set up to store form definitions in the database, you will be able to store forms within folders. This can help with organization and makes it easier to locate the forms for modification, especially if you plan to create many Forms. + +To create a folder: + +1. Go to the **Forms** section. +2. Click ... next to Forms folder. +3. Select **Create**. +4. Select **New Folder**. + + ![Create Folder](images/create-forms-folder-v14.png) +5. Enter a **Folder Name**. +6. Click **Create Folder**. + + ![Folder Name](images/forms-folder-name-v14.png) + +You can create folders within folders, rename, move, import folders, or delete them. + +![Folder Options](images/Forms-folder-options-v14.png) + +To move or copy forms into folders, click the **...** next to the Form and select **Move**. + +![Move Form in Folder](images/move-form-in-folder-v14.png) + +## Adding the Form to the Umbraco Site + +To add the Form, follow these steps: + +1. Navigate to the **Content** section of the Umbraco Backoffice. +2. Select the content page where you want to insert the Form. The page you choose should have a form picker which you can add in the **Settings** section under **Document Types**. + + ![Content page](images/ContentExamples-v14.png) +3. Click **Choose** and select the Form you want to insert. You will be able to select from the full list of forms. If available on your installation, you will also be able to select using a folder based view, which can be quicker to navigate when many forms have been prepared. + + ![Content page add macro](images/ContentPageAddForm-v14.png) +4. Click **Choose**. +5. The Form is inserted on your page. Click **Save and publish**. + + ![Content page with form](images/ContentExamplesWithFormV14.png) diff --git a/16/umbraco-forms/editor/creating-a-form/conditional-logic.md b/16/umbraco-forms/editor/creating-a-form/conditional-logic.md new file mode 100644 index 00000000000..4ee8c8c0511 --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/conditional-logic.md @@ -0,0 +1,64 @@ +# Setting-up Conditional Logic on Fields + +Sometimes you might have a field in your Form, that you want to show _only_ if the user has entered a specific value in another field. + +You can achieve this setting by using **conditional logic** on Fields. + +## Example + +Take a look at the following: + +![Example Form](images/ExampleForm-v14.png) + +In this case, it makes sense to *only* show the email or phone field when the corresponding option is selected in the **How should we contact you?** field. + +To enable conditions for the **Email** and **Phone** fields, do the following: + +1. Click the `cog` wheel next to the **Email** and **Phone** field. The **Edit question** dialog opens. +2. Enable **Conditions**. The condition field displays more options: + + ![Enable Conditions](images/conditions-v14.png) + +3. Set the appropriate conditions and click **Submit**. + +### Action and Logic Types + +There are two **Action Types**: + +* Show: the field will be displayed if the rules match +* Hide: the field will be hidden if the rules match + +Next up, you'll need to specify the **Logic Type**. This setting is only important if you have multiple rules. + +* All: All of the rules must match +* Any: Any of the rules may match + +## Adding a new condition + +When adding a new condition, you'll need to select the field where you want to evaluate the value and can select an operator. + +In this example, we only want to show the **Phone** field if the value of the **How should we contact you** field is `Phone`. + +![Setup rule](images/phone-conditions-v14.png) + +Similarly, you can display the **Email** field, if the value of the **How should we contact you** field is `Email`. You can see the conditions added to each field in the Forms designer: + +![See conditions in the Forms designer](images/exampleBackoffice-v14.png) + +## Result + +When both the conditions have been set as shown above, this is how it will look on the frontend: + +![Frontend Example](images/exampleFrontend-v14.png) + +In this example, we have only selected **Phone** but it is possible to choose both _Phone_\* and **Email** and display both the fields. + +## Conditions for Pages and Fieldsets + +As well as showing or hiding a field based on conditions, you can also apply conditions to groups of fields (known as fieldsets) or to pages. The process is the same as described above. + +When applying a condition to a page, effectively you are controlling the display of the submit button (for a single-page form) or the next/previous buttons (available on multi-page forms). In this way you can ensure that the entry so far is complete before accepting it or allowing the user to move onto the next page. + +## Conditions for Dates + +You can apply conditions to dates as well as strings. When you use the date picker field, you can set a condition if a submitted date is greater/less than a specific date. diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/README.md b/16/umbraco-forms/editor/creating-a-form/fieldtypes/README.md new file mode 100644 index 00000000000..f36c166aeb5 --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/fieldtypes/README.md @@ -0,0 +1,51 @@ +# Overview Of The Field Types + +Umbraco Forms comes with a bunch of default Field Types also known as **Answer Types**. You can choose from different field types when adding new fields to your Forms. + +By default, the following Field Types are available: + +* **Short Answer**: A textbox allows up to 250 characters. + + ![Textfield](images/shortanswer-V14.png) +* **Long Answer**: A bigger text field that allows multiline text and more than 250 characters. + + ![Textarea](images/longanswer-v14.png) +* [Date](date.md): Displays a picker that allows the user to select a date. + + ![Datepicker](images/date-v14.png) +* **Checkbox**: Displays a single checkbox that can be checked or not. + + ![Checkbox](images/CheckBox-v14.png) +* [File Upload](fileupload.md): Allows user to select and upload a local file. + + ![File upload](images/fileupload-v14.png) +* **Password**: Allows to type a password. The input is not visible when typing. + + ![Password field](images/password-v14.png) +* **Multiple Choice**: Displays a list of items with a checkbox for each item where the user can select multiple options. + + ![Checkboxlist](images/multiplechoice-v14.png) +* **Data Consent**: A field for the purpose of asking for data consent. By default, this field is added to all new Forms. + + ![Data Consent](images/dataconsent-v14.png) +* **Dropdown**: Displays a list of items in a drop down box where the user can select a single option. + + ![Dropdownlist](images/dropdown-v14.png) +* **Single Choice**: Displays a list of items with a radio button for each item where the user can select a single option. + + ![Single choice](images/singlechoice-v14.png) +* **Title and Description**: Displays a read-only title and description for a set of form fields. + + ![Title and description](images/titleanddescription-v14.png) +* **Rich Text**: Displays read-only formatted text that can be used to provide additional information and links within a form. + + ![Rich text](images/richtext-v14.png) +* **Hidden**: A hidden field allows developers to include data that cannot be seen or modified by users when a Form is submitted. + + ![Hidden](images/hidden-v14.png) +* [Recaptcha V2](recaptcha2.md): The field displays a single checkbox for the user to select in order to validate the Form. + + ![reCAPTCHA v2](images/recaptcha2-v14.png) +* [Recaptcha V3 with Score](recaptcha3.md): This field returns a score for each request without user interaction. The score is based on user interactions with the site and enables you to take an appropriate action for your site based on the score. + + ![reCAPTCHA v3](images/recaptcha3-v14.png) diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/date.md b/16/umbraco-forms/editor/creating-a-form/fieldtypes/date.md new file mode 100644 index 00000000000..73f841dc893 --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/fieldtypes/date.md @@ -0,0 +1,18 @@ +# Date + +The date picker uses a front-end library called [Pikaday](https://github.com/dbushell/Pikaday) to display a UI to pick dates. + +![Date picker on frontend](images/date-v14.png) + +Pikaday date picker can be localized based on the page the Form is rendered on. + +The date picker displays the picked date in the required locale. Using JavaScript, a hidden field is updated with a standard date format to send to the server for storing record submissions. This avoids the locale mixing up the dates. + +To achieve localized date, a Razor partial view is included at `/Views/Partials/Forms/Themes/default/DatePicker.cshtml`. + +The **DatePicker.cshtml** includes the `moment-with-locales.min.js` library to help with the date locale formatting and the appropriate changes to Pikaday to support the locales. If you wish to use a different DatePicker component, edit the **DatePicker.cshtml** file as per your needs. + +## Configure the date picker + +The Date picker has [configuration settings](../../../developer/configuration/README.md#date-picker-field-type-configuration) to control the number of years shown in the picker and the date format. + diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/fileupload.md b/16/umbraco-forms/editor/creating-a-form/fieldtypes/fileupload.md new file mode 100644 index 00000000000..4a201ca618b --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/fieldtypes/fileupload.md @@ -0,0 +1,36 @@ +# File upload + +The File Upload field allows the users to upload a file along with the Form on your website. + +In this article, you will find details about the configuration options you have for the File Upload field. + +![fileupload](images/fileupload-types-v14.png) + +## Predefined allowed File Types + +You can choose to specify which files you want to allow the user to upload, when accessing the Form. + +To allow only specific files: + +1. Select the specific File Types the user should be able to upload. +2. Click **Submit**. + +{% hint style="info" %} +We recommend selecting only specified files, to limit malicious code to be uploaded, whenever the user is submitting the Form. +{% endhint %} + +## User Defined Allowed File Types + +If the list of predefined file types does not include a specific file type, you can add additional ones. + +To add new file type: + +1. Type a file extension name in the **User defined allowed file types** field. +2. Click **+**. +3. Click **Submit**. + +## Server-side file validation + +The file upload field type will verify the file contents using the registered set of `IFileStreamSecurityValidator` instances. + +To read more about this feature, see [Server-side file validation](https://docs.umbraco.com/umbraco-cms/v/10.latest-lts/reference/security/serverside-file-validation) in the CMS documentation. diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v14.png new file mode 100644 index 00000000000..0236d22b7bd Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v9.png new file mode 100644 index 00000000000..b25bb9e7981 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox.png new file mode 100644 index 00000000000..83e772f6d8f Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v14.png new file mode 100644 index 00000000000..c79ab2a79b7 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v9.png new file mode 100644 index 00000000000..5593e50daed Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent.png new file mode 100644 index 00000000000..6212b9aaa08 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-picker.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-picker.png new file mode 100644 index 00000000000..88438cf1128 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-picker.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v14.png new file mode 100644 index 00000000000..97e766caeb8 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v9.png new file mode 100644 index 00000000000..a7120c5bd61 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date.PNG b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date.PNG new file mode 100644 index 00000000000..29b4381bcbb Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/date.PNG differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v14.png new file mode 100644 index 00000000000..675c49aef4c Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v9.png new file mode 100644 index 00000000000..449893930f3 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown.PNG b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown.PNG new file mode 100644 index 00000000000..6e91b9d23f6 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown.PNG differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types-v14.png new file mode 100644 index 00000000000..fe6d83959e6 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types.png new file mode 100644 index 00000000000..f00c05c4fc2 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v14.png new file mode 100644 index 00000000000..a0dbb52c581 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v9.png new file mode 100644 index 00000000000..4e60329f2fc Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload.png new file mode 100644 index 00000000000..f80a306f364 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v14.png new file mode 100644 index 00000000000..bfdfe08a630 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v9.png new file mode 100644 index 00000000000..5ab1c600a3e Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden.PNG b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden.PNG new file mode 100644 index 00000000000..bc9f9ce9fa1 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden.PNG differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v14.png new file mode 100644 index 00000000000..009387ada19 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v9.png new file mode 100644 index 00000000000..9980b404ede Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer.PNG b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer.PNG new file mode 100644 index 00000000000..077b1b2c7dc Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer.PNG differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v14.png new file mode 100644 index 00000000000..1e09a543229 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v9.png new file mode 100644 index 00000000000..d1a37cedf1c Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice.PNG b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice.PNG new file mode 100644 index 00000000000..8d3344212e7 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice.PNG differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v14.png new file mode 100644 index 00000000000..94909e503df Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v9.png new file mode 100644 index 00000000000..c771733f6f7 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/password.PNG b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/password.PNG new file mode 100644 index 00000000000..6ed6590fd8d Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/password.PNG differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v14.png new file mode 100644 index 00000000000..87d6f6e63c6 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v9.png new file mode 100644 index 00000000000..c5de9019855 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2.png new file mode 100644 index 00000000000..2ae28bcf014 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v14.png new file mode 100644 index 00000000000..c68b59b5eb3 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v9.png new file mode 100644 index 00000000000..41d9316ede4 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext-v14.png new file mode 100644 index 00000000000..0ec23abba93 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext.png new file mode 100644 index 00000000000..da89d3394cc Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-V14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-V14.png new file mode 100644 index 00000000000..95dfabe1fca Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-v9.png new file mode 100644 index 00000000000..6e504b4aa61 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer.PNG b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer.PNG new file mode 100644 index 00000000000..bf130226f3b Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer.PNG differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v14.png new file mode 100644 index 00000000000..1c36d09f476 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v9.png new file mode 100644 index 00000000000..f175439fd32 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice.PNG b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice.PNG new file mode 100644 index 00000000000..589dbd4d563 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice.PNG differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v14.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v14.png new file mode 100644 index 00000000000..00b2877899d Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v9.png b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v9.png new file mode 100644 index 00000000000..1260f8cb9d2 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription.PNG b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription.PNG new file mode 100644 index 00000000000..02c2187853d Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription.PNG differ diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha2.md b/16/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha2.md new file mode 100644 index 00000000000..6ee355bd82d --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha2.md @@ -0,0 +1,28 @@ +# reCAPTCHA V2 + +In Umbraco Forms, reCAPTCHA V2 comes out of the box to help you to protect your site from spam, malicious people, and so on. + +## Enabling reCAPTCHA V2 + +Follow these steps to enable reCAPTCHA V2 in Umbraco Forms: + +1. Go to the **Forms** section in the backoffice. +2. Find the form that should have **ReCAPTCHA v2** enabled. +3. Add a new question and select **ReCAPTCHA v2** as its answer type. +4. Make sure the field is set as **Mandatory**. +5. Configure ReCAPTCHA settings in the `appSettings.json` file to include public and private keys: + +```json +"Umbraco"{ + "Forms": { + "FieldTypes": { + "Recaptcha2": { + "PublicKey": "", + "PrivateKey": "" + } + } + } + } +``` + +You can create your keys by logging into your [reCAPTCHA account](https://www.google.com/recaptcha/). diff --git a/16/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha3.md b/16/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha3.md new file mode 100644 index 00000000000..e8d23ca9bc4 --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha3.md @@ -0,0 +1,30 @@ +# reCAPTCHA V3 + +In Umbraco Forms, reCAPTCHA V3 comes out of the box. + +reCAPTCHA v3 allows you to verify if an interaction is legitimate without any user interaction. + +## Enabling reCAPTCHA V3 + +Follow these steps to enable reCAPTCHA V3 in Umbraco Forms: + +1. Go to the **Forms** section in the backoffice. +2. Find the form that should have **ReCAPTCHA v3** enabled. +3. Add a new question and select **ReCAPTCHA v3 with Score** as its answer type. +4. Make sure the field is set as **Mandatory**. +5. Configure ReCAPTCHA settings in the `appSettings.json` file to include public and private keys: + +```json +"Umbraco"{ + "Forms": { + "FieldTypes": { + "Recaptcha3": { + "SiteKey": "", + "PrivateKey": "" + } + } + } + } +``` + +You can create your keys by logging into your [reCAPTCHA account](https://www.google.com/recaptcha/). diff --git a/16/umbraco-forms/editor/creating-a-form/form-advanced.md b/16/umbraco-forms/editor/creating-a-form/form-advanced.md new file mode 100644 index 00000000000..1fd82a910b5 --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/form-advanced.md @@ -0,0 +1,98 @@ +# Form Advanced Options + +In this article, you will find information about accessing the Forms Advanced Options and the features available to customize your Form. + +To access the Form Advanced Options: + +1. Navigate to the **Forms** section. +2. Open a Form you wish to customize. +3. Click **Advanced** in the top-right corner of the screen. + +{% hint style="info" %} +The advanced options for forms are only available when [configured to display](../../developer/configuration/README.md#enableadvancedvalidationrules). +{% endhint %} + +## Validation Rules + +When creating forms you can add validation to individual fields, making them mandatory or applying a regular expression pattern. You can provide validation rules for the entire form via the advanced options. This allows you to validate expressions based on multiple fields. For example, "these two email fields should be the same", or "this date should be after this other one". + +![Validation rules](./images/validation-rules.png) + +To add new rules, you need to provide the rule definition, an error message and select a field to which the message will be associated. Once created you can click to edit or delete them from the list. + +Crafting the rule definition itself requires use of [JSON logic](https://jsonlogic.com/) along with placeholders for the field or fields that are being validated. + +### Examples + +One example use case would be ensuring that two fields match each other, perhaps when asking for a user's email address. Given two fields on the form, one with the alias of `email` and the other `compareEmail`, the rule would be: + +```json +{ + "==": [ + "{email}", + "{compareEmail}" + ] +} +``` + +A slightly more complex example could be with two dates, where, if provided, you want to ensure the second date is later than the first. So given fields with aliases of `startDate` and `endDate` a rule would look like this: + +```json +{ + "or": [ + { + "==": [ + "{startDate}", + "" + ] + }, + { + "==": [ + "{endDate}", + "" + ] + }, + { + ">": [ + "{endDate}", + "{startDate}" + ] + } + ] +} +``` + +Rules can be nested too. In this final illustrative example, we have two fields. One with the alias `choose` is a drop-down list with two values: `A` and `B`. The second field with alias `test` we want to be completed only if the user selects `B`. So we create a rule that is valid only if A is selected OR B is selected AND `test` is completed. + +```json +{ + "or": [ + { + "==": [ + "{choose}", + "A" + ] + }, + { + "and": [ + { + "==": [ + "{choose}", + "B" + ] + }, + { + "!=": [ + "{test}", + "" + ] + } + ] + } + ] +} +``` + +Overall, you can create rules of varying complexity, using comparisons between fields and static values. + +When the form is rendered, these validation rules will be applied on both the client and server-side. In this way, you can ensure the submission is only accepted if it meets the requirements. \ No newline at end of file diff --git a/16/umbraco-forms/editor/creating-a-form/form-info.md b/16/umbraco-forms/editor/creating-a-form/form-info.md new file mode 100644 index 00000000000..ce615b50b51 --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/form-info.md @@ -0,0 +1,25 @@ +# Form Information + +You can view the System information of the form in the **Info** tab. + +To access the Form Information: + +1. Go to the **Forms** section. +2. Open a Form you wish to customize. +3. Click **Info** in the top-right corner of the screen. + +![Form information dialog](images/form-info-V14.png) + +## General + +The "General" panel displays system information about the form. The date the form was created and last updated are shown. Also available are the integer and GUID identifiers that are useful when referring to the form in code. + +![Form general information panel](images/form-info-general-v14.png) + +## References + +Information about which pages a form is hosted on is tracked by Umbraco every time a content item is saved. + +The list of pages where the form is hosted is shown in this section. + +![Form relations panel](images/form-info-references-V14.png) diff --git a/16/umbraco-forms/editor/creating-a-form/form-settings.md b/16/umbraco-forms/editor/creating-a-form/form-settings.md new file mode 100644 index 00000000000..9266930d56f --- /dev/null +++ b/16/umbraco-forms/editor/creating-a-form/form-settings.md @@ -0,0 +1,98 @@ +# Form Settings + +In this article, you will find information about accessing the Form Settings and the options available to customize your Form. + +To access the Form Settings: + +1. Go to the **Forms** section. +2. Open a Form you wish to customize. +3. Click **Settings** in the top-right corner of the screen. + + ![Form settings dialog](images/FormSettings-V14.png) + +## Settings Options + +The following options are available in Forms Settings: + +### Store Records + +By default, all submitted records are saved in the database. This option allows you to view and export the saved records from the queries overview. If you do not want to store data (due to policies in your organization), you can uncheck the box. + +Disabling this option will prevent database records from being stored, but any file uploads made as part of the form submission will still be retained. If you do not want the files to be stored, ensure that any process or method used to process, move, or copy them to a different location also removes the file. + +![Form settings Store Records](images/Store-Records-V14.png) + +### Captions + +Customize the labels of the **Submit**, **Next**, and **Previous** buttons used in your Form. + +![Form settings stylesheet](images/FormSettingsCaptions-V14.png) + +### Styling + +Set a stylesheet to give your Form custom styling. You have an option to disable the default styling. Enabling the **Disable default stylesheet** option will prevent a default stylesheet to be added to the pages where the Form is placed. + +![Form settings stylesheet](images/FormSettingsStyling-V14.png) + +### Validation + +Define a message that is displayed when a field is mandatory, when a value is not supplied, or when the value is invalid. + +![Form settings validation](images/FormSettingsValidation-V14.png) + +The following Validations are available: + +| Validation Type | Description | +| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Mandatory error message** | The error message is displayed for a field that is marked as mandatory but a value has not been provided upon submission. This setting can be overwritten on a field level - `{0}` will be replaced with the field caption. | +| **Invalid error message** | The error message is displayed for a field if the value provided is not valid (a regular expression has been setup but the input does not match). This setting can be overwritten on a field level - `{0}` will be replaced with the field caption. | +| **Show validation summary** | Enable this option if you wish to display a summary of all the error messages on top of the Form. | +| **Hide field validation labels** | Enable this option if you wish to hide individual field error messages from being displayed. | +| **Mark fields** | You can choose to not mark any fields or only mark mandatory or optional fields. | +| **Indicator** | Choose which indicator to use when a field has been marked as mandatory. The default indicator is `*` | + +### Autocomplete + +The autocomplete setting for the overall form can be changed from the default of "None" to "On" or "Off". Setting this explicitly will control how the browser offers automatic prompts to the user when completing the form. + +![Form Settings Autocomplete](images/FormSettingsAutocomplete-V14.png) + +### Multi-page forms + +The settings available in this section allow you to customize how multi-page forms are presented to site visitors. + +

Multi-Page Form Settings

+ +| Option | Description | +| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **Paging display** | Select whether paging information is displayed at the top and/or bottom of the form. | +| **Paging display format** | Provide a format string for the paging details. By default `Page {0} of {1}` is used which will be replaced as, for example, `Page 1 of 4`. | +| **Page caption format** | Provide a format string for rendering the page captions. By default `Page {0}` is used which will be replaced as, for example, `Page 1`. If a caption for the page has been provided, it will be used instead. | +| **Show summary page** | Select whether a summary page is displayed at the end of multi-page forms, where a user can review their entry before submitting. | +| **Summary heading** | Provide the heading for the summary page. | + +{% hint style="info" %} +These options will only be available if [the feature is configured for display](../../developer/configuration/README.md#enablemultipageformsettings). +{% endhint %} + +### Moderation + +Enabling this feature allows the moderator to manage the approval status of a form. This can be used in a number of scenarios. For example, if the form submission will be publicly shown, you can control which are published. + +![Form settings Moderation](images/FormSettingsModeration-V14.png) + +### Fields Displayed + +By default, a constant set of fields are displayed when form entries are shown in a list. You will see the first three fields in the form, plus some system information like the record state and the date it was created. + +To customize this, turn off the "Display default fields" option and select the ones you wish to display. + +![Form settings Fields Displayed](images/FormSettingsFieldsDisplayed-V14.png) + +### Data Retentions + +To help protect site visitor privacy, rules can be configured in this section for the automatic deletion of submissions. You can set how long to retain records for each state (submitted, approved or rejected). + +A background service that carries out the actual removal of records needs to be [enabled in configuration](../../developer/configuration/#scheduledrecorddeletion). If that is not running, a notification will be displayed. + +![Form settings Date Retentions](images/FormSettingsDataRetention-V14.png) diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentExampleMacroButton.png b/16/umbraco-forms/editor/creating-a-form/images/ContentExampleMacroButton.png new file mode 100644 index 00000000000..6eb9af9ba2a Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentExampleMacroButton.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentExamples-v14.png b/16/umbraco-forms/editor/creating-a-form/images/ContentExamples-v14.png new file mode 100644 index 00000000000..1631e9aa17f Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentExamples-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentExamples.png b/16/umbraco-forms/editor/creating-a-form/images/ContentExamples.png new file mode 100644 index 00000000000..4788a8051cb Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentExamples.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithForm.png b/16/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithForm.png new file mode 100644 index 00000000000..fbfac9ec1e2 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithForm.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithFormV14.png b/16/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithFormV14.png new file mode 100644 index 00000000000..aad96c12297 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithFormV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentPage.png b/16/umbraco-forms/editor/creating-a-form/images/ContentPage.png new file mode 100644 index 00000000000..4f69f96fbb9 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentPage.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentPageAddForm-v14.png b/16/umbraco-forms/editor/creating-a-form/images/ContentPageAddForm-v14.png new file mode 100644 index 00000000000..8193eb6a31d Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentPageAddForm-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialog.png b/16/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialog.png new file mode 100644 index 00000000000..768d74786e2 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialog.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialogChooseForm.png b/16/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialogChooseForm.png new file mode 100644 index 00000000000..0e7d474a735 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialogChooseForm.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentPageMacroButton.png b/16/umbraco-forms/editor/creating-a-form/images/ContentPageMacroButton.png new file mode 100644 index 00000000000..4b246d8300e Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentPageMacroButton.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ContentPageWithForm.png b/16/umbraco-forms/editor/creating-a-form/images/ContentPageWithForm.png new file mode 100644 index 00000000000..20367d97c3a Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ContentPageWithForm.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/EnableConditions-v9.png b/16/umbraco-forms/editor/creating-a-form/images/EnableConditions-v9.png new file mode 100644 index 00000000000..c966c9dd1b5 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/EnableConditions-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/EnableConditions.png b/16/umbraco-forms/editor/creating-a-form/images/EnableConditions.png new file mode 100644 index 00000000000..6b340b94d29 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/EnableConditions.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ExampleForm-v14.png b/16/umbraco-forms/editor/creating-a-form/images/ExampleForm-v14.png new file mode 100644 index 00000000000..9c511f6dfe5 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ExampleForm-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/ExampleForm.png b/16/umbraco-forms/editor/creating-a-form/images/ExampleForm.png new file mode 100644 index 00000000000..ff0f3e4d85f Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/ExampleForm.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddField.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddField.png new file mode 100644 index 00000000000..8b0e1300dcd Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddField.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialog.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialog.png new file mode 100644 index 00000000000..98dccacddfb Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialog.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV14.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV14.png new file mode 100644 index 00000000000..acca60a6587 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV8.png new file mode 100644 index 00000000000..a3496f28f83 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV14.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV14.png new file mode 100644 index 00000000000..532d3ce4218 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV8.png new file mode 100644 index 00000000000..e299ae2e4c7 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAdded.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAdded.png new file mode 100644 index 00000000000..295eea6fb2e Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAdded.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV14.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV14.png new file mode 100644 index 00000000000..df5c3351312 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV8.png new file mode 100644 index 00000000000..dec6a524c71 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFormName.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFormName.png new file mode 100644 index 00000000000..44b3416ea87 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFormName.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNameV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNameV8.png new file mode 100644 index 00000000000..d6309410183 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNameV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNamev14.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNamev14.png new file mode 100644 index 00000000000..633800eb6db Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNamev14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaption.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaption.png new file mode 100644 index 00000000000..86f6b8c0da9 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaption.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV14.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV14.png new file mode 100644 index 00000000000..abc1667bf8f Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV8.png new file mode 100644 index 00000000000..d3949955585 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroup.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroup.png new file mode 100644 index 00000000000..21e7a5cfedb Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroup.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV14.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV14.png new file mode 100644 index 00000000000..2eec93fa39f Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV8.png new file mode 100644 index 00000000000..60b9ba0ec4c Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSave.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSave.png new file mode 100644 index 00000000000..9f7d175686c Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSave.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV14.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV14.png new file mode 100644 index 00000000000..14277e102f0 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV8.png new file mode 100644 index 00000000000..65ba8981085 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSetFieldCaption.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSetFieldCaption.png new file mode 100644 index 00000000000..cccb58ed6fc Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerSetFieldCaption.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerStart.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerStart.png new file mode 100644 index 00000000000..1c8c630ba2b Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerStart.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV14.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV14.png new file mode 100644 index 00000000000..71d3d2f3908 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV8.png new file mode 100644 index 00000000000..c2d410cc4b8 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettings-V14.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettings-V14.png new file mode 100644 index 00000000000..45713c06409 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettings-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettings.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettings.png new file mode 100644 index 00000000000..75869b154b9 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettings.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete (1).png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete (1).png new file mode 100644 index 00000000000..148c59918e3 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete (1).png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete-V14.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete-V14.png new file mode 100644 index 00000000000..7580de5f9d8 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete.png new file mode 100644 index 00000000000..148c59918e3 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-V14.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-V14.png new file mode 100644 index 00000000000..6cfe5eba5cb Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-v9.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-v9.png new file mode 100644 index 00000000000..47d983ac098 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions.png new file mode 100644 index 00000000000..78aa8931291 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention-V14.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention-V14.png new file mode 100644 index 00000000000..1285c139069 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention.png new file mode 100644 index 00000000000..9021062ac0a Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed-V14.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed-V14.png new file mode 100644 index 00000000000..9193b25fbe4 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed.png new file mode 100644 index 00000000000..18cc4170619 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration-V14.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration-V14.png new file mode 100644 index 00000000000..6ae72c1f72b Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration.png new file mode 100644 index 00000000000..02deafec93d Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling-V14.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling-V14.png new file mode 100644 index 00000000000..bfd37303560 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling.png new file mode 100644 index 00000000000..450a2a8ace6 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation-V14.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation-V14.png new file mode 100644 index 00000000000..d4ec44a8472 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation.png b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation.png new file mode 100644 index 00000000000..ed70a24c4af Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/Forms-folder-options-v14.png b/16/umbraco-forms/editor/creating-a-form/images/Forms-folder-options-v14.png new file mode 100644 index 00000000000..f3ed72c626f Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/Forms-folder-options-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialog.png b/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialog.png new file mode 100644 index 00000000000..147cb920f8d Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialog.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV14.png b/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV14.png new file mode 100644 index 00000000000..7a0f7d6c053 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV8.png new file mode 100644 index 00000000000..ed694743220 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV9.png b/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV9.png new file mode 100644 index 00000000000..b607cfdfedc Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsFieldSettings.gif b/16/umbraco-forms/editor/creating-a-form/images/FormsFieldSettings.gif new file mode 100644 index 00000000000..eee91a2c3f2 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsFieldSettings.gif differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsSection.png b/16/umbraco-forms/editor/creating-a-form/images/FormsSection.png new file mode 100644 index 00000000000..388839d192e Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsSection.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsSectionV14.png b/16/umbraco-forms/editor/creating-a-form/images/FormsSectionV14.png new file mode 100644 index 00000000000..c8cbd01f797 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsSectionV14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsSectionV8.png b/16/umbraco-forms/editor/creating-a-form/images/FormsSectionV8.png new file mode 100644 index 00000000000..d10b6854700 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsSectionV8.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsSectionV9.png b/16/umbraco-forms/editor/creating-a-form/images/FormsSectionV9.png new file mode 100644 index 00000000000..ff9731388e2 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsSectionV9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsTree-v14.png b/16/umbraco-forms/editor/creating-a-form/images/FormsTree-v14.png new file mode 100644 index 00000000000..8d1af3e3ea6 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsTree-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/FormsTree.png b/16/umbraco-forms/editor/creating-a-form/images/FormsTree.png new file mode 100644 index 00000000000..83c8153e016 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/FormsTree.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/Reorder-Form-v14.png b/16/umbraco-forms/editor/creating-a-form/images/Reorder-Form-v14.png new file mode 100644 index 00000000000..e0424f8deb8 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/Reorder-Form-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/Reorder-form-fields-done-v14.png b/16/umbraco-forms/editor/creating-a-form/images/Reorder-form-fields-done-v14.png new file mode 100644 index 00000000000..d4f50e63259 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/Reorder-form-fields-done-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/Reorder_Form.png b/16/umbraco-forms/editor/creating-a-form/images/Reorder_Form.png new file mode 100644 index 00000000000..46d08a18cce Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/Reorder_Form.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/Reorder_Form_1.png b/16/umbraco-forms/editor/creating-a-form/images/Reorder_Form_1.png new file mode 100644 index 00000000000..ca5c608127b Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/Reorder_Form_1.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/Store-Records-V14.png b/16/umbraco-forms/editor/creating-a-form/images/Store-Records-V14.png new file mode 100644 index 00000000000..2f1cc088557 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/Store-Records-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/Store-Records.png b/16/umbraco-forms/editor/creating-a-form/images/Store-Records.png new file mode 100644 index 00000000000..4c6b7287dd5 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/Store-Records.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/add-new-group-button-v14.png b/16/umbraco-forms/editor/creating-a-form/images/add-new-group-button-v14.png new file mode 100644 index 00000000000..47bed8874f0 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/add-new-group-button-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/add-new-page-button-v14.png b/16/umbraco-forms/editor/creating-a-form/images/add-new-page-button-v14.png new file mode 100644 index 00000000000..4c8502b0f23 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/add-new-page-button-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/add-new-page-v14.png b/16/umbraco-forms/editor/creating-a-form/images/add-new-page-v14.png new file mode 100644 index 00000000000..57809496a8e Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/add-new-page-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/add-new-page.png b/16/umbraco-forms/editor/creating-a-form/images/add-new-page.png new file mode 100644 index 00000000000..c7eccc7a639 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/add-new-page.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/conditions-v14.png b/16/umbraco-forms/editor/creating-a-form/images/conditions-v14.png new file mode 100644 index 00000000000..71ff4f34777 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/conditions-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/conditions-v9.png b/16/umbraco-forms/editor/creating-a-form/images/conditions-v9.png new file mode 100644 index 00000000000..894fa43a1c5 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/conditions-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/conditions.png b/16/umbraco-forms/editor/creating-a-form/images/conditions.png new file mode 100644 index 00000000000..6fa49f4e76d Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/conditions.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/create-forms-folder-v14.png b/16/umbraco-forms/editor/creating-a-form/images/create-forms-folder-v14.png new file mode 100644 index 00000000000..b5fef0962e7 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/create-forms-folder-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/edit-group-columns.png b/16/umbraco-forms/editor/creating-a-form/images/edit-group-columns.png new file mode 100644 index 00000000000..a57099f3d6d Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/edit-group-columns.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/email.png b/16/umbraco-forms/editor/creating-a-form/images/email.png new file mode 100644 index 00000000000..bf8baf3211b Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/email.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v14.png b/16/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v14.png new file mode 100644 index 00000000000..c950da37724 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v9.png b/16/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v9.png new file mode 100644 index 00000000000..2a1c0a8d0d5 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/exampleBackoffice.png b/16/umbraco-forms/editor/creating-a-form/images/exampleBackoffice.png new file mode 100644 index 00000000000..9e2798b2350 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/exampleBackoffice.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/exampleConditions.png b/16/umbraco-forms/editor/creating-a-form/images/exampleConditions.png new file mode 100644 index 00000000000..47720a8a894 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/exampleConditions.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v14.png b/16/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v14.png new file mode 100644 index 00000000000..3a2c1de6c25 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v9.png b/16/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v9.png new file mode 100644 index 00000000000..1d31ab79570 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v9.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/exampleFrontend.png b/16/umbraco-forms/editor/creating-a-form/images/exampleFrontend.png new file mode 100644 index 00000000000..e400cd61780 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/exampleFrontend.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/form-info-V14.png b/16/umbraco-forms/editor/creating-a-form/images/form-info-V14.png new file mode 100644 index 00000000000..89076d66f75 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/form-info-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/form-info-general-v14.png b/16/umbraco-forms/editor/creating-a-form/images/form-info-general-v14.png new file mode 100644 index 00000000000..16766b38d54 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/form-info-general-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/form-info-general.png b/16/umbraco-forms/editor/creating-a-form/images/form-info-general.png new file mode 100644 index 00000000000..00f228f6e6a Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/form-info-general.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/form-info-references-V14.png b/16/umbraco-forms/editor/creating-a-form/images/form-info-references-V14.png new file mode 100644 index 00000000000..23e111fc50e Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/form-info-references-V14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/form-info-relations.png b/16/umbraco-forms/editor/creating-a-form/images/form-info-relations.png new file mode 100644 index 00000000000..03eac1b8ec5 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/form-info-relations.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/form-info.png b/16/umbraco-forms/editor/creating-a-form/images/form-info.png new file mode 100644 index 00000000000..f0f8e36d94b Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/form-info.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/forms-folder-name-v14.png b/16/umbraco-forms/editor/creating-a-form/images/forms-folder-name-v14.png new file mode 100644 index 00000000000..8b166a4fefc Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/forms-folder-name-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/frontend-email.png b/16/umbraco-forms/editor/creating-a-form/images/frontend-email.png new file mode 100644 index 00000000000..1a30fbcdc0c Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/frontend-email.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/frontend-phone.png b/16/umbraco-forms/editor/creating-a-form/images/frontend-phone.png new file mode 100644 index 00000000000..662b35cec7a Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/frontend-phone.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/import-form.png b/16/umbraco-forms/editor/creating-a-form/images/import-form.png new file mode 100644 index 00000000000..ad5b8c6c180 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/import-form.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/move-form-in-folder-v14.png b/16/umbraco-forms/editor/creating-a-form/images/move-form-in-folder-v14.png new file mode 100644 index 00000000000..dff1e769bfa Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/move-form-in-folder-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/phone-conditions-v14.png b/16/umbraco-forms/editor/creating-a-form/images/phone-conditions-v14.png new file mode 100644 index 00000000000..1e2425cd03e Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/phone-conditions-v14.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/phone.png b/16/umbraco-forms/editor/creating-a-form/images/phone.png new file mode 100644 index 00000000000..77cc3f9a414 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/phone.png differ diff --git a/16/umbraco-forms/editor/creating-a-form/images/validation-rules.png b/16/umbraco-forms/editor/creating-a-form/images/validation-rules.png new file mode 100644 index 00000000000..97452dfa8e7 Binary files /dev/null and b/16/umbraco-forms/editor/creating-a-form/images/validation-rules.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/README.md b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/README.md new file mode 100644 index 00000000000..464237b07e3 --- /dev/null +++ b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/README.md @@ -0,0 +1,86 @@ +# Defining And Attaching Prevalue Sources + +Prevalue sources are a way to pre-define and/or retrieve a list of items from a certain source. They can be added in any field types that include some kind of list like Dropdown and Multiple/Single Choice lists. + +## Setting up a Prevalue Source + +Prevalue sources can be managed in the **Prevalue sources** folder available in the **Forms** section. + +![Prevalue source tree](images/prevaluesourcetree-v14.png) + +To set a prevalue source: + +1. Go to the **Forms** section. +2. Click **...** next to the **Prevalue Sources** folder. +3. Click **Create**. +4. The **Choose prevalue source type** pane opens in the right-side of the editor. +5. Select the type of prevalue source. For more information on the different default types, see the [Overview of the Prevalue Source Types](prevalue-source-types.md) article. + + ![Choose type](images/choosetype-v14.png.png) + +### Configuring the Prevalue Source + +Depending on the **prevalue source type** you choose, you'll need to provide some additional settings. For this article, we will select **Get values from textfile**. + +1. Select **Get values from textfile** from the **Choose prevalue source type** pane. + ![Type settings](images/typesettings-v14.png) + +2. Enter a Name for the prevalue source type. Let's call it *My Prevalue Source*. +3. Now, create a file containing the list to use as prevalues. For example: a `.txt` file containing the following values: + + ```cs + example value 1 + example value 2 + example value 3 + example value 4 + example value 5 + ``` + +4. Select **Click to upload** in the **Text File**. +5. Choose the text file you created. Click **Open**. +6. Select your preferred **Cache option** for caching the list of prevalues when rendering in a form. +7. Click **Save**. + + ![Prevalue source settings](images/preview-v14.png) + +If you would like to have different values presented to your users from the value stored, you can provide two values per line, separated with a vertical bar (|), e.g.: + +``` +1|example value 1 +2|example value 2 +3|example value 3 +4|example value 4 +5|example value 5 +``` + +In this case the user would pick from a list showing the captions, but the single integer values would be stored with the record. + +This can be useful if the recorded entries are used in any subsequent workflows or business processes, where particular values, that aren't appropriate for the user to select from, are required. + +### Defining Cache Options for the Prevalue Source + +Sometimes retrieving the list of options for a prevalue source can be an expensive operation. If the source depends on data from external systems, it could be that the list changes regularly or rarely. + +Given the variation here, we allow you to select an appropriate level of caching for the list of options. + +You can choose between: + +- `No Caching` - no caching will be applied and the list of options will be retrieved from source on every request. You will likely only want to choose this option if the information changes frequently and it's important that the latest is presented to website visitors. +- `Cache For Specified Time` - the list will be cached for the period of time provided. +- `Cache With No Expiry` - the list will be cached on first request and not retrieved again until either the prevalue source is edited or the website is restarted. This ismost appropriate to use for information held within the prevalue source data itself (such as when uploading a text file). + +![Prevalue cache options](images/prevalue-cache-options-v14.png) + +## Attaching a Prevalue Source to a Field + +Once a prevalue source has been created, it can be used while building Forms in the Forms designer. + +**Example:** Let's add a Multiple Choice field type in our Form. + +If there is at least one prevalue source defined in the project, the Prevalues source will contain a dropdown from where you can choose the predefined value. + +![Prevalue source](images/FieldPrevalueSource-v14.png) + +Once you have selected the prevalue source, the values are rendered in the Forms designer from the attached source. + +![Preview](images/fieldpreview.png) diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource-v14.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource-v14.png new file mode 100644 index 00000000000..fa445776bcf Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource-v14.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource.png new file mode 100644 index 00000000000..c1293a4a9ae Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/Prevalues-with-caption.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/Prevalues-with-caption.png new file mode 100644 index 00000000000..7e0a79b21b1 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/Prevalues-with-caption.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/SQLdatabase-v14.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/SQLdatabase-v14.png new file mode 100644 index 00000000000..e5793f6bfe6 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/SQLdatabase-v14.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype-v14.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype-v14.png new file mode 100644 index 00000000000..5fe77bae083 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype-v14.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype.png new file mode 100644 index 00000000000..3ed6b97bb94 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues-v14.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues-v14.png new file mode 100644 index 00000000000..9f350a72448 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues-v14.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues.png new file mode 100644 index 00000000000..4e0dd7513ce Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/docs-from-xpath.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/docs-from-xpath.png new file mode 100644 index 00000000000..05a0b020f3f Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/docs-from-xpath.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/fieldpreview.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/fieldpreview.png new file mode 100644 index 00000000000..ba1e9aeac2f Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/fieldpreview.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options-v14.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options-v14.png new file mode 100644 index 00000000000..52222907264 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options-v14.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options.png new file mode 100644 index 00000000000..d030dd94fd4 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree-v14.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree-v14.png new file mode 100644 index 00000000000..23ae81e8c86 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree-v14.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree.png new file mode 100644 index 00000000000..bb90fa4e7d3 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview-v14.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview-v14.png new file mode 100644 index 00000000000..94d165ae93b Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview-v14.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview.png new file mode 100644 index 00000000000..3fca5d00d48 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings-v14.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings-v14.png new file mode 100644 index 00000000000..aa1c171d39c Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings-v14.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings.png new file mode 100644 index 00000000000..8281c10fab2 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v14.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v14.png new file mode 100644 index 00000000000..940c3a9ecaf Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v14.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v9.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v9.png new file mode 100644 index 00000000000..2f769c15c47 Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v9.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents.png b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents.png new file mode 100644 index 00000000000..ec43727e01e Binary files /dev/null and b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents.png differ diff --git a/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/prevalue-source-types.md b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/prevalue-source-types.md new file mode 100644 index 00000000000..7b40c18766a --- /dev/null +++ b/16/umbraco-forms/editor/defining-and-attaching-prevaluesources/prevalue-source-types.md @@ -0,0 +1,51 @@ +# Prevalue Source Types Overview + +There are some default prevalue source types that can be used. In this article, we will give a quick overview of them: + +## Get values from textfile + +Upload a textfile that contains the prevalues. Each prevalue should have its own line in the file. Once the file has been uploaded, you can find it in `~/wwwroot/App_Data/UmbracoForms/Data/PreValueTextFiles/{GUID}` where the `{GUID}`is replaced with the pre-value ID. + +![Get values from textfile](images/preview-v14.png) + +## Umbraco Documents + +Allows to use content nodes from a specific source as prevalues. You can apply the following settings in the **Details** section: + +* Select which **Value field** should be used for the value of the prevalue. +* You can define the root node by either + * Choosing a node directly from the Content tree or + * Using XPath +* Enable **Use current page as root** instead of choosing a specific root node. _The preview is not available when this setting is enabled._ +* Select a specific **Document type**, if the selected root node contains a different Document Type. +* Enable **List all Descendants** of the selected root node to list all levels of descendants. +* Select **Order by** from the drop-down list to display how the prevalue list should be ordered. +* Select your preferred **Cache option** for caching the list of prevalues when rendering in a form. + +![Umbraco Documents](images/umbraco-documents-v14.png) + +## SQL Database + +You can provide the following details in the **Details** section: + +Connect to a OleDB compatible database table and construct a prevalue source from it. Once selected, it will be editable from the Forms interface. + +The following configurations need to be set in the **Details** section: + +* Connection string (either choose one from your web.config or add another from a textfield). +* Connection String from configuration +* Table Name +* Key Column +* Value Column +* Caption Column +* Select your preferred **Cache option** for caching the list of prevalues when rendering in a form. + +![SQL Database](images/SQLdatabase-v14.png) + +## Umbraco Data Type Prevalues + +Choose an Umbraco Data Type to use its configured prevalue collection. + +In the example below, the prevalue collection from a Data Type called `Home - Font - Radio button` is used: + +![Data Type prevalues](images/datatype-prevalues-v14.png) diff --git a/16/umbraco-forms/editor/images/BulkActions.png b/16/umbraco-forms/editor/images/BulkActions.png new file mode 100644 index 00000000000..dfb879546e9 Binary files /dev/null and b/16/umbraco-forms/editor/images/BulkActions.png differ diff --git a/16/umbraco-forms/editor/images/EntriesViewer.png b/16/umbraco-forms/editor/images/EntriesViewer.png new file mode 100644 index 00000000000..fe077a4161f Binary files /dev/null and b/16/umbraco-forms/editor/images/EntriesViewer.png differ diff --git a/16/umbraco-forms/editor/images/Export-v14.png b/16/umbraco-forms/editor/images/Export-v14.png new file mode 100644 index 00000000000..efc9bb7686b Binary files /dev/null and b/16/umbraco-forms/editor/images/Export-v14.png differ diff --git a/16/umbraco-forms/editor/images/Export.png b/16/umbraco-forms/editor/images/Export.png new file mode 100644 index 00000000000..9ba199defea Binary files /dev/null and b/16/umbraco-forms/editor/images/Export.png differ diff --git a/16/umbraco-forms/editor/images/ExportAllDialog-v14.png b/16/umbraco-forms/editor/images/ExportAllDialog-v14.png new file mode 100644 index 00000000000..2d7dd5a549f Binary files /dev/null and b/16/umbraco-forms/editor/images/ExportAllDialog-v14.png differ diff --git a/16/umbraco-forms/editor/images/ExportAllDialog.png b/16/umbraco-forms/editor/images/ExportAllDialog.png new file mode 100644 index 00000000000..09bf4519314 Binary files /dev/null and b/16/umbraco-forms/editor/images/ExportAllDialog.png differ diff --git a/16/umbraco-forms/editor/images/Filter.png b/16/umbraco-forms/editor/images/Filter.png new file mode 100644 index 00000000000..36dbbd65dd6 Binary files /dev/null and b/16/umbraco-forms/editor/images/Filter.png differ diff --git a/16/umbraco-forms/editor/images/entry-details-v14.png b/16/umbraco-forms/editor/images/entry-details-v14.png new file mode 100644 index 00000000000..77e47c96500 Binary files /dev/null and b/16/umbraco-forms/editor/images/entry-details-v14.png differ diff --git a/16/umbraco-forms/editor/images/tree-v14.png b/16/umbraco-forms/editor/images/tree-v14.png new file mode 100644 index 00000000000..c472e109511 Binary files /dev/null and b/16/umbraco-forms/editor/images/tree-v14.png differ diff --git a/16/umbraco-forms/editor/images/tree.png b/16/umbraco-forms/editor/images/tree.png new file mode 100644 index 00000000000..37918780188 Binary files /dev/null and b/16/umbraco-forms/editor/images/tree.png differ diff --git a/16/umbraco-forms/editor/viewing-and-exporting-entries.md b/16/umbraco-forms/editor/viewing-and-exporting-entries.md new file mode 100644 index 00000000000..8d873f1548e --- /dev/null +++ b/16/umbraco-forms/editor/viewing-and-exporting-entries.md @@ -0,0 +1,60 @@ +# Viewing And Exporting Entries + +To view the Entries for each Form, go to the Form and click on the **Entries** tab. + +![Tree](images/tree-v14.png) + +## Video overview + +{% embed url="https://youtu.be/vUQpX3wqDrs" %} +Watch this video to learn how to manage entries submitted via Umbraco Forms. +{% endembed %} + +## Entries Overview + +When accessing the Entries viewer, you will be able to see all the entries submitted via the Form. + +![Entries viewer](images/tree-v14.png) + +### Viewing the Entries + +By default, the list is filtered to show entries only from the past month. If you want to change the date range, pick the appropriate time period from the date picker. You can also filter the entries by specific words using the Search field on the left. + +Click **Entry details** on each record in the list to open the full set of information recorded for the form entry. Clicking on the entry record displays the **Clear** and **Delete** buttons. + +![Filter](images/entry-details-v14.png) + +### Editing the Entries + +If configured via the permissions model and supported by the version of Umbraco Forms you are running, entries may be editable via the backoffice. If available, click the _Edit_ button to switch the read-only view of an entry to an editable one and _Save_ to record the changes. An audit trail will show who and when updates on the entry were made. + +Validation will operate as is configured for the form in terms of mandatory fields and those that must match a particular pattern. Conditional display of fields is not supported. + +## Exporting Entries + +To export all the entries from your Form: + +1. Go to the **Forms** section. +2. Navigate to the Form **Entries** you wish to export. +3. Click **Export**. + + ![Export Entries](images/Export-v14.png) + +4. The Export dialog opens. Choose a format such as **Excel File** to export the Form records to. + + ![Export dialog](images/ExportAllDialog-v14.png) +5. Click **Export**. +6. Click **Save**. + +If you have fields that allow the user to upload files within your form, you will also have the option to download a zip file containing these files. You can either download the files in the structure that they are stored on the web server's disk. Or you can download them organised by entry, so it's easier to match up the entry listed in the spreadsheet download with the uploaded file(s). + +## Record Actions + +When selecting entries, it is possible to execute different actions. To select an entry, click anywhere on the entry. + +![Record bulk actions](images/entry-details-v14.png) + +Select at least 1 record to see the available actions. By default, there are 2 possible actions: + +* Clear +* Delete diff --git a/16/umbraco-forms/installation/images/Forms_Section_Backoffice.png b/16/umbraco-forms/installation/images/Forms_Section_Backoffice.png new file mode 100644 index 00000000000..9ed7bf7f936 Binary files /dev/null and b/16/umbraco-forms/installation/images/Forms_Section_Backoffice.png differ diff --git a/16/umbraco-forms/installation/images/InstallingForms.gif b/16/umbraco-forms/installation/images/InstallingForms.gif new file mode 100644 index 00000000000..59643bd9c02 Binary files /dev/null and b/16/umbraco-forms/installation/images/InstallingForms.gif differ diff --git a/16/umbraco-forms/installation/images/Manage_packages.png b/16/umbraco-forms/installation/images/Manage_packages.png new file mode 100644 index 00000000000..53774af554b Binary files /dev/null and b/16/umbraco-forms/installation/images/Manage_packages.png differ diff --git a/16/umbraco-forms/installation/images/Manage_packages_v10.png b/16/umbraco-forms/installation/images/Manage_packages_v10.png new file mode 100644 index 00000000000..c47a0ecf652 Binary files /dev/null and b/16/umbraco-forms/installation/images/Manage_packages_v10.png differ diff --git a/16/umbraco-forms/installation/images/Manage_packages_v14.png b/16/umbraco-forms/installation/images/Manage_packages_v14.png new file mode 100644 index 00000000000..dd8f92cf16a Binary files /dev/null and b/16/umbraco-forms/installation/images/Manage_packages_v14.png differ diff --git a/16/umbraco-forms/installation/images/UpgradeAvailable.png b/16/umbraco-forms/installation/images/UpgradeAvailable.png new file mode 100644 index 00000000000..6a24cc30737 Binary files /dev/null and b/16/umbraco-forms/installation/images/UpgradeAvailable.png differ diff --git a/16/umbraco-forms/installation/images/UpgradeNow.png b/16/umbraco-forms/installation/images/UpgradeNow.png new file mode 100644 index 00000000000..92a5d752e00 Binary files /dev/null and b/16/umbraco-forms/installation/images/UpgradeNow.png differ diff --git a/16/umbraco-forms/installation/images/UpgradeProgress.png b/16/umbraco-forms/installation/images/UpgradeProgress.png new file mode 100644 index 00000000000..3d092da8972 Binary files /dev/null and b/16/umbraco-forms/installation/images/UpgradeProgress.png differ diff --git a/16/umbraco-forms/installation/images/buy-license.png b/16/umbraco-forms/installation/images/buy-license.png new file mode 100644 index 00000000000..29655a7bf20 Binary files /dev/null and b/16/umbraco-forms/installation/images/buy-license.png differ diff --git a/16/umbraco-forms/installation/images/image.png b/16/umbraco-forms/installation/images/image.png new file mode 100644 index 00000000000..002dbcbe5c8 Binary files /dev/null and b/16/umbraco-forms/installation/images/image.png differ diff --git a/16/umbraco-forms/installation/images/start-with-forms-v14.png b/16/umbraco-forms/installation/images/start-with-forms-v14.png new file mode 100644 index 00000000000..a17420f6d3d Binary files /dev/null and b/16/umbraco-forms/installation/images/start-with-forms-v14.png differ diff --git a/16/umbraco-forms/installation/images/start-with-forms-v9.png b/16/umbraco-forms/installation/images/start-with-forms-v9.png new file mode 100644 index 00000000000..e8ff764e518 Binary files /dev/null and b/16/umbraco-forms/installation/images/start-with-forms-v9.png differ diff --git a/16/umbraco-forms/installation/images/start-with-forms.png b/16/umbraco-forms/installation/images/start-with-forms.png new file mode 100644 index 00000000000..eafcd021e58 Binary files /dev/null and b/16/umbraco-forms/installation/images/start-with-forms.png differ diff --git a/16/umbraco-forms/installation/install.md b/16/umbraco-forms/installation/install.md new file mode 100644 index 00000000000..3b65659a255 --- /dev/null +++ b/16/umbraco-forms/installation/install.md @@ -0,0 +1,38 @@ +--- +description: Installing Umbraco Forms +--- + +# Installing Umbraco Forms + +Umbraco contains the **Forms** section, by default. You will see a similar interface, when you click on the **Forms** section in the **Umbraco Backoffice**. + +![Form section in backoffice](images/Forms\_Section\_Backoffice.png) + +## Video Tutorial + +{% embed url="https://www.youtube.com/watch?v=3Aojbp_1MPc" %} + +To install the Umbraco Forms package (**Umbraco.Forms**), follow these steps: + +1. Identify the Umbraco CMS version your project is running. +2. Find a compatible version of Umbraco Forms that matches your Umbraco CMS version. A list of Umbraco Forms versions can be found on [nuget.org](https://www.nuget.org/packages/Umbraco.Forms#versions-body-tab). +3. Run the following command on a command prompt of your choice, replacing `` with the appropriate version identified above: + + ```cs + dotnet add package Umbraco.Forms --version + ``` +4. Restart the web application using the following command: + + ```cs + dotnet run + ``` + +## Start Building Forms + +Once the installation is successful, you will see a similar screen in the **Forms** section: + +![Create form](images/start-with-forms-v14.png) + +## Using Forms + +For details on using Forms, see the [Editor Documentation](../editor/creating-a-form/README.md). diff --git a/16/umbraco-forms/installation/the-licensing-model.md b/16/umbraco-forms/installation/the-licensing-model.md new file mode 100644 index 00000000000..5284bc59a67 --- /dev/null +++ b/16/umbraco-forms/installation/the-licensing-model.md @@ -0,0 +1,132 @@ +# Licensing + +Umbraco Forms is a commercial product. You have a 14-day free trial to try out the product. After your trial expires, you'll need to have a **valid license** to keep using the product on your site. + +## How does it work? + +Licenses are sold per domain and will also work on all subdomains. With every license, you will be able to configure two development/testing domains. + +{% hint style="info" %} +The licenses are not bound to a specific product version. They will work for all versions of the related product. +{% endhint %} + +Let's say that you have a license configured for your domain, `mysite.com`, and you've configured two development domains, `devdomain.com` and `devdomain2.com`. + +The license will cover the following domains: + +* `localhost` +* `*.mysite.com` +* `www.mysite.com` +* `mysite.com.local` +* `devdomain.com` +* `www.devdomain.com` +* `devdomain2.com` +* `www.devdomain2.com` + +{% hint style="info" %} +You can have only 1 license per Umbraco installation. +{% endhint %} + +## What does a license cover? + +There are a few differences as to what the licenses cover: + +* A single license covers the installation of Umbraco Forms in 1 production domain, as well as in 2 development domains. +* The production domain includes **all subdomains** (e.g. `*.mysite.com`), as well as the `.local` extension (e.g. `mysite.com.local`). +* The development domains work with or without the `www` subdomain. +* The license allows for an unlimited number of forms. +* The license also includes `localhost` as a valid domain. + +{% hint style="info" %} +If you have multiple domains pointing at the same installation, you have the option to purchase and [add **additional domains**](the-licensing-model.md#add-additional-domains) to your license. + +Each additional domain includes 1 live domain and 2 development/testing domains. + +This is an add-on domain for existing licenses. Refunds will not be given for this product. +{% endhint %} + +## Configuring your license + +You can look at the pricing, features, and purchase the license on the [Umbraco Forms](https://umbraco.com/products/add-ons/forms/) page. + +When you've bought a license you need to configure it with your domains. You can either configure your license right away or you can do it later by visiting your account on Umbraco.com. + +1. Login to your account at [shop.umbraco.com](https://shop.umbraco.com). +2. Navigate to the **Manage Licenses** section. +3. Locate your unconfigured Forms license and choose **Configure / Add domain**. +4. Define the primary as well as up to two development domains for which the license will be used. + +### Add additional domains + +Once you have a configured Umbraco Forms license, you can add additional domains. This is relevant if you need your forms to be available on multiple public domains. + +1. Login to your account at [shop.umbraco.com](https://shop.umbraco.com). +2. Navigate to the **Manage Licenses** section. +3. Locate your configured Forms license. +4. Choose **Configure / Add domain**. + +
+ +5. Select **Click here to buy** at the bottom of the configuration page. +6. Configure the additional domain after completing the purchase, or do it later via your account. + +### Reconfiguration of domains + +Once a license has been configured with the domains, it is not possible to reconfigure them. An exception is when there is a mistake in the domain URL. +As reconfiguration is not possible, you will either need to purchase an additional domain or a [new license](https://umbraco.com/products/umbraco-forms/). + +## Installing your license + +Once you've configured your license with the correct domains, you are ready to install the license on your Umbraco installation. + +1. Download your license from your Umbraco.com account - this will give you a `.lic` file +2. Place the file in the `/umbraco/Licenses` directory in your Umbraco installation + +The `.lic` file must be placed in the `/umbraco/Licenses` directory to be registered by Umbraco Forms. If the file isn't placed correctly, the application will automatically switch to trial mode. + +### Multiple license files + +You can install multiple Umbraco Forms license files without merging them. Place each license file in the `/umbraco/Licenses` directory (or an alternative location). Each file should begin with `umbracoForms`, for example, `umbracoForms.example1.lic` and `umbracoForms.example2.lic`. This setup allows your installation to recognize multiple licensed domains. + +### Alternative license location + +If you can't include the license file in the `/umbraco/Licenses` directory for any reason, it is possible to configure an alternative location for the file. + +It can be configured in the Umbraco installation's `appSettings.json` file by adding the following configuration: + +```json +{ + "Umbraco": { + "Licensing": { + "Directory": "~/custom-licenses-folder/" + } + } +} +``` + +The value contains the path of your custom license directory relative to the root of your Umbraco installation. + +{% hint style="warning" %} +This will also change the location for other Umbraco-related licenses in this project. +{% endhint %} + +## Federal Information Processing Standards (FIPS) Compliant Environments + +The algorithm used to decrypt Forms licenses is not supported on locked down FIPS compliant environments, such as those used in the defense industry. + +If you are in this situation and unable to resolve it via configuration of the environment, please reach out to Umbraco support. + +We have the possibility of generating and providing Forms licenses using alternate algorithms. + +{% hint style="info" %} +You can use this configuration if you reference `Umbraco.Licensing` version `13.0.1` or higher. +{% endhint %} + +Apply the following configuration with the appropriate algorithm - `DES` (the default), `TripleDES`, or `AES`: + +```json + "Umbraco": { + "Licensing": { + "LicenseEncodeAndDecodeAlgorithm": "DES|TripleDES|AES" + }, +`````` \ No newline at end of file diff --git a/16/umbraco-forms/legacy-documentation.md b/16/umbraco-forms/legacy-documentation.md new file mode 100644 index 00000000000..50cadab40d4 --- /dev/null +++ b/16/umbraco-forms/legacy-documentation.md @@ -0,0 +1,7 @@ +# Legacy Documentation + +This documentation platform covers only major versions of the Umbraco Forms since Umbraco 9+. If you are using an older version of Umbraco Forms, you will need to go elsewhere. + +The documentation for Umbraco 7 and 8 lives on [our.umbraco.com](https://our.umbraco.com/documentation/Add-ons/). + +
Umbraco 11 Documentationhttps://github.com/umbraco/UmbracoDocs/tree/umbraco-eol-versions/11/umbraco-forms
Umbraco 8 Documentationhttps://our.umbraco.com/documentation/Add-ons/UmbracoForms/
diff --git a/16/umbraco-forms/release-notes.md b/16/umbraco-forms/release-notes.md new file mode 100644 index 00000000000..9b5aa378dfa --- /dev/null +++ b/16/umbraco-forms/release-notes.md @@ -0,0 +1,168 @@ +--- +description: Get an overview of the things changed and fixed in each version of Umbraco Forms. +--- + +# Release notes + +In this section, we have summarized the changes to Umbraco Forms released in each version. Each version is presented with a link to the [Forms issue tracker](https://github.com/umbraco/Umbraco.Forms.Issues/issues) showing a list of issues resolved in the release. We also link to the individual issues themselves from the detail. + +If there are any breaking changes or other issues to be aware of when upgrading they are also noted here. + +{% hint style="info" %} +If you are upgrading to a new major version, you can find information about the breaking changes in the [Version Specific Upgrade Notes](upgrading/version-specific/) article. +{% endhint %} + +## Release history + +This section contains the release notes for Umbraco Forms 15 including all changes for this version. + +### [15.1.1](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.1.1) (March 7th 2025) + +* Ignore existing corrupt record data and ensure proper JSON serialization when storing entries with forged data +* Parse magic string placeholders in advanced validation rule error message +* Only parse magic string placeholders in field mapping static values (fixes JSON deserialization error) +* Fix invalid `CreatedBy` and `UpdatedBy` column name errors in migration by getting 'slim' objects from repository +* Fix export file path generation and checking (enhances Linux/Docker compatibility) + +### [15.1.0](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.1.0) (January 16th 2025) + +* All items detailed under release candidates for 15.1.0. + +### [15.1.0-rc3](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.1.0) (December 20th 2024) + +* Rendered a hidden submit button on multi-page forms. Ensures that a default button to go forward is used when submitting a form via return key press or a mobile "Go" button [#1343](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1343). + +### [15.1.0-rc2](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.1.0) (December 20th 2024) + +* Used the name and description defined on the setting attribute for backoffice labels when no client-side localization is available [#1336](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1336). +* Resolved minor backoffice issues when creating and saving prevalue and data sources. +* Resolved issue where maximum length check on input field was applied to incorrect field [#1342](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1342). + +### [15.1.0-rc1](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.1.0) (December 17th 2024) + +#### Validation rules across form fields + +When creating forms you are able to add validation to individual fields, making them mandatory or applying a regular expression pattern. With the 13.4 release we are looking to make this more powerful, by allowing the addition of validation rules for the entire form. The idea is that this will allow you to validate expressions based on multiple fields. For example, "these two email fields should be the same", or "this date should be after this other one". + +Crafting these rules requires use of [JSON logic](https://jsonlogic.com/) so is considered a "power user" feature. They also require an additional front-end dependency for the rendering of forms on the website. As such they are surfaced on a new "Advanced" tab and only visible and used if enabled in configuration. We don't have, and it seems difficult to provide, an intuitive user interface for rule creation taking into account all the flexibility available. Nonetheless, having the ability to use more complex validation rules seems a valuable addition. + +When the form is rendered, the validation rules will be applied on the client, where we support both the `aspnet-client-validation` and `jquery.validate` libraries. They are also verified server-side. In this way you can ensure the submission is only accepted if it meets the requirements. + +Feedback on this feature in particular is welcome. + +Read more about [editing advanced validation rules](./editor/creating-a-form/form-advanced.md) as well as the [configuration option required to enable them](./developer/configuration/README.md#enableadvancedvalidationrules). + +#### Tracking editor activity + +Whilst previously we tracked and displayed the date a form was created and last edited, we didn't show who had made these updates. With 15.1 installed we will start to track this and display the information where available. You'll find this on the form, data source or prevalue source's "Info" tab [#1315](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1315). + +#### Copy of workflows + +Forms allows you to make a copy of a form to use as a starting point for a new one. You can choose whether or not to copy workflows along with the form. With the 15.1 release, we've made available a second dialog allowing you to copy workflows to an existing form [#1185](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1185). You can select any or all of the workflows on the current form and copy them to the selected destination form. + +We've also resolved an edge case around copying a form. It's possible to [define workflows as mandatory](./developer/extending/customize-default-workflows.md#setting-a-mandatory-default-workflow). Copying the form without workflows excludes the desired workflow. You would have a form that didn't contain the workflow you wanted to be included on all. This has been tightened up now and mandatory workflows will always be assigned to the copied form [#1331](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1331). + +#### File upload validation messages + +Previously the validation messages presented on the website front end when uploading files were hardcoded and always provided in English. We've added settings now to the "File Upload" field type allowing you to customize these. Dictionary keys can be used in order to provide the information in the user's preferred language [#1327](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1327). + +#### Other + +Other bug fixes included in the release: + +* Fixed issue with applying links to rich text settings on custom field or workflow types [#1329](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1329). + +### [15.0.3](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.3) (December 5th 2024) + +* Fixed regression introduced in 15.0.1 that caused issues for custom field types overriding the `ProcessSubmittedValue` method [#1328](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1328). + +### [15.0.2](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.2) (November 28th 2024) + +* Fixed issue with case sensitive checkbox conditions across multi-page forms [#1325](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1325). +* Fixed Forms dashboard form title and icon alignment. +* Migrated rich text features to use the CMS's Tiptap editor [#1326](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1326). +* Fixed issue with creation of folder for forms. + +### [15.0.1](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.1) (November 21st 2024) + +* Fixed issues with multi-page forms used in conjunction with a `FormPrePopulateNotification` handler. File uploads and multi-value fields like checkbox lists now function correctly [#1317](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1317) [#1320](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1320). +* Added a couple of missing translation keys [#1316](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1316) [#1319](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1319). +* Rendered file upload previews in the backoffice. +* Fixed issue with saving the "Hide field validation labels" value when editing form settings. +* Fixed issue with selection of Document Type on the "Save as Umbraco node" workflow type. +* Used correct labels for conditions when used on fields, fieldsets, pages or workflows [#1323](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1323). + +### [15.0.0](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.0) (November 14th 2024) + +* Compatibility with Umbraco 15.0.0 + +### [15.0.0-rc4](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.0) (November 13th 2024) + +* Compatibility with Umbraco 15.0.0-rc4 + +### [15.0.0-rc3](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.0) (November 6th 2024) + +* Compatibility with Umbraco 15.0.0-rc3 +* Preview of features and bug fixes due in 13.3 and 14.2: + * Fixed issue where sensitive data flag on a field could not be set for new fields added to a form [#1309](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1309) + * Added date picker setting to set the text for the aria-label [#1082](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1082) + * Allow selection of custom fields for values and captions for pre-value sources based on Umbraco documents [#1195](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1195) + * Added Umbraco Flavoured Markdown component for the rendering of form names within a block list + * Added validation message when submitting a form via the API with an invalid file extension [#1310](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1310) + +### [15.0.0-rc2](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.0) (October 18th 2024) + +* Compatibility with Umbraco 15.0.0-rc2 +* Preview of features and bug fixes due in 13.3 and 14.2: + * Permission for delete entries [#1303](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1303). + * Configurable date format for date picker field [#1276](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1276). + * Fixed issue with single checkbox triggering a condition on a field on a subsequent page [#1304](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1304). + * Improve cross-platform check when exporting to Excel. + +### [15.0.0-rc1](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.0) (October 8th 2024) + +* Compatibility with Umbraco 15.0.0-rc1 + * See full details of breaking changes under the [Version-specific Upgrade Guide](upgrading/version-specific/). +* Made retrieval of prevalue source values and execution of record exports asynchronous [#1285](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1285). +* Preview of features due in 13.3 and 14.2: + * Option to display paging details for multi-page forms. + * Form picker with allowed forms managed via folders. + * New "form details picker" providing a single property editor for the selection of form, theme, and redirect. + * Ability to provide custom themes and email templates via razor class libraries [#795](https://github.com/umbraco/Umbraco.Forms.Issues/issues/795). + * Backoffice translations for Dutch [#1264](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1264). + +## Umbraco.Forms.Deploy + +This Deploy add-on adds support for transferring, restoring, exporting and importing (including migrating between major versions) of Umbraco Forms data. + +### 15.1.0 (January 23rd 2025) + +* All items from 15.1.0-rc1 + +### 15.1.0-rc1 (December 17th 2024) + +* Set the form entities created/updated by to the resolved user when deploying (requires Umbraco Forms 15.1) + +### 15.0.0 (November 14th 2024) + +* Update Forms and Deploy dependencies to 15.0.0 + +### 15.0.0-rc4 (November 13th 2024) + +* Update Forms and Deploy dependencies to 15.0.0-rc4 + +### 15.0.0-rc3 (November 7th 2024) + +* Update Forms and Deploy dependencies to 15.0.0-rc3 + +### 15.0.0-rc2 (October 24th 2024) + +* Update Forms and Deploy dependencies to 15.0.0-rc2 + +### 15.0.0-rc1 (October 14th 2024) + +* Update Forms and Deploy dependencies to 15.0.0-rc1 + +## Legacy release notes + +You can find the release notes for versions out of support in the [Legacy documentation on GitHub](https://github.com/umbraco/UmbracoDocs/blob/umbraco-eol-versions/12/umbraco-forms/release-notes.md) and [Umbraco Forms Package page](https://our.umbraco.com/packages/developer-tools/umbraco-forms/). diff --git a/16/umbraco-forms/tutorials/creating-a-contact-form.md b/16/umbraco-forms/tutorials/creating-a-contact-form.md new file mode 100644 index 00000000000..b6a61f748db --- /dev/null +++ b/16/umbraco-forms/tutorials/creating-a-contact-form.md @@ -0,0 +1,293 @@ +# Creating a Contact Form + +In this tutorial, we'll look at creating a Contact Form using Umbraco Forms. It will take you through the process of creating a Contact Form and cover all the different components involved in building the form. + +You can use a Contact Form on your website to allow a visitors to send you a message. Having a Contact Form on your website allows you to keep track of potential customer queries and possibly generate leads via email communication. + +## Video Tutorial + +{% embed url="https://www.youtube-nocookie.com/embed/l0X9DOwd6zk" %} +Creating a Contact Us Form using Umbraco Forms +{% endembed %} + +## Step 1: Configure the Document Types + +The first step in this tutorial is to configure the Document Types that will be used to show the Contact Form on your website. + +### Creating a Composition + +We'll start off by creating a Composition. A Composition is a stand-alone Document Type, that you can reuse on other Document Types. By creating a Composition, we are not duplicating the same properties on multiple Document Types. This is helpful when we want to use the same set of properties on multiple Document Types. + +To create a Composition, follow these steps: + +1. Go to **Settings** in the Umbraco Backoffice. +2. Expand the **Document Types** folder in the **Settings** tree. +3. Select **...** next to the **Compositions** folder. +4. Click **Create**. +5. Select **Document Type**. +6. Enter a **Name** for the **Composition**- let's call it _Title Box_. +7. Add the following fields with the respective specifications: + + | Group | Field Name | Alias | Data Type | + | --------- | ---------- | -------- | ---------- | + | Title Box | Title | title | Textstring | + | Title Box | Subtitle | subtitle | Textarea | +8. Click **Save** to save the Composition. + + ![Add Composition Properties](images/composition-properties-v14.png) + +### Creating a Contact Us Document Type with Template + +Next, we will create a Document type with template. A Document Type contains different properties for holding different types of content. The Document Type we create here will be the one used for creating the content page that will hold our Contact Form. + +To create a **Contact Us** Document Type, follow these steps: + +1. Go to **Settings** in the Umbraco Backoffice. +2. Select **...** next to the **Document Types** folder. +3. Click **Create**. +4. Select **Document Type with Template**. +5. Enter a **Name** for the **Document Type**- let's call it _Contact Us_. +6. Select **Compositions** in the top-right corner. +7. Select **Title Box**. +8. Click **Submit**. +9. Add the following fields with the respective specifications: + + | Group | Field Name | Alias | Data Type | + | ------- | ------------ | ----------- | --------------- | + | Form | Contact Form | contactForm | Form Picker | + | Content | Body Text | bodyText | Richtext Editor | +10. Click **Save**. + + ![Contact Us Document Type Properties](images/contact-us-doc-type-properties-v14.png) + +### Updating the Document Type Permission + +In the following we will update the Document Type permissions to specifically add child nodes under the root content node. + +To update the **Contact Us** Document Type permissions, follow these steps: + +1. Navigate to the Document Type used for the root content node on your website, in this case **Home** page. +2. Go to the **Structure** tab. +3. Select **Choose** in the **Allowed child node types** section. +4. Select the **Contact Us** page. + + ![Update Home Page Document Type Properties](images/update-doc-type-permissions-v14.png) +5. Click **Choose**. +6. Click **Save**. + +## Step 2: Prepare the Content Node + +This step takes you through creating the content node for your Contact Form. The content node uses the Document Type and Template to serve up an HTML page to web visitors. + +To add the content node, follow these steps: + +1. Go to **Content** in the Umbraco Backoffice. +2. Select **...** next to the **Home Page**. +3. Click **Create**. +4. Select **Contact Us**. +5. Enter the name for the content node. let's call it _Contact Us_. +6. Enter a **Title**, **Subtitle**, and **Body Text** value. These can always be updated at a later point. + + ![Enter values in Contact Us Content node](images/fill-contact-us-node-v14.png) +7. Click **Save** or **Save and Publish**. + +## Step 3: Creating the Contact Form + +In this step, we will create the Contact Form using Umbraco Forms. + +To create a form, follow these steps: + +1. Go to the **Forms** section in the Umbraco Backoffice. +2. Click **...** next to the Forms folder. +3. Click Create. +4. Select **New Form...**. +5. Enter a **Name** for the Form. Let's call it _Contact Us_. +6. _\[Optional]_ Enter a **Page Name** and **Group Name** for the Data Consent statement. Let's call it _Data Consent_. +7. Click **Add new group**. Let's call it _Information_. +8. Select **Add Question** to add a new field. +9. Enter the following details: + + | Field Name | Value | + | ------------------ | ------------ | + | Enter question | **Name** | + | Alias | fullName | + | Choose answer type | Short answer | + | Field Type | text | + | Mandatory | On | +10. Click **Submit**. +11. Repeat **steps 8-10** to add the following fields: + + | Field Name | Value | + | ------------------ | ---------------- | + | Enter question | **Company Name** | + | Choose answer type | Short answer | + + | Field Name | Value | + | ------------------ | ------------------------------ | + | Enter question | **How should we contact you?** | + | Choose answer type | Single choice | + | Prevalues Items | phone, email | + | Mandatory | On | + + | Field Name | Value | + | ------------------ | --------------------------- | + | Enter question | **Enter your phone number** | + | Choose answer type | Short answer | + | Field Type | tel | + | Validation | Validate as a number | +12. Enable **Conditions** in the _Enter your phone number_ field. +13. Click **Add Condition**. +14. Select **How should we contact you?** from the dropwdown. +15. Select **phone** in the value field. +16. Click **Submit**. +17. Repeat **steps 8-10** to add the following field: + + | Field Name | Value | + | ------------------ | ---------------------------- | + | Enter question | **Enter your email address** | + | Choose answer type | Short answer | + | Field Type | email | + | Validation | Validate as an email address | +18. Enable **Conditions** in the _Enter your email address_ field. +19. Click **Add Condition**. +20. Select **How should we contact you?** from the dropwdown. +21. Select **email** in the value field. +22. Click **Submit**. +23. Repeat **steps 8-10** to add the following field: + + | Field Name | Value | + | ------------------ | -------------------------------------------------------- | + | Enter question | **What is your role?** | + | Choose answer type | Dropdown | + | Prevalues Items | manager, developer, tester, writer, marketing specialist | + + | Field Name | Value | + | ----------------------------- | ------------------------ | + | Enter question | **Attachments (if any)** | + | Choose answer type | File upload | + | Predefined allowed file types | pdf, png, jpg, gif, txt | + + | Field Name | Value | + | ------------------ | -------------------- | + | Enter question | **Are you a Robot?** | + | Choose answer type | reCAPTCHAv2 | + | Theme | light | + | Size | normal | + | Mandatory | On | + + ![Add questions](images/contact-us-form-add-questions-v14.png) +24. Select the **Reorder** option. +25. Drag the **Data consent** group below the **Information** group. +26. Click **I am done reordering**. +27. Click **Save**. + +### Configuring the Form Workflow + +Workflows is how you determine what you happen after your form is submitted. It could be actions like sending an email or displaying a "Thank You" message. + +To configure the Form workflow, follow these steps: + +1. Select the **Submit message/ Go to page** options in the bottom of the Forms editor. +2. Enter a customised message in the **Message on Submit** field. +3. Click **Submit**. +4. Click on **Send template email to xxx@xx.dk**. +5. Enter an email address in the **Sender Email** field. +6. By default, the **Example-Template.cshtml** template will be selected in the **Email template** field. +7. Enable **Attach Uploaded Files**. +8. Click **Submit**. +9. Click **Save**. + +### Configuring the Form Settings + +In this step, you will find the information about accessing the Forms Settings and the validations available to customise your form. + +To configure the form settings, follow these steps: + +1. Navigate to the **Settings** tab in the Forms editor. +2. Scroll to find the **Validation** section. +3. Ensure that the **Mark Mandatory fields** option is checked under **Mark fields**. +4. Click **Save**. + +{% hint style="info" %} +There are multiple settings that be configured. These are all optional in relation to this tutorial. +{% endhint %} + +## Step 4: Adding the Contact Form to the Content Node + +Now that you have created your Contact Form, you can add it in the Contact Us Content Node using the _Form Picke_ Data Type. + +To add the Contact Form to the Content Node, follow these steps: + +1. Go to the **Content** section in the Umbraco Backoffice. +2. Open the **Contact Us** Page. +3. Select **Choose** in the **Contact Form** field. +4. Select the **Insert Form with Theme** option. +5. Select the **Contact Us** Form. +6. Click **Choose**. + + ![Adding the Contact Us Form](images/select-form-v14.png) +7. Click **Save** or **Save and Publish**. + +## Step 5: Additional configuration + +In the next couple of steps, we will add some additional configuration required in order for our form to work properly. + +### Configuring the reCAPTCHA value + +You need to update the configuration to include a value in the `appsettings.json` file. + +To configure the reCAPTCHA value, see the [reCAPTCHA configuration](../developer/configuration/#recaptcha-v2-field-type-configuration) article. + +### Configuring Simple Mail Transfer Protocol (SMTP) + +By adding the SMTP settings in the `appsettings.json` file, you can send out emails from your Umbraco installation. It is required in order for your form to be able to send emails on submission. + +To configure the SMTP settings, see the [Global Settings](https://docs.umbraco.com/umbraco-cms/reference/configuration/globalsettings#smtp-settings) article. + +## Step 6: Rendering the Contact Form + +In this step, we will render the values of the Contact Us Document Type in the template. + +To render the Contact Form, follow these steps: + +1. Go to the **Settings** section in the Umbraco Backoffice. +2. Open the **Contact Us** template in the **Templates** folder. +3. Enter the following code to render the form: + + ```cs + @using Umbraco.Forms.Web.Helpers; + @await Component.InvokeAsync("RenderForm", new { formId = Guid.Parse(""), FormTheme = "bootstrap3-horizontal", ExcludeScripts = "1" }) + ``` + +{% hint style="info" %} +``` +Replace **** with the ID of your form. You can find the ID in the Form's **Info** tab. +``` +{% endhint %} + +4. Select **Insert**. +5. Click **Value**. +6. Select **Document Type** from the **Choose field** dropdown. +7. Select **Contact Us**. +8. Click **Choose**. +9. Select **bodyText** from the **Contact Us** dropdown. +10. Click **Submit**. +11. Click **Save**. + +{% hint style="info" %} +For Umbraco Forms to work correctly, you need to include some client dependencies. For more information, see the [Preparing Your Frontend](../developer/prepping-frontend.md) article. +{% endhint %} + +## The final result + +Finally, it is time to view the Contact Form on the frontend. + +To view the Contact Form on the Frontend, follow these steps: + +1. Go to the **Content** section in the Umbraco Backoffice. +2. Open the **Contact Us** Page. +3. Ensure that the page is published. +4. Go to the **Info** tab. +5. Click on the Published link in the **Links** section. + +You now have a full-fledged Contact Form ready to be used on your website. diff --git a/16/umbraco-forms/tutorials/creating-a-multipage-form.md b/16/umbraco-forms/tutorials/creating-a-multipage-form.md new file mode 100644 index 00000000000..629b74d07fc --- /dev/null +++ b/16/umbraco-forms/tutorials/creating-a-multipage-form.md @@ -0,0 +1,189 @@ +# Creating a Multi-Page Form + +In this tutorial, you will learn how to create a multi-page form using Umbraco Forms. Multi-page forms are particularly useful when you need to collect detailed information from users in a structured and user-friendly way. + +Multi-page forms are ideal for use cases such as event registration, job applications, booking a meeting, and so on. + +## Prerequisites + +* [Umbraco CMS Installation](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/install) +* [Umbraco Forms Package](../installation/install.md) +* Pre-built Website including a **Document Type** with the **Form Picker** Data Type. + +## Log in to the Umbraco Backoffice + +1. Log in to the Umbraco backoffice. +2. Go to the **Forms** section. + +## Create a New Form + +1. Click **+** next to the Forms folder. +2. Select **New Form**. + +![New Form Creation](images/create-form.png) + +3. Enter a **Name** for the form. For example: _Book a Meeting_. +4. Click **Save**. + +## Set up the First Page of the Form + +Let us begin by adding some fields to the first page of the form. By default, the **Data Consent** field is already available, and we will call this group **Data Consent**. + +To create a new group: + +1. Click **Add new group**. +2. **Enter the Name** of the group. For example: _Personal Information_. +3. Click **Add question**. +4. Select **Short answer** as the field type. +5. **Enter a Name** for the field type. For example, _First Name_. +6. Select **Text** as the **Field Type** from the drop-down list. +7. Mark the field as **Mandatory**. +8. Click **Submit**. +9. Click **Save**. + +Similarly, you can also add other relevant fields such as last name or email based on your requirements. + +For this tutorial, the following fields are added with the respective specifications: + +| Field Name | Data Type | Field Type | +| ------------- | ------------ | ---------- | +| Surname | Short answer | text | +| Age | Short answer | number | +| Country | Short answer | text | +| Phone number | Short answer | tel | +| Email address | Short answer | email | + +If you wish to reorder your fields, click **Reorder**. + +![Personal Information Questions on the First Page](images/first-page-of-form.png) + +## Create the Second Page + +To create a multi-page form, you need to add more pages: + +1. Click **Add new page** to create the second page of your form. +2. **Enter a Name** for this page. For example: _Company Information_. +3. Click **Add question**. +4. Select **Short answer** as the field type. +5. **Enter a Name** for the field type. For example, _Company Name_. +6. Provide a **Default Value**. For example, _Enter the name of your company_. +7. Click **Submit**. +8. Click **Save**. + +![Default Value displayed](images/company-information.png) + +Similarly, you can also add other relevant fields based on your requirements. + +### Add Conditional Logic + +Umbraco Forms allows you to customize the flow of your multi-page form. You can add conditional logic to control which questions appear based on user inputs. + +To add conditions, follow these steps: + +1. Click **Add question**. +2. Select **Single choice** as the field type. +3. **Enter a Name** for the field type. For example, _Do you work with Umbraco_. +4. Enter the **Value** and **Caption** in the **Options** field. + + For this tutorial, the following values are added: + + * Yes + * No + +![Values in the Options Field](images/prevalue-fields.png) + +5. Mark the field as **Mandatory**. +6. Click **Submit**. +7. Click **Save**. +8. Repeat steps 1-4 to create a conditional question titled: _If yes, how many years?_ +9. Enter the **Value** and **Caption** in the **Options** field. + + For this tutorial, the following values are added: + + * 1-5 years + * 5-10 years + * 10+ years + +![Conditional Question Values in the Options Field](images/conditional-question-part-1.png) + +10. Enable **Conditions**. +11. Set the parameters for the condition as follows: + * **Show** this field if **all** of the following match: + * Question: **Do you work with Umbraco?** + * Condition: **is** + * Value: **Yes** + +![Values for adding a Condition](images/conditional-question-part-2.png) + +12. Click **Submit**. +13. Click **Save**. + +![Company information Questions on the Second Page](images/page-2-details.png) + +## Create the Final Page + +1. Click **Add new page** to create the final page of your form. +2. **Enter a Name** for this page. For example: _Products_. +3. Click **Add question**. +4. Select **Multiple choice** as the field type. +5. **Enter a Name** for the field type. For example, _Select the products you are interested in_. +6. Enter the **Value** and **Caption** in the **Options** field. + + For this tutorial, the following values are added: + + * Umbraco CMS + * Umbraco Cloud + * Umbraco Deploy + * Umbraco Heartcore + * Umbraco Forms + * Umbraco Commerce + * Umbraco Workflow + +![Multiple Values in the Option Field](images/multiple-choice.png) + +7. Click **Submit**. +8. Click **Save**. + +![Products Selection Question on the Final Page](images/Final-page.png) + +## Embed the Form on a Web Page + +Once you are satisfied with your multi-page form, it is time to embed it on your website. + +To display the form on the website, follow these steps: + +1. Go to the **Content** section. +2. Click **+** next to the parent page of the website. +3. Select the Document Type. + +![Pick a Document Type](images/pick-document-type.png) + +4. **Enter a Name** for the page. For example, _Book a Meeting!_ +5. Select the **Book a Meeting** form using the _Form Picker_. +6. Click **Save and Publish**. + +![New Page created in the Content Section](images/Form-Content-section.png) + +## Customize Form Settings + +If you wish to customize the Form Settings, see the [Form Settings](../editor/creating-a-form/form-settings.md) article. + +## Rendering the Form on the Frontend + +For Umbraco Forms to work correctly, you need to include some client dependencies. For more information, see the [Preparing Your Frontend](../developer/prepping-frontend.md) article. + +To render the Form on the frontend, see the [Rendering Forms](../developer/rendering-forms.md) article. + +## Testing the Form + +1. Go to the **Info** workspace view of the _Book a Meeting!_ page. +2. Click on the Published link in the **Links** section. +3. Fill out the form to see how it functions. +4. Submit the form to ensure it redirects to a Thank You page. +5. Go to the **Forms** section in the Backoffice. +6. Navigate to the **Book a Meeting** Form. +7. Click on the **Entries** tab and verify that the data is captured. + +![Form Data in the Entries tab](images/form-data-entry.png) + +You have successfully created a multi-page form with conditional logic in Umbraco Forms. By using multi-page forms, you have made complex data entry much simpler and more user-friendly. This not only improves the experience for your users but also makes your forms more efficient and manageable. diff --git a/16/umbraco-forms/tutorials/images/Final-page.png b/16/umbraco-forms/tutorials/images/Final-page.png new file mode 100644 index 00000000000..d418c911578 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/Final-page.png differ diff --git a/16/umbraco-forms/tutorials/images/Form-Content-section.png b/16/umbraco-forms/tutorials/images/Form-Content-section.png new file mode 100644 index 00000000000..5b60689923d Binary files /dev/null and b/16/umbraco-forms/tutorials/images/Form-Content-section.png differ diff --git a/16/umbraco-forms/tutorials/images/company-information.png b/16/umbraco-forms/tutorials/images/company-information.png new file mode 100644 index 00000000000..8208c9af31e Binary files /dev/null and b/16/umbraco-forms/tutorials/images/company-information.png differ diff --git a/16/umbraco-forms/tutorials/images/composition-properties-v14.png b/16/umbraco-forms/tutorials/images/composition-properties-v14.png new file mode 100644 index 00000000000..19ee86be699 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/composition-properties-v14.png differ diff --git a/16/umbraco-forms/tutorials/images/composition-properties.png b/16/umbraco-forms/tutorials/images/composition-properties.png new file mode 100644 index 00000000000..3bf730fba7e Binary files /dev/null and b/16/umbraco-forms/tutorials/images/composition-properties.png differ diff --git a/16/umbraco-forms/tutorials/images/conditional-question-part-1.png b/16/umbraco-forms/tutorials/images/conditional-question-part-1.png new file mode 100644 index 00000000000..ca2b9b83d18 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/conditional-question-part-1.png differ diff --git a/16/umbraco-forms/tutorials/images/conditional-question-part-2.png b/16/umbraco-forms/tutorials/images/conditional-question-part-2.png new file mode 100644 index 00000000000..eabde810d2d Binary files /dev/null and b/16/umbraco-forms/tutorials/images/conditional-question-part-2.png differ diff --git a/16/umbraco-forms/tutorials/images/contact-us-doc-type-properties-v14.png b/16/umbraco-forms/tutorials/images/contact-us-doc-type-properties-v14.png new file mode 100644 index 00000000000..307f0aca971 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/contact-us-doc-type-properties-v14.png differ diff --git a/16/umbraco-forms/tutorials/images/contact-us-doc-type-properties.png b/16/umbraco-forms/tutorials/images/contact-us-doc-type-properties.png new file mode 100644 index 00000000000..efe005b1c57 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/contact-us-doc-type-properties.png differ diff --git a/16/umbraco-forms/tutorials/images/contact-us-form-add-questions-v14.png b/16/umbraco-forms/tutorials/images/contact-us-form-add-questions-v14.png new file mode 100644 index 00000000000..e0d4cf1bd10 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/contact-us-form-add-questions-v14.png differ diff --git a/16/umbraco-forms/tutorials/images/contact-us-form-add-questions.png b/16/umbraco-forms/tutorials/images/contact-us-form-add-questions.png new file mode 100644 index 00000000000..a100b2d4426 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/contact-us-form-add-questions.png differ diff --git a/16/umbraco-forms/tutorials/images/create-form.png b/16/umbraco-forms/tutorials/images/create-form.png new file mode 100644 index 00000000000..b735f9d1e9f Binary files /dev/null and b/16/umbraco-forms/tutorials/images/create-form.png differ diff --git a/16/umbraco-forms/tutorials/images/creating-a-composition.png b/16/umbraco-forms/tutorials/images/creating-a-composition.png new file mode 100644 index 00000000000..c616f49f0b9 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/creating-a-composition.png differ diff --git a/16/umbraco-forms/tutorials/images/fill-contact-us-node-v14.png b/16/umbraco-forms/tutorials/images/fill-contact-us-node-v14.png new file mode 100644 index 00000000000..fc5a30263f1 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/fill-contact-us-node-v14.png differ diff --git a/16/umbraco-forms/tutorials/images/fill-contact-us-node.png b/16/umbraco-forms/tutorials/images/fill-contact-us-node.png new file mode 100644 index 00000000000..5473a8c2589 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/fill-contact-us-node.png differ diff --git a/16/umbraco-forms/tutorials/images/first-page-of-form.png b/16/umbraco-forms/tutorials/images/first-page-of-form.png new file mode 100644 index 00000000000..5e0c6c742bd Binary files /dev/null and b/16/umbraco-forms/tutorials/images/first-page-of-form.png differ diff --git a/16/umbraco-forms/tutorials/images/form-data-entry.png b/16/umbraco-forms/tutorials/images/form-data-entry.png new file mode 100644 index 00000000000..0d66f6f1847 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/form-data-entry.png differ diff --git a/16/umbraco-forms/tutorials/images/multiple-choice.png b/16/umbraco-forms/tutorials/images/multiple-choice.png new file mode 100644 index 00000000000..d4abe0b3ed1 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/multiple-choice.png differ diff --git a/16/umbraco-forms/tutorials/images/page-2-details.png b/16/umbraco-forms/tutorials/images/page-2-details.png new file mode 100644 index 00000000000..4285fc810be Binary files /dev/null and b/16/umbraco-forms/tutorials/images/page-2-details.png differ diff --git a/16/umbraco-forms/tutorials/images/pick-document-type.png b/16/umbraco-forms/tutorials/images/pick-document-type.png new file mode 100644 index 00000000000..6d3f1b2f9be Binary files /dev/null and b/16/umbraco-forms/tutorials/images/pick-document-type.png differ diff --git a/16/umbraco-forms/tutorials/images/prevalue-fields.png b/16/umbraco-forms/tutorials/images/prevalue-fields.png new file mode 100644 index 00000000000..f713a9f6212 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/prevalue-fields.png differ diff --git a/16/umbraco-forms/tutorials/images/select-form-v14.png b/16/umbraco-forms/tutorials/images/select-form-v14.png new file mode 100644 index 00000000000..078eb3b06a9 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/select-form-v14.png differ diff --git a/16/umbraco-forms/tutorials/images/select-form.png b/16/umbraco-forms/tutorials/images/select-form.png new file mode 100644 index 00000000000..888e8f1e48e Binary files /dev/null and b/16/umbraco-forms/tutorials/images/select-form.png differ diff --git a/16/umbraco-forms/tutorials/images/update-doc-type-permissions-v14.png b/16/umbraco-forms/tutorials/images/update-doc-type-permissions-v14.png new file mode 100644 index 00000000000..548a86d93fe Binary files /dev/null and b/16/umbraco-forms/tutorials/images/update-doc-type-permissions-v14.png differ diff --git a/16/umbraco-forms/tutorials/images/update-doc-type-permissions.png b/16/umbraco-forms/tutorials/images/update-doc-type-permissions.png new file mode 100644 index 00000000000..a26f091fc53 Binary files /dev/null and b/16/umbraco-forms/tutorials/images/update-doc-type-permissions.png differ diff --git a/16/umbraco-forms/tutorials/overview.md b/16/umbraco-forms/tutorials/overview.md new file mode 100644 index 00000000000..22071b01561 --- /dev/null +++ b/16/umbraco-forms/tutorials/overview.md @@ -0,0 +1,16 @@ +# Overview + +In this section, you can find a set of different tutorials to use when creating and working with Umbraco Forms. + +{% hint style="info" %} +This section is a work in progress. + +Do you have suggestions for or wishes for tutorials on Umbraco Forms? +Let us know using the [UmbracoDocs GitHub Issue Tracker](https://github.com/umbraco/UmbracoDocs/issues). +{% endhint %} + +## Tutorials + +### [Creating a Contact Form](creating-a-contact-form.md) + +Learn how to create a Contact Form and add it to your website. \ No newline at end of file diff --git a/16/umbraco-forms/upgrading/manualupgrade.md b/16/umbraco-forms/upgrading/manualupgrade.md new file mode 100644 index 00000000000..dfd3d5c1362 --- /dev/null +++ b/16/umbraco-forms/upgrading/manualupgrade.md @@ -0,0 +1,33 @@ +# Upgrading Umbraco Forms + +This article shows how to manually upgrade Umbraco Forms to run the latest version. + +When upgrading Umbraco Forms, be sure to also consult the [version specific upgrade notes](version-specific.md) to learn about potential breaking changes and common pitfalls. + +## Get the latest version of Umbraco Forms + +To get the latest version of Umbraco Forms, you can upgrade using: + +* [NuGet](manualupgrade.md#nuget) +* [Visual Studio](manualupgrade.md#visual-studio) + +### NuGet + +* NuGet installs the latest version of the package when you use the `dotnet add package Umbraco.Forms` command unless you specify a package version: `dotnet add package Umbraco.Forms --version ` +* After you have added a package reference to your project by executing the `dotnet add package Umbraco.Forms` command in the directory that contains your project file, run `dotnet restore` to install the package. + +### Visual Studio + +1. Go to `Tools` -> `NuGet Package Manager` -> `Manage NuGet Packages for Solution...` in Visual Studio, to upgrade your Forms: +2. Select **Umbraco.Forms**. +3. Select the latest version from the **Version** drop-down and click **Install**. + +
NuGet Package Manager
+ +4. When the command completes, open the **.csproj** file to make sure the package reference is updated: + +```xml + + + +``` diff --git a/16/umbraco-forms/upgrading/migration-ids.md b/16/umbraco-forms/upgrading/migration-ids.md new file mode 100644 index 00000000000..3aef9f3f405 --- /dev/null +++ b/16/umbraco-forms/upgrading/migration-ids.md @@ -0,0 +1,26 @@ +--- +hidden: true +--- + +# Migration IDs + +A unique **migration ID** is generated for each Umbraco Forms upgrade that requires a migration. The migration IDs are all listed in this article. + +| Migration ID | Introduced In Version | Description | +|--------------------------------------|-----------------------|------------------------------------------------------------------------------------| +| 7c7bc5ee-4c5b-42dc-9576-5ce6dfbddb8e | 10.0.0 | Installs Umbraco Forms. | +| 9f7e6fe6-bbd5-4b2b-8820-e9e0e36cc74c | 10.1.0 | Adds Culture column to Records table. | +| 1a8f0d04-9396-40a2-9423-39fc9ae3828f | 10.1.0 | Adds a Record Workflow Audit table. | +| 6e692c5d-c670-4c34-af17-28d8dbf0dcd2 | 10.1.0 | Adds an ExecutionStage column to the Record Workflow Audit table. | +| 5d84fee1-388c-4e5f-b98c-1e66947278f1 | 10.1.0 | No operation migration. | +| 22df962a-ae26-4bdd-b8fd-0513a9c636bf | 10.5.2/12.1.2 | Ensures the presence of an index on the FolderKey column in the Forms table. | +| c3e657f6-3ae7-4ee9-b442-01702a41de9a | 12.2.0/13.0.0 | Adds a relation between content and forms. | +| e0290a40-91c9-4acb-a7ca-d312037078f2 | 12.2.0/13.0.0 | Adds a NodeId column to Forms table | +| 6f0eb771-6690-4b53-870a-f7dbb2785cac | 12.2.0/13.0.0 | Populates the NodeId column in the Forms table. | +| 44949e12-e4ef-42c0-949b-67286b946fe0 | 12.2.0/13.0.0 | No operation migration. | +| 773ae769-00b7-4429-b7d5-de0fda0b4217 | 12.2.1/13.0.1 | Ensures the consistent key is used for the relation type between content and forms.| +| 55d53d2e-f795-42fb-9e77-8edfc6eed4aa | 13.2.0 | Adds an AdditionalData column to the Records table. | +| 1fff8b7b-48e7-450a-80b1-7df628508b27 | 13.3.0 | Adds delete entries permissions field to the security tables | +| 7e170195-cab7-48ca-98c7-bbcbd5cfda95 | 13.4.0 | Adds created and updated by columns to the entity tables | +| c74223ed-a554-4a14-a1f0-0477dce01ad6 | 14.0.0 | Updates the form picker property editor UI alias. | +| a5ffa9a7-ca77-4a7c-a1e4-f32e25cde758 | 14.1.0 | Adds an AdditionalData column to the Records table. | diff --git a/16/umbraco-forms/upgrading/version-specific.md b/16/umbraco-forms/upgrading/version-specific.md new file mode 100644 index 00000000000..6336c856ed6 --- /dev/null +++ b/16/umbraco-forms/upgrading/version-specific.md @@ -0,0 +1,57 @@ +--- +description: >- + Version specific documentation for upgrading to new major versions of Umbraco + Forms. +--- + +# Version Specific Upgrade Notes + +This article provides specific upgrade documentation for migrating to Umbraco Forms version 15. + +{% hint style="info" %} +If you are upgrading to a minor or patch version, you can find the details about the changes in the [Release Notes](../release-notes.md) article. +{% endhint %} + +## Version Specific Upgrade Notes History + +Version 15 of Umbraco Forms has a minimum dependency on Umbraco CMS core of `15.0.0`. It runs on .NET 9. + +#### **Breaking changes** + +Version 15 contains a number of breaking changes. If you do run into any, they should be straightforward to adjust and recompile. + +For reference, the full details are listed here: + +#### **Configuration** + +* The setting `FieldSettings:Recaptcha3:ShowFieldValidation` has a new default of `true`. +* The setting `Options:EnableMultiPageFormSettings` has a new default of `true`. +* The setting `FormDesign:RemoveProvidedEmailTemplate` has been removed (as adding and removing email templates can be more consistently handled using [`EmailTemplateCollection`](../developer/themes.md#removing-the-default-email-template)). + +#### **Asynchronous Methods** + +* `IFieldPreValueSourceType.GetPrevalues` (and the abstract method of the same name in `FieldPreValueSourceType`) is now an asynchronous method. It has an `Async` suffix. +* `IExportType.ExportRecords` and `ExportToFile` are now asynchronous methods and have `Async` suffixes. + +#### **Code** + +* Parameters in the `FileUpload` constructor were renamed. +* Obsolete constructors in the classes `SendRazorEmail`, `EntryAcceptedDtoFactory`, `FormDtoFactory`, `RenderFormViewComponent`, `GetValuesByKeyPrevalueSourceController`, and `UmbracoFormsController` were removed. +* The obsolete overload on `FormFileExtensions.IsFileTypeAllowed` was removed. +* The purposes defined for uses of `IDataProtector` were renamed to have a common prefix. +* Unused fields `Field.Placeholder` and `FormFieldDto.Placeholder` were removed. +* Unused `ServerVariablesParsingHandler` was removed. +* Default implementations on the interfaces `IWorkflowFactory`, `IWorkflowRepository`, `IWorkflowService` were removed. +* Obsolete methods on `PlaceholderParsingService` were removed. +* Method overloads without optional parameters on `FormDtoFactory`, `EntryAcceptedDtoFactory`, `IFormRenderingService`, `IPlaceholderParsingService`, `WorkflowType`, `DictionaryExtensions` and `StringExtensions` were removed. +* Base64 encoding was removed when storing and retrieving form state. +* The obsolete overload of `FormViewModel.Build` was removed. +* The `UmbracoPreValuesReadOnly` constructor now has an additional parameter. +* Due to the introduction of asynchronous behavior to `IFieldPreValueSourceType.GetPrevalues`, `FormViewModel.Build` is now also asynchronous. +* `FormsTreeRequirement` and related classes were removed. +* `FormRenderingService` and `FormThemeResolver` was made internal. +* Default implementations on `IFormThemeResolver` were removed. + +## Legacy version specific upgrade notes + +You can find the version specific upgrade notes for versions out of support in the [Legacy documentation on GitHub](https://github.com/umbraco/UmbracoDocs/blob/umbraco-eol-versions/11/umbraco-forms/installation/version-specific.md). diff --git a/16/umbraco-ui-builder/.gitbook.yaml b/16/umbraco-ui-builder/.gitbook.yaml new file mode 100644 index 00000000000..534ade5cdbe --- /dev/null +++ b/16/umbraco-ui-builder/.gitbook.yaml @@ -0,0 +1,7 @@ +root: ./ + +​structure: + readme: README.md + summary: SUMMARY.md + +redirects: diff --git a/16/umbraco-ui-builder/README.md b/16/umbraco-ui-builder/README.md new file mode 100644 index 00000000000..ca993a7050a --- /dev/null +++ b/16/umbraco-ui-builder/README.md @@ -0,0 +1,29 @@ +--- +description: A guide to using Umbraco UI Builder for creating custom backoffice UIs. +--- + +# Umbraco UI Builder Documentation + +Umbraco UI Builder is a tool for creating custom Backoffice User Interfaces (UIs) in Umbraco using a fluent API. + +![Example Umbraco UI Builder UI](images/listview.png) + +If you have a custom data store that you want to manage within Umbraco, you can use Umbraco UI Builder. With few lines of code, you can configure a custom administration UI, and reuse many core components with a consistent look and feel. + +With Umbraco UI Builder, custom backoffice integrations can now be set up in minutes rather than days. + +## Using The Documentation + +This documentation is intended for **developers** with a basic understanding of Umbraco and C#/MVC principles. + +If you are new to Umbraco UI Builder, it is recommended to start with the [Getting Started](getting-started/requirements.md) section. This section covers system requirements and installation instructions. + +Once you have Umbraco UI Builder installed, explore the [Guides](guides/creating-your-first-integration.md) section. This section provides a quick-start example on configuring Umbraco UI Builder. + +Use the main menu to explore features in detail and navigate directly to topics of interest. + +For additional resources and best practices, visit the [Miscellaneous](miscellaneous/conventions.md) section. + +## Getting Help + +If you need assistance, refer to our support channels for help and troubleshooting. diff --git a/16/umbraco-ui-builder/SUMMARY.md b/16/umbraco-ui-builder/SUMMARY.md new file mode 100644 index 00000000000..f52e3e3a763 --- /dev/null +++ b/16/umbraco-ui-builder/SUMMARY.md @@ -0,0 +1,90 @@ +# Table of contents + +* [Umbraco UI Builder Documentation](README.md) +* [Known Issues](known-issues.md) +* [Release Notes](release-notes.md) + +## Getting Started + +* [Requirements](getting-started/requirements.md) +* [Installing Umbraco UI Builder](getting-started/installation.md) +* [Licensing](getting-started/licensing-model.md) +* [Configuration](getting-started/configuration.md) +* [User Interface](getting-started/user-interface.md) + +## Upgrading + +* [Upgrading Umbraco UI Builder](upgrading/upgrade.md) +* [Version Specific Upgrade Notes](upgrading/version-specific.md) +* [Migrate from Konstrukt to Umbraco UI Builder](upgrading/migrating-from-konstrukt-to-umbraco-ui-builder.md) + +## How-to Guides + +* [Creating your First Integration](guides/creating-your-first-integration.md) + +## Areas + +* [Overview](areas/overview.md) +* [Sections](areas/sections.md) + * [Summary Dashboards](areas/summary-dashboards.md) +* [Trees](areas/trees.md) + * [Folders](areas/folders.md) +* [Dashboards](areas/dashboards.md) +* [Context Apps](areas/context-apps.md) + +## Collections + +* [Overview](collections/overview.md) +* [The Basics](collections/the-basics.md) +* [List Views](collections/list-views.md) + * [Field Views](collections/field-views.md) +* [Editors](collections/editors.md) +* [Child Collections](collections/child-collections.md) + * [Child Collection Groups](collections/child-collection-groups.md) + * [Retrieve Child Collections](collections/retrieve-child-collections.md) +* [Related Collections](collections/related-collections.md) +* [Entity Identifier Converters](collections/entity-identifier-converters.md) + +## Searching + +* [Overview](searching/overview.md) +* [Searchable Properties](searching/searchable-properties.md) + +## Filtering + +* [Overview](filtering/overview.md) +* [Global Filters](filtering/global-filters.md) +* [Data Views](filtering/data-views.md) + * [Data Views Builders](filtering/data-views-builders.md) +* [Filterable Properties](filtering/filterable-properties.md) + +## Actions + +* [Overview](actions/overview.md) +* [The Basics](actions/the-basics.md) +* [Action Visibility](actions/action-visibility.md) +* [Inbuilt Actions](actions/inbuilt-actions.md) + +## Cards + +* [Overview](cards/overview.md) +* [Count Cards](cards/count-cards.md) +* [Custom Cards](cards/custom-cards.md) + +## Property Editors + +* [Overview](property-editors/overview.md) +* [Entity Picker](property-editors/entity-picker.md) + +## Advanced + +* [Virtual Sub Trees](advanced/virtual-sub-trees.md) +* [Encrypted Properties](advanced/encrypted-properties.md) +* [Value Mappers](advanced/value-mappers.md) +* [Repositories](advanced/repositories.md) +* [Events](advanced/events.md) + +## Miscellaneous + +* [Conventions](miscellaneous/conventions.md) +* [Umbraco Aliases](miscellaneous/umbraco-aliases.md) diff --git a/16/umbraco-ui-builder/actions/action-visibility.md b/16/umbraco-ui-builder/actions/action-visibility.md new file mode 100644 index 00000000000..ce9e31a1234 --- /dev/null +++ b/16/umbraco-ui-builder/actions/action-visibility.md @@ -0,0 +1,130 @@ +--- +description: Controlling the visibility of actions in Umbraco UI Builder. +--- + +# Action Visibility + +By default, actions are hidden in the UI. You must define when and where an action should appear. This can be done either at the action definition level or when registering it in the collection config. + +## Controlling Default Action Visibility + +To define the default visibility of an action, override the `IsVisible` method of the `Action<>` base class. + +````csharp +// Example +public class MyAction : Action +{ + ... + public override bool IsVisible(ActionVisibilityContext ctx) + { + return ctx.ActionType == ActionType.Bulk + || ctx.ActionType == ActionType.Row; + } + ... +} +```` + +The `IsVisible` method receives an `ActionVisibilityContext`. You can use this context to decide whether the action should be displayed. Return `true` to show it, or `false` to hide it. For more information, see the [Action visibility context](#action-visibility-context) section below. + +## Overriding Action Visibility + +You can override an action's visibility in the [Collections](../collections/overview.md) settings. + +### Using the `AddAction()` Method + +Adds an action of the given type to the collection with the specified visibility. + +#### Method Syntax + +```cs +AddAction(Lambda actionConfig = null) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddAction(actionConfig => actionConfig + .SetVisibility(x => x.ActionType == ActionType.Bulk + || x.ActionType == ActionType.Row) +); +```` + +### Using the `AddAction(Type actionType, Lambda actionConfig = null)` Method + +Adds an action of the given type to the collection by specifying the action type dynamically using `Type` instead of a generic type. + +#### Method Syntax + +```cs +AddAction(Type actionType, Lambda actionConfig = null) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddAction(typeof(ExportMenuAction), actionConfig => actionConfig + .SetVisibility(x => x.ActionType == ActionType.Bulk + || x.ActionType == ActionType.Row) +); +```` + +### Using the `AddAction(IAction action, Lambda actionConfig = null)` Method + +Adds the already defined action instance to the collection with the specified visibility. + +#### Method Syntax + +```cs +AddAction(IAction action, Lambda actionConfig = null) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddAction(action, actionConfig => actionConfig + .SetVisibility(x => x.ActionType == ActionType.Bulk + || x.ActionType == ActionType.Row) +); +```` + +## Action Visibility Context + +When controlling the visibility of an action, you will receive an `ActionVisibilityContext` object. This context allows you to decide whether to show the action. The context contains two key pieces of information for this decision. + +### ActionType + +The `ActionType` property is an enum property that defines which area of the UI wants to access the action. This property helps determine where the action is displayed. + +#### ContainerMenu + +The `ContainerMenu` action type displays the action in both the collection tree and its list view actions menu. + +![Container Menu](../images/container_actions_menu.png) + +#### EntityMenu + +The `EntityMenu` action type shows the action in the collection editor UI's actions menu. + +![Entity Menu](../images/entity_actions_menu.png) + +#### Bulk + +The `Bulk` action type displays the action in the collection list view bulk actions menu. + +![Bulk Actions](../images/bulk_actions_menu.png) + +#### Row + +The `Row` action type shows the action in the collection list view action row menu. + +![Row Actions](../images/row_actions_menu.png) + +#### Save + +The `Save` action type displays the action as a sub-button in the entity editor’s save button. All `Save` actions trigger a save before executing. Their labels are prefixed with `Save & [Action Name]`. + +![Save Actions](../images/save_actions_menu.png) + +### UserGroups + +The `UserGroups` collection contains a list of `IReadOnlyUserGroup` objects for the current logged-in backoffice user. This allows you to control action visibility for members of specific user groups. diff --git a/16/umbraco-ui-builder/actions/inbuilt-actions.md b/16/umbraco-ui-builder/actions/inbuilt-actions.md new file mode 100644 index 00000000000..92d76f03a22 --- /dev/null +++ b/16/umbraco-ui-builder/actions/inbuilt-actions.md @@ -0,0 +1,19 @@ +--- +description: A list of inbuilt actions that come with Umbraco UI Builder. +--- + +# Inbuilt Actions + +Umbraco UI Builder provides different inbuilt actions that you can use right away. + +## ExportEntityAction + +**Namespace:** `Umbraco.UIBuilder.Infrastructure.Configuration.Actions` + +Exports entity data to a Comma-Separated Values (CSV) file. It converts all properties into column headings and renders each entity's property values in rows. + +## ImportEntityAction + +**Namespace:** `Umbraco.UIBuilder.Infrastructure.Configuration.Actions` + +Imports data from a Comma-Separated Values (CSV) file. This action matches column headings with entity properties and maps row values to an entity. diff --git a/16/umbraco-ui-builder/actions/overview.md b/16/umbraco-ui-builder/actions/overview.md new file mode 100644 index 00000000000..a26fc2db2c4 --- /dev/null +++ b/16/umbraco-ui-builder/actions/overview.md @@ -0,0 +1,15 @@ +--- +description: Learn how to configure actions in Umbraco UI Builder. +--- + +# Actions + +Actions allow you to perform custom tasks on collections and their entities from different areas in the UI. For Example: menu actions, bulk actions, or individual table row actions. + +![Bulk Actions UI](../images/bulk_actions.png) + +To get started with actions, check out the basics: + +{% content-ref url="the-basics.md" %} +[the-basics.md](the-basics.md) +{% endcontent-ref %} diff --git a/16/umbraco-ui-builder/actions/the-basics.md b/16/umbraco-ui-builder/actions/the-basics.md new file mode 100644 index 00000000000..089a7d0b3c7 --- /dev/null +++ b/16/umbraco-ui-builder/actions/the-basics.md @@ -0,0 +1,139 @@ +--- +description: Configuring actions in Umbraco UI Builder. +--- + +# The Basics + +Actions allow you to add custom functionality to Umbraco UI Builder without creating custom UI elements. By providing an action to run, Umbraco UI Builder can trigger actions from different UI locations. + +## Defining an Action + +To define an action, create a class that inherits from the base class `Action<>` and configure it as shown below: + +````csharp +// Example +public class MyAction : Action +{ + public override string Icon => "icon-settings"; + public override string Alias => "myaction"; + public override string Name => "My Action"; + public override bool ConfirmAction => true; + + public override ActionResult Execute(string collectionAlias, object[] entityIds) + { + // Perform operation here... + } +} +```` + +### Configuration Options + +| Option | Description | Required | +|:-------------:|:--------------------------------------------------------------------------:|----------| +| Name | The name of the action. | Yes | +| Alias | A unique alias for the action. | Yes | +| Icon | An icon to display next to the action’s name. | Yes | +| Execute | The method that runs for the given list of entities. | Yes | +| ConfirmAction | Set whether a confirm dialog should display before performing this action. | No | + +The generic argument specifies the return type for the action. For more details, see the [Controlling the Action Result](#controlling-the-action-result) section below. + +{% hint style="info" %} +You can use dependency injection to inject any services required for your specific task. It's recommended to inject `Lazy` implementations of the required services to ensure they are resolved only when needed. +{% endhint %} + +## Controlling the Action Result + +By default, actions return an `ActionResult`, but you can return other types by changing the `Action<>` generic argument. + +* **`ActionResult`** - Standard result with a boolean `Success` value. +* **`FileActionResult`** - Returns a file stream or bytes and triggers a download dialog. + +## Capturing Settings for an Action + +Sometimes, you need to collect user input before performing an action. You can achieve this by using the `Action<>` base class with an additional `TSetting` generic argument. + +````csharp +// Example +public class MyAction : Action +{ + public override string Icon => "icon-settings"; + public override string Alias => "myaction"; + public override string Name => "My Action"; + public override bool ConfirmAction => true; + + public override void Configure(SettingsConfigBuilder settingsConfig) + { + settingsConfig.AddFieldset("General", fieldsetConfig => fieldsetConfig + .AddField(s => s.RecipientName).SetLabel("Recipient Name") + .AddField(s => s.RecipientEmail).SetLabel("Recipient Email")); + } + + public override ActionResult Execute(string collectionAlias, object[] entityIds, MyActionSettings settings) + { + // Perform operation here... + } +} + +public class MyActionSettings +{ + public string RecipientName { get; set; } + public string RecipientEmail { get; set; } +} +```` + +By implementing this base class, you must also implement the `Configure` method which accepts a `SettingsConfigBuilder<>` parameter. Use this builder to define the settings dialog UI and how it maps to the settings type. You can create fieldsets and fields with the same fluent API as in the [Collection Editors](../collections/editors.md#adding-a-fieldset-to-a-tab) section. + +Additionally, the `Execute` method now accepts an extra `settings` parameter, which Umbraco UI Builder will pre-populate with the user-entered values. You can adjust the action's behavior based on this data. + +## Adding an Action to a Collection + +Actions are added via the [Collections](../collections/overview.md) settings. + +### Using the `AddAction()` Method + +Adds an action of the specified type to the collection. + +#### Method Syntax + +```cs +AddAction() : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddAction(); +```` + +#### Using the `AddAction(Type actionType)` Method + +Adds an action of the specified type to the collection. + +#### Method Syntax + +```cs +AddAction(Type actionType) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddAction(actionType); +```` + +#### Using the `AddAction(IAction action)` Method + +Adds the given action to the collection. + +#### Method Syntax + +```cs +AddAction(IAction action) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddAction(action); +```` diff --git a/16/umbraco-ui-builder/advanced/encrypted-properties.md b/16/umbraco-ui-builder/advanced/encrypted-properties.md new file mode 100644 index 00000000000..da6d659bd25 --- /dev/null +++ b/16/umbraco-ui-builder/advanced/encrypted-properties.md @@ -0,0 +1,29 @@ +--- +description: Configuring and using encrypted properties in Umbraco UI Builder to securely store sensitive data. +--- + +# Encrypted Properties + +Umbraco UI Builder allows encrypting properties to store sensitive information securely. When a property is marked as encrypted, its value is automatically encrypted before storage and decrypted upon retrieval. + +{% hint style="info" %} +Umbraco UI Builder uses the `IDataProtectionProvider` instance registered in the DI container for encryption and decryption. To modify the encryption algorithm, replace the `IDataProtectionProvider` instance in the DI container. +{% endhint %} + +## Defining Encrypted Properties + +### Using the `AddEncryptedProperty()` Method + +Encrypts the specified property. The property must be of type `String`. The value is encrypted before storage and decrypted when retrieved. + +#### Method Syntax + +```csharp +AddEncryptedProperty(Lambda encryptedPropertyExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddEncryptedProperty(p => p.Secret); +```` diff --git a/16/umbraco-ui-builder/advanced/events.md b/16/umbraco-ui-builder/advanced/events.md new file mode 100644 index 00000000000..922b234443a --- /dev/null +++ b/16/umbraco-ui-builder/advanced/events.md @@ -0,0 +1,172 @@ +--- +description: Configuring event handlers in Umbraco UI Builder. +--- + +# Events + +Umbraco UI Builder triggers different notification events during operation, allowing customization of default behavior. + +## Registering Event Handlers + +Umbraco UI Builder follows the [Umbraco Notification mechanism](../../umbraco-cms/fundamentals/code/subscribing-to-notifications.md) for event registration. + +Define a notification event handler for the target event: + +```csharp +public class MyEntitySavingEventHandler : INotificationHandler { + + public void Handle(EntitySavingNotification notification) + { + // Handle the event here + } + +} +``` + +Register the event handler in `Program.cs`: + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .AddNotificationHandler() + .Build(); +``` + +## Repository Events + +### Using the `EntitySavingNotification()` + +Triggers when `Save` is called before persisting the entity. The notification contains an `Entity` property with `Before` and `After` values, providing access to the previous and updated entities. Modify the `After` entity to persist changes. If the `Cancel` property of the notification is set to `true` then the save operation will be canceled and no changes will be saved. + +#### Example + +```csharp +public class MyEntitySavingEventHandler : INotificationHandler { + + public void Handle(EntitySavingNotification notification) + { + var person = notification.Entity.After as Person; + if (person != null){ + ... + } + } + +} +``` + +### Using the `EntitySavedNotification()` + +Triggers when the repository `Save` method is called and after the entity has been persisted. The notification contains an `Entity` property with `Before` and `After` inner properties. These properties provide access to a copy of the previously persisted entity (or null if a new entity) and the updated entity that´s saved. + +#### Example + +```csharp +public class MyEntitySavedEventHandler : INotificationHandler { + + public void Handle(EntitySavedNotification notification) + { + var person = notification.Entity.After as Person; + if (person != null){ + ... + } + } + +} +``` + +### Using the `EntityDeletingNotification()` + +Triggers when the repository `Delete` method is called and **before** the entity is deleted. The notification contains an `Entity` property providing access to a copy of the entity about to be deleted. If the `Cancel` property of notification is set to `true` then the delete operation will be cancelled and entity won't be deleted. + +#### Example + +```csharp +public class MyEntityDeletingEventHandler : INotificationHandler { + + public void Handle(EntityDeletingNotification notification) + { + var person = notification.Entity.After as Person; + if (person != null){ + ... + } + } + +} +``` + +### Using the `EntityDeletedNotification()` + +Triggers when the repository `Delete` method is called and **after** the entity has been deleted. The notification contains an `Entity` property providing access to a copy of the entity that´s deleted. + +#### Example + +```csharp +public class MyEntityDeletedEventHandler : INotificationHandler { + + public void Handle(EntityDeletedNotification notification) + { + var person = notification.Entity.After as Person; + if (person != null){ + ... + } + } + +} +``` + +### Using the `SqlQueryBuildingNotification()` + +Triggers when the repository is **preparing** a SQL query. The notification contains the collection alias + type, the NPoco `Sql` object, and the where clause/order by clauses. These will be used to generate the SQL query. + +#### Example + +```csharp +public class MySqlQueryBuildingEventHandler : INotificationHandler { + + public void Handle(SqlQueryBuildingNotification notification) + { + notification.Sql = notification.Sql.Append("WHERE MyId = @0", 1); + } + +} +``` + +### Using the `SqlQueryBuiltNotification()` + +Triggers when the repository has **repaired** a SQL query. The notification contains the collection alias + type, the NPoco `Sql` object and the where clause/order by clauses that was used to generate the SQL query. + +#### Example + +```csharp +public class MySqlQueryBuiltEventHandler : INotificationHandler { + + public void Handle(SqlQueryBuiltNotification notification) + { + notification.Sql = notification.Sql.Append("WHERE MyId = @0", 1); + } + +} +``` + +## Repository Events Validation + +From version `15.1.0`, complex server-side validation can be added to a collection using the `CancelOperation` method of the notification. + +### Example + +```csharp +public class MyEntitySavingEventHandler : INotificationHandler { + + public void Handle(EntitySavingNotification notification) + { + var person = notification.Entity.After as Person; + if (person != null && person.Age < 18) { + notification.CancelOperation(new EventMessage("ValidationError", "Custom validation error message raised from the notification handler")); + } + } + +} +``` diff --git a/16/umbraco-ui-builder/advanced/repositories.md b/16/umbraco-ui-builder/advanced/repositories.md new file mode 100644 index 00000000000..2f87fe37b36 --- /dev/null +++ b/16/umbraco-ui-builder/advanced/repositories.md @@ -0,0 +1,150 @@ +--- +description: Configure repositories in Umbraco UI Builder. +--- + +# Repositories + +Repositories in Umbraco UI Builder manage entity data storage. By default, collections use a built-in NPoco repository. To use a different storage strategy, define a custom repository implementation. + +## Defining a Repository + +Create a class that inherits from `Repository` and implements all abstract methods. + +````csharp +// Example +public class PersonRepository : Repository { + + public PersonRepository(RepositoryContext context) + : base(context) + { } + + protected override int GetIdImpl(Person entity) { + return entity.Id; + } + + protected override Person GetImpl(int id) { + ... + } + + protected override Person SaveImpl(Person entity) { + ... + } + + protected override void DeleteImpl(int id) { + ... + } + + protected override IEnumerable GetAllImpl(Expression> whereClause, Expression> orderBy, SortDirection orderByDirection) { + ... + } + + protected override PagedResult GetPagedImpl(int pageNumber, int pageSize, Expression> whereClause, Expression> orderBy, SortDirection orderByDirection) { + ... + } + + protected override long GetCountImpl(Expression> whereClause) { + ... + } + + protected override IEnumerable GetRelationsByParentIdImpl(int parentId, string relationAlias) + { + ... + } + + protected override TJunctionEntity SaveRelationImpl(TJunctionEntity entity) + { + ... + } +} +```` + +{% hint style="info" %} +`Impl` methods have public alternatives without the suffix. Separate implementation methods ensure repositories trigger Umbraco UI Builder events, whether actions originate from the UI or not. +{% endhint %} + +## Changing the Repository Implementation of a Collection + +### Using the `SetRepositoryType()` Method + +Assign a custom repository type to a collection. + +#### Method Syntax + +```cs +SetRepositoryType() : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetRepositoryType(); +```` + +### Using the `SetRepositoryType(Type repositoryType)` Method + +Sets the repository type dynamically to the given type for the current collection. + +#### Method Syntax + +```cs +SetRepositoryType(Type repositoryType) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetRepositoryType(typeof(PersonRepositoryType)); +```` + +## Accessing a Repository in Code + +To help with accessing a repository (default or custom) Umbraco UI Builder has an `IRepositoryFactory` you can inject into your code base. This includes a couple of factory methods to create the repository instances for you. +Repositories should only be created via the repository factory as there are some injected dependencies that can only be resolved by Umbraco UI Builder. + +### Using the `GetRepository()` Method + +Creates a repository for the given entity type. Umbraco UI Builder will search the configuration for the first section/collection with a configuration for the given entity type. Then it will use that as a repository configuration. + +#### Method Syntax + +```cs +IRepositoryFactory.GetRepository() : Repository +``` + +#### Example + +````csharp +public class MyController : Controller +{ + private readonly Repository _repo; + + public MyController(IRepositoryFactory repoFactory) + { + _repo = repoFactory.GetRepository(); + } +} +```` + +### Using the `GetRepository(string collectionAlias)` Method + +Creates a repository for the given entity type from the collection with the given alias. + +#### Method Syntax + +```cs +IRepositoryFactory.GetRepository(string collectionAlias) : Repository +``` + +#### Example + +````csharp +public class MyController : Controller +{ + private readonly Repository _repo; + + public MyController(IRepositoryFactory repoFactory) + { + _repo = repoFactory.GetRepository("person"); + } +} +```` diff --git a/16/umbraco-ui-builder/advanced/value-mappers.md b/16/umbraco-ui-builder/advanced/value-mappers.md new file mode 100644 index 00000000000..b440e8e3e9d --- /dev/null +++ b/16/umbraco-ui-builder/advanced/value-mappers.md @@ -0,0 +1,84 @@ +--- +description: Configuring value mappers in Umbraco UI Builder to modify how data is stored and retrieved. +--- + +# Value Mappers + +Value mappers in Umbraco UI Builder act as intermediaries between the editor UI and the database, allowing customization of stored field values. By default, Umbraco UI Builder saves data as it would be stored in Umbraco, but value mappers enable modifications. + +When resolving a value mapper, Umbraco UI Builder first checks the global DI container. If no type is defined, it manually instantiates a new instance. + +## Defining a Value Mapper + +To define a mapper, create a class that inherits from the base class `ValueMapper` and implements the `EditorToModel` and `ModelToEditor` methods. + +### Example + +````csharp +public class MyValueMapper : ValueMapper +{ + public override object EditorToModel(object input) + { + // Tweak the input and return mapped object + ... + } + + public override object ModelToEditor(object input) + { + // Tweak the input and return mapped object + ... + } +} +```` + +## Setting a Field Value Mapper + +Value mappers are defined as part of a collection editor field configuration. + +### Using the `SetValueMapper()` Method + +Set the value mapper for the current field. + +#### Method Syntax + +```csharp +SetValueMapper() : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetValueMapper(); +```` + +### Using the `SetValueMapper(Type mapperType)` Method + +Set the value mapper for the current field using a type reference. + +#### Method Syntax + +```csharp +SetValueMapper(Type mapperType) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetValueMapper(typeof(MyValueMapper)); +```` + +### Using the `SetValueMapper(Mapper mapper)` Method + +Set the value mapper for the current field using an instance. + +#### Method Syntax + +```csharp +SetValueMapper(Mapper mapper) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetValueMapper(new MyValueMapper()); +```` diff --git a/16/umbraco-ui-builder/advanced/virtual-sub-trees.md b/16/umbraco-ui-builder/advanced/virtual-sub-trees.md new file mode 100644 index 00000000000..6be46b481a9 --- /dev/null +++ b/16/umbraco-ui-builder/advanced/virtual-sub-trees.md @@ -0,0 +1,162 @@ +--- +description: Configuring virtual sub trees in Umbraco UI Builder. +--- + +# Virtual SubTrees + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Virtual subtrees inject an Umbraco UI Builder tree structure into another Umbraco tree at a specified location, acting as child nodes of the injection point. They extend built-in or third-party package trees with additional features. For example a "loyalty points" program for an e-commerce site can inject related database tables into a Commerce store tree, making management more intuitive. + +![Virtual sub tree injected into a Commerce store tree](../images/virtual-sub-tree.png) + +## Defining Virtual SubTrees + +Use the `AddVirtualSubTree` methods of a [WithTreeConfigBuilder](../areas/trees.md#extending-an-existing-tree) instance to define a virtual subtree. + +### Using the `AddVirtualSubTree()` Method + +Adds a virtual subtree to the current tree with visibility controlled by the specified expression. + +#### Method Syntax + +```csharp +AddVirtualSubTree(string sectionAlias, string treeAlias, Lambda visibilityExpression, Lambda virtualSubTreeConfig = null) : VirtualSubTreeConfigBuilder +``` + +#### Example + +````csharp +withTreeConfig.AddVirtualSubTree(ctx => ctx.Source.Id == 1056, contextAppConfig => { + ... +}); +```` + +### Using the `AddVirtualSubTreeBefore()` Method + +Adds a virtual subtree to the current tree **before** the tree node matches the match expression, with its visibility controlled by the specified expression. + +#### Method Syntax + +```csharp +AddVirtualSubTreeBefore(string sectionAlias, string treeAlias, Lambda visibilityExpression, Lambda matchExpression, Lambda virtualSubTreeConfig = null) : VirtualSubTreeConfigBuilder +``` + +#### Example + +````csharp +withTreeConfig.AddVirtualSubTreeBefore(ctx => ctx.Source.Id == 1056, treeNode => treeNode.Name == "Settings", contextAppConfig => { + ... +}); +```` + +### Using the `AddVirtualSubTreeAfter()` Method + +Adds a virtual subtree to the current tree **after** the tree node matches the match expression, with its visibility controlled by the specified expression. + +#### Method Syntax + +```csharp +AddVirtualSubTreeAfter(string sectionAlias, string treeAlias, Lambda visibilityExpression, Lambda matchExpression, Lambda virtualSubTreeConfig = null) : VirtualSubTreeConfigBuilder +``` + +#### Example + +````csharp +withTreeConfig.AddVirtualSubTreeAfter(ctx => ctx.Source.Id == 1056, treeNode => treeNode.Name == "Settings", contextAppConfig => { + ... +}); +```` + +## Control the Virtual SubTrees Inject Location + +Control the injection location by passing a visibility expression to the `AddVirtualSubTree` methods on the root `UIBuilderConfigBuilder` instance. Without a visibility expression, the subtree appears under every node in the target tree. This expression can be used to identify the exact location where the tree should go. + +The visibility expression receives a `VirtualSubTreeFilterContext` argument with relevant contextual information. The information includes the current node being rendered, alongside a list of the current user's user groups for permission-based visibility control. It also includes access to an `IServiceProvider` for dependency resolution. + +````csharp +public class VirtualSubTreeFilterContext +{ + public NodeContext Source { get; } + public IEnumerable UserGroups { get; } + public IServiceProvider ServiceProvider { get; } +} + +public class NodeContext +{ + public string Id { get; } + public string TreeAlias { get; } + public string SectionAlias { get; } + public FormCollection QueryString { get; } +} +```` + +### Example: Filter Injection by Document Type + +````csharp +withTreeConfig.AddVirtualSubTree(ctx => + { + using var umbracoContextRef = ctx.ServiceProvider.GetRequiredService().EnsureUmbracoContext(); + + if (!int.TryParse(ctx.Source.Id, out int id)) + return false; + + return (umbracoContextRef.UmbracoContext.Content.GetById(id)?.ContentType.Alias ?? "") == "textPage"; + }, + virtualNodeConfig => virtualNodeConfig + ... +); +```` + +## Control the Position of the injected Virtual SubTrees + +The position of a virtual subtree within the child nodes of the injection node is controlled by using one of the `AddVirtualSubTreeBefore` or `AddVirtualSubTreeAfter` methods. These methods need to be on the root level `UIBuilderConfigBuilder` instance. The match expression identifies the node for insertion. This expression passes a single `TreeNode` argument to determine the position. It also requires a `boolean` return value to indicate the relevant location has been found. + +````csharp +public class TreeNode +{ + public object Id { get; } + public object ParentId { get; } + public string Alias { get; } + public string Name { get; } + public string NodeType { get; } + public string Path { get; } + public string RoutePath { get; } + public IDictionary AdditionalData { get; } + ... +} +```` + +Below you can find an example of positioning a subtree after a node with the alias "settings": + +````csharp +treeNode => treeNode.alias == "settings" +```` + +## Configuring a Virtual SubTree + +Virtual subtrees use the `Tree` config builder API including support for folders and collections. There is an exception when adding collections to a subtree where you will have an additional foreign key expression parameter to define. The foreign key expression links the entities of the collection to the parent node of the subtree. For more information, see the [Trees](../areas/trees.md) article. + +## Inject Virtual Subtrees into Third-Party Trees + +Out of the box, Umbraco UI Builder supports injecting subtrees into the core content, media, members, and member group trees. It also includes third-party support for [Umbraco Commerce](../../umbraco-commerce/README.md) settings and commerce trees. To inject into additional trees, implement an `ITreeHelper` to extract necessary data. The tree helper consists of a tree alias for which the tree helper is. It includes methods to correctly identify the full parent path, a unique ID for a given node ID, and to resolve the actual entity ID. The entity ID should be used for the foreign key collection values. + +````csharp +public interface ITreeHelper +{ + string TreeAlias { get; } + string GetUniqueId(string nodeId, FormCollection queryString); + object GetEntityId(string uniqueId); + string GetPath(string uniqueId); +} +```` + +Once you have defined a tree helper, register the DI container in your startup class. + +````csharp +builder.Services.AddSingleton(); +```` + +Once registered, any virtual subtree assigned to the helper’s tree alias will use it to locate required data. diff --git a/16/umbraco-ui-builder/areas/context-apps.md b/16/umbraco-ui-builder/areas/context-apps.md new file mode 100644 index 00000000000..75ff3602cd6 --- /dev/null +++ b/16/umbraco-ui-builder/areas/context-apps.md @@ -0,0 +1,252 @@ +--- +description: Configuring context apps in Umbraco UI Builder. +--- + +# Context Apps + +Context Apps in Umbraco UI Builder function similarly to Workspace Views (previously called as Content Apps). They provide contextual applications within the content editor UI. By defining context apps, you can expose collections that are directly related to the content in question. For example, blog post comments can be linked to their respective blog posts and managed in context through a Workspace View. + +![Context App](../images/context_app.png) + +## Defining a Context App + +You can define a context app by calling one of the `AddContextApp` methods on a [`WithTreeConfigBuilder`](trees.md#extending-an-existing-tree) instance. + +### Using the `AddContextApp()` Method + +Adds a context app with the specified name and default icon. + +#### Method Syntax + +```cs +AddContextApp(string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextApp("Comments", contextAppConfig => { + ... +}); +``` + +### Using the `AddContextApp()` Method with Custom Icon + +Adds a context app with the specified name and custom icon. + +#### Method Syntax + +```cs +AddContextApp(string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextApp("Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +### Using the `AddContextAppBefore()` Method + +Adds a context app with the specified name and default icon before another context app specified by its alias. + +#### Method Syntax + +```cs +AddContextAppBefore(string beforeAlias, string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextAppBefore("umbContent", "Comments", contextAppConfig => { + ... +}); +``` + +### Using the `AddContextAppBefore()` Method with a Custom Icon + +Adds a context app with the specified name and custom icon before another context app specified by its alias. + +#### Method Syntax + +```cs +AddContextAppBefore(string beforeAlias, string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextAppBefore("umbContent", "Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +### Using the `AddContextAppAfter()` Method + +Adds a context app with the specified name and default icon after another context app specified by its alias. + +#### Method Syntax + +```cs +AddContextAppAfter(string afterAlias, string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp + +withTreeConfig.AddContextAppAfter("umbContent", "Comments", contextAppConfig => { + ... +}); +``` + +### Using the `AddContextAppAfter()` Method with a Custom Icon + +Adds a context app with the specified name and custom icon after another context app specified by its alias. + +#### Method Syntax + +```cs +AddContextAppAfter(string afterAlias, string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextAppAfter("umbContent", "Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +## Changing a Context App Alias + +### Using the `SetAlias()` Method + +Sets the alias of the context app. By default, an alias is automatically generated from the context app's name. You can use the `SetAlias` method to specify a custom alias. + +#### Method Syntax + +```cs +SetAlias(string alias) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +contextAppConfig.SetAlias("comments"); +``` + +## Changing a Context App Icon Color + +### Using the `SetIconColor()` Method + +Sets the context app icon color to the given color. The available colors are: `black`, `green`, `yellow`, `orange`, `blue` or `red`. + +#### Method Syntax + +```cs +SetIconColor(string color) : ContextAppConfigBuilder +``` + +#### Example + +````csharp +contextAppConfig.SetIconColor("blue"); +```` + +## Changing Context App Visibility + +Context app visibility is controlled by a delegate that takes a `ContextAppVisibilityContext` instance. This method contains a `Source` property which holds a reference to the source object that the Workspace View is being displayed on (i.e., an `IContent` instance). It also holds a reference to a `UserGroups` collection of the currently logged-in user's user groups. You can use these values to determine when the context app should be displayed. + +By default, context apps are pre-filtered to only appear on the tree they are defined in. This default behavior is combined with the SetVisibility configuration to control visibility. + +### Using the `SetIconColor()` Method + +Defines the visibility of the context app based on a delegate expression. + +#### Method Syntax + +```cs +SetVisibility(Func visibilityExpression) : ContextAppConfigBuilder +``` + +#### Example + +````csharp +contextAppConfig.SetVisibility(appCtx => appCtx.Source is IContent content && content.ContentType.Alias == "blogPost"); +```` + +## Adding a Collection to a Context App + +Context apps can consist of one or more collections. If a context app contains multiple collections, the collection list views will be displayed in tabs within the context app. + +### Using the `AddCollection<>()` Method + +Adds a collection to the current context app with the specified names, descriptions, and default icons. Each collection requires an ID field and a foreign key field, linking to Umbraco node UDI values. For more details, see the [Collections](../collections/overview.md) article. + +#### Method Syntax + +```cs +AddCollection( + Lambda idFieldExpression, + Lambda fkFieldExpression, + string nameSingular, + string namePlural, + string description, + Lambda collectionConfig = null +) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +contextAppConfig.AddCollection( + p => p.Id, + p => "Comment", + "Comments", + "A collection of comments", + collectionConfig => { + // Collection configuration here + } +); +``` + +### Using the `AddCollection<>()` Method with Custom Icon + +**AddCollection<TEntityType>(Lambda idFieldExpression, Lambda fkFieldExpression, string nameSingular, string namePlural, string description, string iconSingular, string iconPlural, Lambda collectionConfig = null) : ContextAppConfigBuilder** + +Adds a collection to the current context app with the specified names, descriptions, and custom icons. Each collection requires an ID field and a foreign key field, linking to Umbraco node UDI values. For more details, see the [Collections](../collections/overview.md) article. + +#### Method Syntax + +```cs +AddCollection( + Lambda idFieldExpression, + Lambda fkFieldExpression, + string nameSingular, + string namePlural, + string description, + string iconSingular, + string iconPlural, + Lambda collectionConfig = null +) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +contextAppConfig.AddCollection( + p => p.Id, + "Comment", + "Comments", + "A collection of comments", + "icon-chat", + "icon-chat", + collectionConfig => { + // Collection configuration here + } +); +``` diff --git a/16/umbraco-ui-builder/areas/dashboards.md b/16/umbraco-ui-builder/areas/dashboards.md new file mode 100644 index 00000000000..d753f2332e9 --- /dev/null +++ b/16/umbraco-ui-builder/areas/dashboards.md @@ -0,0 +1,180 @@ +--- +description: Configuring Dashboards in Umbraco UI Builder. +--- + +# Dashboards + +Dashboards in Umbraco UI Builder provide an intuitive way to present important information and tools at the root of a section within the Umbraco backoffice. They serve as a starting point for users, offering quick access to relevant data, insights, or actions. Dashboards can be customized, reordered, and configured to display for specific user groups, making them a flexible tool for enhancing the backoffice experience. When multiple dashboards are available in a section, they appear in a tabbed layout for easy navigation. + +![Dashboards](../images/dashboards.png) + +## Defining a Dashboard + +You can define a dashboard by calling one of the `AddDashboard` methods on a [`SectionConfigBuilder`](sections.md) or a [`WithSectionConfigBuilder`](sections.md#extending-an-existing-section) instance. + +### Using the `AddDashboard()` Method + +Adds a dashboard with the specified name. + +#### Method Syntax + +```cs +AddDashboard(string name, Lambda dashboardConfig = null) : DashboardConfigBuilder +``` + +#### Example + +```csharp +sectionConfig.AddDashboard("Team", dashboardConfig => { + ... +}); +``` + +### Using the `AddDashboardBefore()` Method + +Adds a dashboard with the specified name before the dashboard with the given alias. + +#### Method Syntax + +```cs +AddDashboardBefore(string beforeAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder +``` + +#### Example + +```csharp +sectionConfig.AddDashboardBefore("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +### Using the `AddDashboardAfter()` Method + +Adds a dashboard with the specified name after the dashboard with the given alias. + +#### Method Syntax + +```cs +AddDashboardAfter(string afterAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder +``` + +#### Example + +```csharp +sectionConfig.AddDashboardAfter("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +## Setting a Custom Dashboard Alias + +### Using the `SetAlias()` Method + +Sets the alias of the dashboard. By default, an alias is automatically generated based on the supplied name. If a specific alias is required, the `SetAlias` method can be used to override the default. + +#### Method Syntax + +```cs +SetAlias(string alias) : DashboardConfigBuilder +``` + +#### Example + +```csharp +dashboardConfig.SetAlias("team"); +``` + +## Controlling Dashboard Visibility + +Dashboard visibility can be controlled using `ShowForUserGroup` and `HideForUserGroup`, which specify which user groups can see the dashboard. These settings can be applied multiple times for different user roles. + +By default, dashboards are pre-filtered to display only in their defined section. This filtering is combined with the `SetVisibility` method to control when a dashboard appears. + +### Using the `SetVisibility()` Method + +Defines visibility rules for the dashboard. + +#### Method Syntax + +```cs +SetVisibility(Lambda visibilityConfig) : DashboardConfigBuilder +``` + +#### Example + +````csharp +dashboardConfig.SetVisibility(visibilityConfig => visibilityConfig + .ShowForUserGroup("admin") + .HideForUserGroup("translator") +); +```` + +## Assigning a Collection to a Dashboard + +A dashboard can display only one collection. To display multiple collections, multiple dashboards must be configured. + +### Using the `SetCollection<>()` Method + +Assigns a collection to the dashboard with the specified names, descriptions, and default icons. The ID property must be defined. For more details, see the [Collections](../collections/overview.md) article. + +#### Method Syntax + +```cs +SetCollection( + Lambda idFieldExpression, + string nameSingular, + string namePlural, + string description, + Lambda collectionConfig = null +) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +dashboardConfig.SetCollection( + p => p.Id, + "Team Member", + "Team Members", + "A collection of team members", + collectionConfig => { + ... + } +); +``` + +### Using the `SetCollection<>()` Method with Custom Icons + +Assigns a collection to the dashboard with the specified names, descriptions, and custom icons. The ID property must be defined. For more details, see the [Collections](../collections/overview.md) article. + +#### Method Syntax + +```cs +SetCollection( + Lambda idFieldExpression, + Lambda fkFieldExpression, + string nameSingular, + string namePlural, + string description, + string iconSingular, + string iconPlural, + Lambda collectionConfig = null +) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +dashboardConfig.SetCollection( + p => p.Id, + p => p.ForeignKey, + "Team Member", + "Team Members", + "A collection of team members", + "icon-umm-user", + "icon-umb-user", + collectionConfig => { + ... + } +); +``` diff --git a/16/umbraco-ui-builder/areas/folders.md b/16/umbraco-ui-builder/areas/folders.md new file mode 100644 index 00000000000..0077bf0861e --- /dev/null +++ b/16/umbraco-ui-builder/areas/folders.md @@ -0,0 +1,193 @@ +--- +description: Configuring folders to organise trees in Umbraco UI Builder. +--- + +# Folders + +Folders help organize trees in Umbraco UI Builder, allowing you to structure content with nested folders and collections. A folder can exist within a tree or as a sub-folder within another folder. Folders can contain either sub-folders or [Collections](../collections/overview.md). + +![Tree with Settings folder](../images/tree.png) + +## Defining a Folder + +To define a folder, use one of the `AddFolder` methods on a [`Tree`](trees.md) or parent `Folder` config builder instance. + +### Using the `AddFolder()` Method + +Adds a folder to the current tree with the specified name and a default folder icon. + +#### Method Syntax + +```cs +AddFolder(string name, Lambda folderConfig = null) : FolderConfigBuilder +``` + +#### Example + +````csharp +treeConfig.AddFolder("Settings", folderConfig => { + ... +}); +```` + +### Using the `AddFolder()` Method with Custom Icon + +Adds a folder to the current tree with a specified name and icon. + +#### Method Syntax + +```cs +AddFolder(string name, string icon, Lambda folderConfig = null) : FolderConfigBuilder +``` + +#### Example + +````csharp +treeConfig.AddFolder("Settings", "icon-settings", folderConfig => { + ... +}); +```` + +## Changing a Folder Alias + +When creating a new folder, an alias is automatically generated. However, if you need a specific alias, you can use the `SetAlias` method to override it. + +### Using the `SetAlias()` Method + +Sets a custom alias for a folder. + +#### Method Syntax + +```cs +SetAlias(string alias) : FolderConfigBuilder +``` + +#### Example + +````csharp +folderConfig.SetAlias("settings"); +```` + +## Changing a Folder Icon Color + +### Using the `SetIconColor()` Method + +Sets the folder icon color to the given color. The available colors are: `black`, `green`, `yellow`, `orange`, `blue`, or `red`. + +#### Method Syntax + +```cs +SetIconColor(string color) : FolderConfigBuilder +``` + +#### Example + +````csharp +folderConfig.SetIconColor("blue"); +```` + +## Adding a Sub-Folder To a Folder + +### Using the `AddFolder()` Method for Sub-Folders + +Adds a sub-folder inside the current folder with a specified name and a default folder icon. + +#### Method Syntax + +```cs +AddFolder (string name, Lambda folderConfig = null) : FolderConfigBuilder +``` + +#### Example + +````csharp +folderConfig.AddFolder("Categories", subFolderConfig => { + ... +}); +```` + +### Using the `AddFolder()` Method for Sub-Folders with Custom Icon + +Adds a sub folder to the current folder with a specified name and custom icon. + +#### Method Syntax + +```cs +AddFolder (string name, string icon, Lambda folderConfig = null) : FolderConfigBuilder +``` + +#### Example + +````csharp +folderConfig.AddFolder("Categories", "icon-tags", subFolderConfig => { + ... +}); +```` + +## Adding a Collection to a Folder + +### Using the `AddCollection<>()` Method + +Adds a collection to the current folder with the given names, descriptions, and default icons. The ID property must be defined. For more details, see the [Collections](../collections/overview.md) article. + +#### Method Syntax + +```cs +AddCollection( + Lambda idFieldExpression, + string nameSingular, + string namePlural, + string description, + Lambda collectionConfig = null +) : CollectionConfigBuilder + +``` + +#### Example + +````csharp +folderConfig.AddCollection( + p => p.Id, + "Person", + "People", + "A collection of people", + collectionConfig => { + ... + } +); +```` + +### Using the `AddCollection<>()` Method with Custom Icons + +Adds a collection to the current folder with the given names, description and icons. The ID property must be defined. For more details, see the [Collections](../collections/overview.md) article. + +#### Method Syntax + +```cs +AddCollection( + Lambda idFieldExpression, + string nameSingular, + string namePlural, + string description, + string iconSingular, + string iconPlural, + Lambda collectionConfig = null +) : CollectionConfigBuilder + +``` + +#### Example + +````csharp +folderConfig.AddCollection( + p => p.Id, + "Person", + "People", + "A collection of people", + "icon-umb-users", + "icon-umb-users", + collectionConfig => { + ... + } +); +```` diff --git a/16/umbraco-ui-builder/areas/overview.md b/16/umbraco-ui-builder/areas/overview.md new file mode 100644 index 00000000000..ff59d609d58 --- /dev/null +++ b/16/umbraco-ui-builder/areas/overview.md @@ -0,0 +1,17 @@ +--- +description: Learn how to choose and configure the appropriate area for connecting Umbraco UI builder for Umbraco. +--- + +# Areas + +Umbraco UI Builder can be integrated into different areas of the Umbraco Backoffice. Before you start managing content, it is essential to decide which area best suits the presentation of your data. Each area offers unique features for displaying and interacting with content. + +Once you have identified the most appropriate area, you can proceed with configuring it to suit your needs. + +## Key Areas for Integration + +- [Sections](sections.md): The Sections area allows you to organize your content in a structured layout, enabling users to navigate different parts of the backoffice. +- [Dashboards](dashboards.md): The Dashboards area is ideal for creating custom views that provide quick access to key information and statistics. +- [Context Apps](context-apps.md): Context Apps provide contextual tools and information based on the specific content a user is working with. + +Selecting the correct area is essential to ensure your UI is both functional and user-friendly. Consider the nature of your content and the tasks users need to perform when deciding which area to use. diff --git a/16/umbraco-ui-builder/areas/sections.md b/16/umbraco-ui-builder/areas/sections.md new file mode 100644 index 00000000000..eee4e553d93 --- /dev/null +++ b/16/umbraco-ui-builder/areas/sections.md @@ -0,0 +1,317 @@ +--- +description: Configuring and customizing sections in Umbraco UI Builder to organize and manage the backoffice interface effectively. +--- + +# Sections + +A section in Umbraco represents a distinct area within the backoffice, such as content, media, and so on. Sections are accessible via links in the main menu at the top of the Umbraco interface. Using Umbraco UI Builder, multiple sections can be defined to organize the management of models logically. + +![Sections](../images/sections.png) + +## Defining a Section + +Sections are defined using the `AddSection` method on the root-level `UIBuilderConfigBuilder` instance. + +### Using the `AddSection()` Method + +This method adds a new section to the Umbraco menu with the specified name, allowing custom areas for organizing content in the backoffice. + +#### Method Syntax + +```cs +AddSection(string name, Lambda sectionConfig = null) : SectionConfigBuilder +``` + +#### Example + +```csharp +config.AddSection("Repositories", sectionConfig => { + ... +}); +``` + +### Using the `AddSectionBefore()` Method + +This method adds a section before another section with the specified alias, allowing for customized ordering of sections in the backoffice. + +#### Method Syntax + +```cs +AddSectionBefore(string beforeAlias, string name, Lambda sectionConfig = null) : SectionConfigBuilder +``` + +#### Example + +```csharp +config.AddSectionBefore("settings", "Repositories", sectionConfig => { + ... +}); +``` + +### Using the `AddSectionAfter()` Method + +This method adds a section after another section with the specified alias, allowing for a custom order of sections in the backoffice. + +#### Method Syntax + +```cs +AddSectionAfter(string afterAlias, string name, Lambda sectionConfig = null) : SectionConfigBuilder +``` + +#### Example + +```csharp +config.AddSectionAfter("media", "Repositories", sectionConfig => { + ... +}); +``` + +## Customizing the Section Alias + +### Setting a Custom Alias with `SetAlias()` Method + +This method sets a custom alias for the section. + +*Optional:* By default, an alias is automatically generated from the section's name. To customize the alias, the `SetAlias()` method can be used. + +#### Method Syntax + +```cs +SetAlias(string alias) : SectionConfigBuilder +``` + +#### Example + +```csharp +sectionConfig.SetAlias("repositories"); +``` + +## Configuring the Section Tree + +### Using the `Tree()` Method for Configuration + +This method configures the tree structure for the section, which is used to organize content types. For more information, see the [Trees](trees.md) article. + +#### Method Syntax + +```cs +Tree(Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +````csharp +sectionConfig.Tree(treeConfig => { + ... +}); +```` + +## Adding Dashboards to the Section + +### Adding a Dashboard with the `AddDashboard()` Method + +This method adds a dashboard to the section with the specified alias, providing tools and features for content management. For more information, see the [Dashboards](dashboards.md) article. + +#### Method Syntax + +```cs +AddDashboard(string name, Lambda dashboardConfig = null) : DashboardConfigBuilder +``` + +#### Example + +```csharp +sectionConfig.AddDashboard("Team", dashboardConfig => { + ... +}); +``` + +### Using `AddDashboardBefore()` to Place a Dashboard + +This method adds a dashboard before another dashboard with the specified alias, allowing custom placement in the section. For more information, see the [Dashboards](dashboards.md) article. + +#### Method Syntax + +```cs +AddDashboardBefore(string beforeAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder +``` + +#### Example + +```csharp +sectionConfig.AddDashboardBefore("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +### Using `AddDashboardAfter()` to Place a Dashboard + +This method adds a dashboard after another dashboard with the specified alias, giving control over dashboard order. For more information, see the [Dashboards](dashboards.md) article. + +#### Method Syntax + +```cs +AddDashboardAfter(string afterAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder +``` + +#### Example + +```csharp +sectionConfig.AddDashboardAfter("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +## Extending Existing Sections + +You can extend existing sections by adding Umbraco UI Builder trees and dashboards, context apps, and virtual subtrees. This can be done by calling the `WithSection` method on the root-level `UIBuilderConfigBuilder` instance. + +### Extending an Existing Section with `WithSection()` + +This method extends an existing section with additional configuration, enabling more customization for existing areas. + +#### Method Syntax + +```cs +WithSection(string alias, Lambda sectionConfig = null) : WithSectionConfigBuilder +``` + +#### Example + +```csharp +config.WithSection("member", withSectionConfig => { + ... +}); +``` + +## Adding Trees to an Existing Section + +### Using the `AddTree()` Method + +This method adds a tree to the section, helping to visualize and organize content types. For more information, see the [Trees](trees.md) article. + +#### Method Syntax + +```cs +AddTree(string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +````csharp +withSectionConfig.AddTree("My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +### Grouping Trees with `AddTree()` Method + +This method adds a tree within a specified group, improving content organization by grouping related trees together. For more information, see the [Trees](trees.md) article. + +#### Method Syntax + +```cs +AddTree(string groupName, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +````csharp +withSectionConfig.AddTree("My Group", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +## Adding a Tree Before or After an Existing Tree + +### Using `AddTreeBefore()` to Position a Tree + +This method adds a tree before another tree within the section, allowing you to customize the tree order. For more information, see the [Trees](trees.md) article. + +#### Method Syntax + +```cs +AddTreeBefore(string treeAlias, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +````csharp +withSectionConfig.AddTreeBefore("member", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +### Using `AddTreeAfter()` to Position a Tree + +This method adds a tree after another tree within the section, enabling specific ordering of trees. For more information, see the [Trees](trees.md) article. + +#### Method Syntax + +```cs +AddTreeAfter(string treeAlias, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +````csharp +withSectionConfig.AddTreeAfter("member", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +## Adding a Dashboard to an Existing Section + +### Using the `AddDashboard()` Method + +This method adds a new dashboard to the section with the specified name. For more information, see the [Dashboards](dashboards.md) article. + +#### Method Syntax + +```cs +AddDashboard (string name, Lambda dashboardConfig = null) : DashboardConfigBuilder +``` + +#### Example + +```csharp +withSectionConfig.AddDashboard("Team", dashboardConfig => { + ... +}); +``` + +### Using the `AddDashboardBefore()` Method + +This method adds a dashboard before the dashboard with the specified alias. For more information, see the [Dashboards](dashboards.md) article. + +#### Method Syntax + +```cs +AddDashboardBefore (string beforeAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder +``` + +#### Example + +```csharp +withSectionConfig.AddDashboardBefore("contentIntro", "Team", dashboardConfig => { + ... +}); +``` + +### Using the `AddDashboardAfter()` Method + +This method adds a dashboard after the dashboard with the specified alias. For more information, see the [Dashboards](dashboards.md) article. + +#### Method Syntax + +```cs +AddDashboardAfter (string afterAlias, string name, Lambda dashboardConfig = null) : DashboardConfigBuilder +``` + +#### Example + +```csharp +withSectionConfig.AddDashboardAfter("contentIntro", "Team", dashboardConfig => { + ... +}); +``` diff --git a/16/umbraco-ui-builder/areas/summary-dashboards.md b/16/umbraco-ui-builder/areas/summary-dashboards.md new file mode 100644 index 00000000000..2bf1fac6e43 --- /dev/null +++ b/16/umbraco-ui-builder/areas/summary-dashboards.md @@ -0,0 +1,27 @@ +--- +description: Configuring a summary dashboard to provide an overview of collections within a section. +--- + +# Summary Dashboards + +A summary dashboard appears automatically at the root of an Umbraco UI Builder section. It provides an overview of key collections within that section, enabling quick access to list views. Additionally, it allows for adding new entries to the collection, provided the collection is not set to read-only. + +By summarizing important data and simplifying navigation, the summary dashboard improves content management efficiency. + +![Summary Dashboard](../images/dashboard.png) + +## Displaying a Collection on the Summary Dashboard + +To display a collection on the summary dashboard, use the `ShowOnSummaryDashboard()` method in the collection configuration. + +### Configuration Example + +````csharp +collectionConfig.ShowOnSummaryDashboard(); +```` + +**Code Reference:** `ShowOnSummaryDashboard() : CollectionConfigBuilder` + +{% hint style="warning" %} +Only root-level collections within a section can be displayed on the summary dashboard. +{% endhint %} diff --git a/16/umbraco-ui-builder/areas/trees.md b/16/umbraco-ui-builder/areas/trees.md new file mode 100644 index 00000000000..b05de36b90f --- /dev/null +++ b/16/umbraco-ui-builder/areas/trees.md @@ -0,0 +1,393 @@ +--- +description: Configuring and customizing Trees to organize and manage the backoffice interface effectively. +--- + +# Tree + +A tree is a hierarchical structure that organizes sections into sub-sections. It appears in the main side panel of the Umbraco interface. In Umbraco UI Builder, each section can only have one tree definition, but you can use folder nodes to organize the tree. + +![Tree](../images/tree.png) + +## Configuring a Umbraco UI Builder Section Tree + +The tree configuration for Umbraco UI Builder sections is part of the [`Section`](sections.md) config builder and is accessed via its `Tree` method. + +### Using the `Tree()` Method + +This method defines the structure and behavior of a tree within a section. + +#### Method Syntax + +```cs +Tree(Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +```csharp +sectionConfig.Tree(treeConfig => { + ... +}); +``` + +## Adding a Tree to an Existing Section + +To add a tree to an existing section, use one of the `AddTree` methods from the [`WithSection`](sections.md#extending-an-existing-section) config builder. + +### Using the `AddTree()` method + +This method adds a tree to the current section, specifying its name and icon. + +#### Method Syntax + +```cs +AddTree(string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +````csharp +withSectionConfig.AddTree("My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +### Grouping Trees with `AddTree()` Method + +This method adds a tree to the current section under a specified group. + +#### Method Syntax + +```cs +AddTree(string groupName, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +````csharp +withSectionConfig.AddTree("My Group", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +### Using `AddTreeBefore()` to Position a Tree + +This method adds a tree to the current section before the tree with the specified alias. + +#### Method Syntax + +```cs +AddTreeBefore(string treeAlias, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +````csharp +withSectionConfig.AddTreeBefore("member", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +### Using `AddTreeAfter()` to Position a Tree + +This method adds a tree to the current section after the tree with the specified alias. + +#### Method Syntax + +```cs +AddTreeAfter(string treeAlias, string name, string icon, Lambda treeConfig = null) : TreeConfigBuilder +``` + +#### Example + +````csharp +withSectionConfig.AddTreeAfter("member", "My Tree", "icon-folder", treeConfig => { + ... +}); +```` + +## Changing the Tree Icon Color + +### Using the `SetIconColor()` Method + +This method changes the color of the tree’s icon. The available options are `black`, `green`, `yellow`, `orange`, `blue`, or `red`. + +{% hint style="warning" %} +Only trees in existing sections have an icon. Trees in Umbraco UI Builder sections display the tree contents directly. +{% endhint %} + +#### Method Syntax + +```cs +SetIconColor(string color) : TreeConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetIconColor("blue"); +```` + +## Adding a Group to a Tree + +### Using the `AddGroup()` Method + +This method adds a group to the current tree with the specified name. + +{% hint style="warning" %} +Only trees in Umbraco UI Builder sections support groups. +{% endhint %} + +#### Method Syntax + +```cs +AddGroup(string name, Lambda groupConfig = null) : GroupConfigBuilder +``` + +#### Example + +```csharp +treeConfig.AddGroup("Settings", groupConfig => { + ... +}); +``` + +## Adding a Folder to a Tree or Group + +### Using the `AddFolder()` Method + +This method adds a folder node inside a tree or group, using the default folder icon. For more details, see the [Folders](folders.md) article. + +#### Method Syntax + +```cs +AddFolder(string name, Lambda folderConfig = null) : FolderConfigBuilder +``` + +#### Example + +```csharp +treeConfig.AddFolder("Settings", folderConfig => { + ... +}); +``` + +### Using the `AddFolder()` Method with Custom Icon + +This method adds a folder with a specified icon inside a tree or group. For more details, see the [Folders](folders.md) article. + +#### Method Syntax + +```cs +AddFolder(string name, string icon, Lambda folderConfig = null) : FolderConfigBuilder +``` + +#### Example + +```csharp +treeConfig.AddFolder("Settings", "icon-settings", folderConfig => { + ... +}); +``` + +## Adding a Collection to a Tree or Group + +### Using the `AddCollection<>()` Method + +This method adds a collection to the current tree or group, specifying its names, descriptions, and default icons. The ID property must be defined. For more details, see the [Collections](../collections/overview.md) article. + +#### Method Syntax + +```cs +AddCollection( + Lambda idFieldExpression, + string nameSingular, + string namePlural, + string description, + Lambda collectionConfig = null +) : CollectionConfigBuilder + +``` + +#### Example + +```csharp +treeConfig.AddCollection( + p => p.Id, + "Person", + "People", + "A collection of people", + collectionConfig => { + ... + } +); +``` + +#### Using the `AddCollection<>()` Method with Icons + +This method adds a collection to the current tree or group, specifying its names, descriptions, and custom icons. The ID property must be defined. For more details, see the [Collections](../collections/overview.md) article. + +#### Method Syntax + +```cs +AddCollection( + Lambda idFieldExpression, + string nameSingular, + string namePlural, + string description, + string iconSingular, + string iconPlural, + Lambda collectionConfig = null +) : CollectionConfigBuilder + +``` + +#### Example + +```csharp +treeConfig.AddCollection( + p => p.Id, + "Person", + "People", + "A collection of people", + "icon-umb-users", + "icon-umb-users", + collectionConfig => { + ... + } +); +``` + +## Extending an Existing Tree + +To extend existing trees, call the `WithTree` method on a [`WithSectionConfigBuilder`](sections.md#extending-an-existing-section) instance. + +### Using the `WithTree()` Method + +This method starts a sub-configuration for an existing tree with the specified alias. + +#### Method Syntax + +```cs +WithTree(string alias, Lambda treeConfig = null) : WithTreeConfigBuilder +``` + +#### Example + +```csharp +sectionConfig.WithTree("content", withTreeConfig => { + ... +}); +``` + +## Adding a Context App to an Existing Tree + +### Using the `AddContextApp()` Method + +This method adds a context app with the specified name and default icon. For more details, see the [Context Apps](context-apps.md) article. + +#### Method Syntax + +```cs +AddContextApp(string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextApp("Comments", contextAppConfig => { + ... +}); +``` + +### Using the `AddContextApp()` Method with Custom Icon + +This method adds a context app with the specified name and custom icon. For more details, see the [Context Apps](context-apps.md) article. + +#### Method Syntax + +```cs +AddContextApp(string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextApp("Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +## Adding a Context App Before or After Another Context App + +### Using the `AddContextApp()` Method Before Another Context App + +This method adds a context app with the specified name and default icon before the specified context app alias. For more information, see the [Context Apps](context-apps.md) article. + +#### Method Syntax + +```cs +AddContextAppBefore(string beforeAlias, string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextAppBefore("umbContent", "Comments", contextAppConfig => { + ... +}); +``` + +### Using the `AddContextApp()` Method with Custom Icon Before Another Context App + +This method adds a context app with the specified name and custom icon before the specified context app alias. For more information, see the [Context Apps](context-apps.md) article. + +#### Method Syntax + +```cs +AddContextAppBefore(string beforeAlias, string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextAppBefore("umbContent", "Comments", "icon-chat", contextAppConfig => { + ... +}); +``` + +### Using the `AddContextApp()` Method After Another Context App + +This method adds a context app with the specified name and default icon after the specified context app alias. For more information, see the [Context Apps](context-apps.md) article. + +#### Method Syntax + +```cs +AddContextAppAfter(string afterAlias, string name, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextAppAfter("umbContent", "Comments", contextAppConfig => { + ... +}); +``` + +### Using the `AddContextApp()` Method with Custom Icon After Another Context App + +This method adds a context app with the specified name and custom icon after the specified context app alias. For more information, see the [Context Apps](context-apps.md) article. + +#### Method Syntax + +```cs +AddContextAppAfter(string afterAlias, string name, string icon, Lambda contextAppConfig = null) : ContextAppConfigBuilder +``` + +#### Example + +```csharp +withTreeConfig.AddContextAppAfter("umbContent", "Comments", "icon-chat", contextAppConfig => { + ... +}); +``` diff --git a/16/umbraco-ui-builder/cards/count-cards.md b/16/umbraco-ui-builder/cards/count-cards.md new file mode 100644 index 00000000000..cbcd55ce60f --- /dev/null +++ b/16/umbraco-ui-builder/cards/count-cards.md @@ -0,0 +1,103 @@ +--- +description: Learn how to configure count cards in Umbraco UI Builder. +--- + +# Count Cards + +Count cards allow you to define cards directly against the [Collection](../collections/overview.md) configuration, providing a basic **where clause** to use in a count SQL statement. These work perfectly for basic data visualizations based on counts of entities in a collection. + +If you need to do more than a basic count, see the [Custom Cards](custom-cards.md) article. + +## Adding a Count Card to a Collection + +Count cards display basic summaries of key information that may be useful to the editor. + +### Using the `AddCard()` Method + +Adds a count card with the specified name and a where clause filter expression. The filter expression must be a `boolean` value. + +#### Method Syntax + +```cs +AddCard(string name, Lambda whereClauseExpression, Lambda cardConfig = null) : CardConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddCard("Older than 30", p => p.Age > 30, cardConfig => { + ... +}); +```` + +### Using the `AddCard()` Method with Icon + +Adds a count card with the specified name, an icon, and a where clause filter expression. The filter expression must be a `boolean` value. + +#### Method Syntax + +```cs +AddCard(string name, string icon, Lambda whereClauseExpression, Lambda cardConfig = null) : CardConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddCard("Older than 30", "icon-umb-users", p => p.Age > 30, cardConfig => { + ... +}); +```` + +### Change the Color of a Count Card + +#### Using the `SetColor()` Method + +Sets the color for the count card. + +#### Method Syntax + +```cs +SetColor(string color) : CardConfigBuilder +``` + +#### Example + +````csharp +cardConfig.SetColor("blue"); +```` + +### Add a Suffix to a Count Value + +#### Using the `SetSuffix()` Method + +Sets a suffix to be displayed alongside the card value.d + +#### Method Syntax + +```cs +SetSuffix(string suffix) : CardConfigBuilder +``` + +#### Example + +````csharp +cardConfig.SetSuffix("years"); +```` + +### Formatting the Value of a Count + +#### Using the `SetFormat()` Method + +Sets a custom format for the card's value. + +#### Method Syntax + +```cs +SetFormat(Lambda formatExpression) : CardConfigBuilder +``` + +#### Example + +````csharp +cardConfig.SetFormat((v) => $"{v}%"); +```` diff --git a/16/umbraco-ui-builder/cards/custom-cards.md b/16/umbraco-ui-builder/cards/custom-cards.md new file mode 100644 index 00000000000..b4c9fb43aa2 --- /dev/null +++ b/16/umbraco-ui-builder/cards/custom-cards.md @@ -0,0 +1,75 @@ +--- +description: Learn how to configure custom cards in Umbraco UI Builder. +--- + +# Custom Cards + +Custom cards enable more complex metric calculations and are defined by a class that implements the `Card` base class. + +When Umbraco UI Builder resolves a card, it tries to do so from the global DI container. This means you can inject any dependencies required for the card's value calculation. If no type is found in the DI container, Umbraco UI Builder will fall back to manually instantiating a new instance of the value mapper. + +## Defining a Custom Card + +To define a custom card, create a class that inherits from the base class `Card` and configure it in the constructor as shown below: + +````csharp +// Example +public class AvgPersonAgeCard : Card +{ + public override string Alias => "avgPersonAge"; + public override string Name => "Average Age"; + public override string Icon => "icon-calendar"; + public override string Color => "green"; + public override string Suffix => "yrs"; + + public override object GetValue(object parentId = null) + { + // Perform value calculation logic + } +} +```` + +### Configuration Options + +| Option | Description | Required | +|:--------------------------------:|:------------------------------------------:|----------| +| Name | The name of the card. | Yes | +| Alias | A unique alias for the card. | Yes | +| GetValue(object parentId = null) | A method to retrieve the card's value. | Yes | +| Icon | An icon displaed in the card. | No | +| Color | The color of the card. | No | +| Suffix | The suffix displayed after the card value. | No | + +## Adding a Custom Card to a Collection + +### Using the `AddCard()` Method + +Adds a custom card of the specified type to the collection. + +#### Method Syntax + +```cs +AddCard() : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddCard(); +```` + +### Using the `AddCard(Type cardType)` Method + +Adds a custom card of the specified type to the collection, using the `Type` parameter to pass the card type dynamically. + +#### Method Syntax + +```cs +AddCard(Type cardType) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddCard(typeof(AvgPersonAgeCard)); +```` diff --git a/16/umbraco-ui-builder/cards/overview.md b/16/umbraco-ui-builder/cards/overview.md new file mode 100644 index 00000000000..9edc2bcbee0 --- /dev/null +++ b/16/umbraco-ui-builder/cards/overview.md @@ -0,0 +1,19 @@ +--- +description: Learn how to configure cards in Umbraco UI Builder. +--- + +# Cards + +Cards provide an API to display summary information in a card-based format, which is useful for displaying key metrics about a collection. + +![Cards](../images/cards.png) + +Cards can be defined in two ways: + +{% content-ref url="count-cards.md" %} +[Count Cards](count-cards.md) +{% endcontent-ref %} + +{% content-ref url="custom-cards.md" %} +[Custom Cards](custom-cards.md) +{% endcontent-ref %} diff --git a/16/umbraco-ui-builder/changelog-archive/changelog.md b/16/umbraco-ui-builder/changelog-archive/changelog.md new file mode 100644 index 00000000000..82b8c320984 --- /dev/null +++ b/16/umbraco-ui-builder/changelog-archive/changelog.md @@ -0,0 +1,180 @@ +--- +description: Changelog for Konstrukt, the backoffice UI builder for Umbraco. +--- + +# Changelog + +## v1.6.4 + +**Date:** 2023-02-22 +**Description:** Patch release with bug fixes + +- Fixed issue where upload file property editor throws "the specified file type has been disallowed by the administrator" error ([#49](https://github.com/outfielddigital/konstrukt/issues/49)). +- Added ngrok URLs to allow domains that don't need a license. + +## v1.6.3 + +**Date:** 2023-01-16 +**Description:** Patch release with bug fixes + +- Moved encrypted properties implementation to the base repository class so encryption is honored when performing save/load operation directly against the repository API ([#44](https://github.com/outfielddigital/konstrukt/issues/44)). +- Made `SecurityHelper` swappable so you can use something other than the default `DataProtectionProvider` implementation that comes out of the box (OOTB). +- Fixed issue with advanced filters that use the lambda `ParameterReplacer` due to the parameter being replaced in the function, but not in the Lambda parameters list ([#45](https://github.com/outfielddigital/konstrukt/issues/45)). +- Fixed date filters not working on mobile resolution devices ([#46](https://github.com/outfielddigital/konstrukt/issues/46)). + +## v1.6.2 + +**Date:** 2022-12-01 +**Description:** Patch release with bug fixes + +- Added marketplace updates. +- Update the Konstrukt type finder to use a non-obsolete constructor. +- Updated to use `IComposer` instead of `IUserComposer` as the latter has been removed in v11. +- Fixed parent ID not being passed to create dialog for associated entities. +- Removed settings section restriction on the licensing info endpoint as it would cause errors when the licensing banner is shown in other sections. + +## v1.6.1 + +**Date:** 2022-10-11 +**Description:** Patch release with bug fixes + +- Fixed issue when running on Azure where the DB provider name reverts to `System.Data.SqlClient` when it should be `Microsoft.Data.SqlClient` + +## v1.6.0 + +**Date:** 2022-09-30 +**Description:** Minor release with additional features + +- Added a Save action type to display actions as a sub-button in an entities Save button (similar to the "Save and Publish" button in the content section). + +## v1.5.2 + +**Date:** 2022-09-09 +**Description:** Patch release with bug fixes + +- Fixed bug in entity picker not correctly showing the `Add` button when it should ([#39](https://github.com/outfielddigital/konstrukt/issues/39)). +- Added some basic validation to config at startup to ensure a valid config model. + +## v1.5.1 + +**Date:** 2022-08-22 +**Description:** Patch release with bug fixes + +- Fixed searchable properties not being searched in a case-insensitive way for repositories that don't use Umbraco's NPoco extension methods ([#36](https://github.com/outfielddigital/konstrukt/issues/36)). +- Fixed regression in Konstrukt repository not correctly combining filters. +- Fixed exception due to `ServiceProvider` not getting passed to Data transfer object (DTO) mapper. + +## v1.5.0 + +**Date:** 2022-08-18 +**Description:** Minor release with additional features and bug fixes + +- Added ability to control collection visibility in the section tree at runtime. +- Added ability to control collection create, update, and delete permissions at runtime. +- Added ability to control list view field visibility at runtime. +- Added ability to control editor tab visibility at runtime. +- Added ability to control editor fieldset visibility at runtime. +- Added ability to control editor field visibility at runtime. +- Added ability to control whether an editor field is read-only or not at runtime. +- Added the ability to add custom dashboards to Konstrukt sections. +- Added child collections support to dashboard collections. +- Updated Konstrukt API to null check sections/collections first and throw exceptions if not found. +- Updated based repositories to automatically implement filtering for configurable options. +- Updated the summary dashboard to not display if there are no collections configured to show on it. +- Fixed bug where entity service would silently fail if it couldn't retrieve an entity. Now throws an exception. +- Fixed bug where content app factory would throw an exception when run in sections where the section entity was not `IUmbracoEntity`. + +## v1.4.0 + +**Date:** 2022-07-12 +**Description:** Minor release with additional features and bug fixes + +- Added [`WithSection`](../areas/sections.md#extending-an-existing-section) / [`WithTree`](../areas/trees.md#extending-an-existing-tree) API to create more logical API groupings and to set context for some APIs. +- Added [`AddTree`](../areas/trees.md#adding-a-tree-to-an-existing-section) support to allow adding a tree to an existing section (currently only able to add 1 Konstrukt tree per section). +- Added [Tree Group](../areas/trees.md#adding-a-group-to-a-tree) support to allow grouping root-level tree folders/collections. +- Added [Tab Sidebar](../collections/editors.md#configuring-a-sidebar-to-a-tab) support to allow showing metadata on the right-hand side of the editor. +- Added file upload support to the actions dialog +- Added a basic [Comma-separated values (CSV) Import](../actions/inbuilt-actions.md#konstruktimportentityaction) action +- Added [`HideLabel`](../collections/editors.md#hiding-the-label-of-a-field) support to editor fields to explicitly hide the label. +- Added explicit Insert / Update methods to IKonstruktRepository. Internally we use these now instead of the Save method as the Save method isn't reliably able to determine if an entity is new. +- Added better support for transient / scoped repository dependencies (example: better support for EF Core DB contexts which are by default registered as scoped) +- Obsoleted root-level APIs for `AddSection`, `AddDashboard` and `AddVirtualSubTree` which have now moved to sub-configurations of the [`WithSection`](../areas/sections.md#extending-an-existing-section) or [`WithTree`](../areas/trees.md#extending-an-existing-tree) APIs. +- Fixed bug with DataViews resolving the wrong filter when using groups and the data view has the same name as a view in a different group. We now prefix the data view alias with the group name to ensure uniqueness across groups. +- Fixed bug in child collections creating dialog thinking it was always editing an existing entity and so wrongfully trying to load an entity from the DB due to the fact the entity ID passed through to the dialog "0" when it should be "-1". + +## v1.3.0 + +**Date:** 2022-07-06 +**Description:** Minor release with additional features and bug fixes + +- Added [Virtual Sub Trees](../advanced/virtual-sub-trees.md) support +- Fixed save/delete notification events being passed the wrong model +- Fixed bug where connection strings with no provider cause an error + +## v1.2.0 + +**Date:** 2022-06-20 +**Description:** Minor release with some breaking changes / additional features + +- Added `DeletedProperty` support where the column type is an `int`, and the value is a unix timestamp +- Fixed bug with encrypted properties not handling `null` values +- **[Breaking]** - Updated minimum Umbraco dependency to v10 +- **[Breaking]** - Updated UI assets to be a (RCL) Razor Compiled Library. **Be sure to clean your solution to remove old files**. + +## v1.1.1 + +**Date:** 2022-06-08 +**Description:** Minor patch release with non-breaking changes + +- Added client-side required / regex validation support +- Added support for nullable types when mapping property filters +- Added support for passing notification messages back from action results +- Fixed SQL escaping issue when using table names with schema prefix +- Fixed a bug in range property filters when a value is `null` +- Fixed a bug where save operations would show a success notification even if the save operation failed +- Fixed a bug in Data Attribute validation where `IServiceProvider` wasn't being passed through +- Fixed `null` error when searching returns no items +- Fixed deleted property filter condition not working +- Fixed bug where encrypted properties would throw an exception if the value was `null` + +## v1.1.0 + +**Date:** 2022-05-03 +**Description:** Minor release with some breaking changes / additional features + +- Added field views support for custom field markup in list views +- Added new consistent actions API +- Added row actions support +- Added filterable properties support +- Fixed entity picker value converter not working +- Fixed JS error when editing content due to bad null checking in the Konstrukt `redirectId` interceptor +- Deprecated List View Layout support +- **[Breaking]** - Obsoleted bulk actions and menu items in favour of new actions API +- **[Breaking]** - Moved actions, data views and cards configuration out of list views onto collections API + +## v1.0.2 + +**Date:** 2022-04-11 +**Description:** Minor patch release with non-breaking changes + +- Fixed OrderBy not handling name field correctly +- Updated license warning to only display if the number of "editable" collections is exceeded +- Fixed custom connection strings not working by implementing a DB factory pattern +- Introduced `IKonstruktNodeUdiResolver` to allow content apps to resolve a different node UDI than the current page +- Fixed error being thrown by menu actions because the current section wasn't being passed through to the menu + +## v1.0.1 + +**Date:** 2022-01-27 +**Description:** Minor patch release with non-breaking changes + +- Fixed bug where section/tree registration can sometimes occur twice resulting in an error. +- Removed licensing header when using a single collection. +- Fixed bug with `ORDER BY 1` causing SQL exceptions + +## v1.0.0 + +**Date:** 2022-01-20 +**Description:** Major new release + +- Initial release diff --git a/16/umbraco-ui-builder/collections/child-collection-groups.md b/16/umbraco-ui-builder/collections/child-collection-groups.md new file mode 100644 index 00000000000..0749436948d --- /dev/null +++ b/16/umbraco-ui-builder/collections/child-collection-groups.md @@ -0,0 +1,53 @@ +--- +description: Configuring child collection groups in Umbraco UI Builder. +--- + +# Child Collection Groups + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A child collection group is a container for other child collections. Its purpose is mainly to provide a logical grouping of multiple child collections to help with organization and an improved user experience. + +![Child Collection Groups](../images/child_collection_groups.png) + +## Defining a Child Collection Group + +You can define a child collection group by calling one of the `AddChildCollectionGroup` methods on a given collection config builder instance. + +### Using the `AddChildCollectionGroup()` Method + +Adds a child collection group to the current collection with the specified name and default icon. + +#### Method Syntax + +```cs +AddChildCollectionGroup(string name, Lambda childCollectionGroupConfig = null) : ChildCollectionGroupConfigBuilder +``` + +#### Example + +```csharp +collectionConfig.AddChildCollectionGroup("Family", childCollectionGroupConfig => { + ... +}); +``` + +### Using the `AddChildCollectionGroup()` Method with Custom Icon + +Adds a child collection group to the current collection with the specified name and custom icon. + +#### Method Syntax + +```cs +AddChildCollectionGroup(string name, string icon, Lambda childCollectionGroupConfig = null) : ChildCollectionGroupConfigBuilder +``` + +#### Example + +```csharp +collectionConfig.AddChildCollectionGroup("Family", "icon-users", childCollectionGroupConfig => { + ... +}); +``` diff --git a/16/umbraco-ui-builder/collections/child-collections.md b/16/umbraco-ui-builder/collections/child-collections.md new file mode 100644 index 00000000000..843b50fb046 --- /dev/null +++ b/16/umbraco-ui-builder/collections/child-collections.md @@ -0,0 +1,59 @@ +--- +description: Configuring child collections in Umbraco UI Builder. +--- + +# Child Collections + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +A child collection is a container for data models that are tied to a parent collection. The child collection system shares the [Collections](the-basics.md) API, offering flexibility for managing and displaying related data within your backoffice UI. + +![Child Collections](../images/child_collections.png) + +By default, child collections are displayed as context apps within the parent model's editor view. If multiple child collections lead to an overcrowded context apps area, consider using the [Child Collection Groups API](child-collection-groups.md). Using the API, you can group related child collections under a single context app, with each child collection appearing in separate tabs. + +## Defining a Child Collection + +To define a child collection, use the `AddChildCollection` method on the given collection config builder instance. + +### Using the `AddChildCollection()` Method + +This method adds a child collection with the specified names, description, and default icons. Both the entity ID and foreign key fields must be specified using property accessor expressions. + +#### Method Syntax + +```cs +AddChildCollection(Lambda idFieldExpression, Lambda fkFieldExpression, string nameSingular, string namePlural, string description, Lambda childCollectionConfig = null) : ChildCollectionConfigBuilder +``` + +#### Example + +```csharp +collectionConfig.AddChildCollection(c => c.Id, c => c.ParentId, "Child", "Children", "A collection of children", childCollectionConfig => { + ... +}); +``` + +### Using the `AddChildCollection()` Method with Custom Icons + +This method adds a child collection to the current collection with the specified names, description and custom icons. Both the entity ID and foreign key fields must be specified using property accessor expressions. + +#### Method Syntax + +```cs +AddChildCollection(Lambda idFieldExpression, Lambda fkFieldExpression, string nameSingular, string namePlural, string description, string iconSingular, string iconPlural, Lambda childCollectionConfig = null) : ChildCollectionConfigBuilder +``` + +#### Example + +```csharp +collectionConfig.AddChildCollection(c => c.Id, c => c.ParentId, "Child", "Children", "A collection of children", "icon-umb-users", "icon-umb-users", childCollectionConfig => { + ... +}); +``` + +## Configuring a Child Collection + +Child collections share the same API as the `Collection` config builder API, except child collections cannot contain further child collections. For more information, see the [Basics](the-basics.md) article. diff --git a/16/umbraco-ui-builder/collections/editors.md b/16/umbraco-ui-builder/collections/editors.md new file mode 100644 index 00000000000..88cb56c92d3 --- /dev/null +++ b/16/umbraco-ui-builder/collections/editors.md @@ -0,0 +1,427 @@ +--- +description: Configuring the editor of a collection in Umbraco UI Builder. +--- + +# Editors + +An editor is the user interface used to edit an entity. It consists of tabs and property editors. + +![A collection editor](../images/editor.png) + +## Configuring an Editor + +The editor configuration is a sub-configuration of a [`Collection`](the-basics.md) config builder instance and is accessed via the `Editor` method. + +### Using the `Editor()` Method + +Accesses the editor configuration for the specified collection. + +#### Method Syntax + +```cs +Editor(Lambda editorConfig = null) : EditorConfig +``` + +#### Example + +````csharp +collectionConfig.Editor(editorConfig => { + ... +}); +```` + +## Adding a Tab to an Editor + +### Using the `AddTab()` Method + +Adds a tab to the editor. + +#### Method Syntax + +```cs +AddTab(string name, Lambda tabConfig = null) : EditorTabConfigBuilder +``` + +#### Example + +````csharp +editorConfig.AddTab("General", tabConfig => { + ... +}); +```` + +## Configuring a Sidebar to a Tab + +A sidebar is a smaller section displayed on the right side of the main editor. It can contain fieldsets and fields, similar to tabs, but with limited space. The sidebar is ideal for displaying entity metadata. + +### Using the `Sidebar()` Method + +Configures the sidebar for the tab. + +#### Method Syntax + +```cs +Sidebar(Lambda sidebarConfig = null) : EditorTabSidebarConfigBuilder +``` + +#### Example + +````csharp +tabConfig.Sidebar(sidebarConfig => { + ... +}); +```` + +## Setting the Visibility of a Tab + +### Using the `SetVisibility()` Method for Tabs + +Determines the visibility of the tab at runtime. + +#### Method Syntax + +```cs +SetVisibility(Predicate visibilityExpression) : EditorTabConfigBuilder +``` + +#### Example + +````csharp +tabConfig.SetVisibility(ctx => ctx.EditorMode == EditorMode.Create); +```` + +## Adding a Fieldset to a Tab + +### Using the `AddFieldset()` Method + +Adds a fieldset to a tab. + +#### Method Syntax + +```cs +AddFieldset(string name, Lambda fieldsetConfig = null) : EditorFieldsetConfigBuilder +``` + +#### Example + +````csharp +tabConfig.AddFieldset("Contact", fieldsetConfig => { + ... +}); +```` + +## Setting the Visibility of a Fieldset + +### Using the `SetVisibility()` Method for Fieldsets + +Determines the visibility of a fieldset at runtime. + +#### Method Syntax + +```cs +SetVisibility(Predicate visibilityExpression) : EditorFieldsetConfigBuilder +``` + +#### Example + +````csharp +fieldsetConfig.SetVisibility(ctx => ctx.EditorMode == EditorMode.Create); +```` + +## Adding a Field to a Fieldset + +### Using the `AddField()` Method + +Adds a property field to the editor. + +#### Method Syntax + +```cs +AddField(Lambda propertyExpression, Lambda propertyConfig = null) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldsetConfig.AddField(p => p.FirstName, fieldConfig => { + ... +}); +```` + +## Changing the Label of a Field + +By default, Umbraco UI Builder converts property names into readable labels by splitting camel case names. You can override this behavior by setting an explicit label. + +### Using the `SetLabel()` Method + +Sets a custom label for a field. + +#### Method Syntax + +```cs +SetLabel(string label) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetLabel("First Name"); +```` + +## Hiding the Label of a Field + +Sometimes, a field works better without a label, especially in full-width layouts. + +### Using the `HideLabel()` Method + +Hides the field label. + +#### Method Syntax + +```cs +HideLabel() : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.HideLabel(); +```` + +## Adding a Description to a Field + +### Using the `SetDescription()` Method + +Adds a description to the field. + +#### Method Syntax + +```cs +SetDescription(string description) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetDescription("Enter your age in years"); +```` + +## Changing the Data Type of a Field + +By default, Umbraco UI Builder assigns a suitable Data Type for basic field types. However, you can specify a custom Data Type. + +### Using the `SetDataType()` Method + +Assigns an Umbraco Data Type by name or ID. + +#### Method Syntax (by name) + +```cs +SetDataType(string dataTypeName) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetDataType("Richtext Editor"); +```` + +#### Method Syntax (by ID) + +```cs +SetDataType(int dataTypeId) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp + +fieldConfig.SetDataType(-88); +```` + +## Setting the Default Value of a Field + +### Using the `SetDefaultValue()` Method + +Sets a static default value. + +#### Method Syntax + +```cs +SetDefaultValue(TValueType defaultValue) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +// Example +fieldConfig.SetDefaultValue(10); +```` + +### Using the `SetDefaultValue()` Method (Function-Based) + +Defines a function to compute the default value at the time of entity creation. + +#### Method Syntax + +```cs +SetDefaultValue(Func defaultValueFunc) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetDefaultValue(() => DateTime.Now); +```` + +## Making a Field Required + +### Using the `MakeRequired()` Method + +Marks a field as required. + +#### Method Syntax + +```cs +MakeRequired() : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.MakeRequired(); +```` + +## Validating a Field + +### Using the `SetValidationRegex()` Method + +Applies a regular expression for field validation. + +#### Method Syntax + +```cs +SetValidationRegex(string regex) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetValidationRegex("[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}"); +```` + +## Making a Field Read-only + +### Using the `MakeReadOnly()` Method + +This method makes the current field read-only, preventing any user modifications in the UI. Once applied, the field's value remains visible but cannot be edited. + +#### Method Syntax + +```cs +MakeReadOnly() : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.MakeReadOnly(); +```` + +### Using the `MakeReadOnly(Func)` Method + +This method makes the current field read-only, preventing user edits in the UI. Additionally, it allows specifying a custom formatting expression, which determines how the field value is displayed as a string. + +#### Method Syntax + +```cs +MakeReadOnly(Func format) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.MakeReadOnly(distanceProp => $"{distanceProp:## 'km'}"); +```` + +### Using the `MakeReadOnly(object dataTypeNameOrId)` Method + +This method makes the current field read-only, preventing user edits in the UI. Additionally, it allows specifying a Data Type name or ID to determine how the field should be rendered when in read-only mode. + +#### Method Syntax + +```cs +MakeReadOnly(object dataTypeNameOrId) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.MakeReadOnly("myReadOnlyEditor"); +```` + +### Using the `MakeReadOnly(Predicate<>)` Method + +This method makes the current field read-only in the UI if the provided runtime predicate evaluates to true, preventing user edits. + +#### Method Syntax + +```cs +MakeReadOnly(Predicate readOnlyExp) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.MakeReadOnly(ctx => ctx.EditorMode == EditorMode.Create); +```` + +### Using the `MakeReadOnly(Predicate<>, Func<>)` Method + +This method makes the current field read-only in the UI if the provided runtime predicate evaluates to true, preventing user edits. It also allows specifying a custom formatting expression to render the field’s value as a string. + +#### Method Syntax + +```cs +MakeReadOnly(Predicate readOnlyExp, Func format) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.MakeReadOnly(ctx => ctx.EditorMode == EditorMode.Create, distanceProp => $"{distanceProp:## 'km'}"); +```` + +### Using the `MakeReadOnly(Predicate<>, Func<>)` Method + +This method makes the current field read-only in the UI if the provided runtime predicate evaluates to true, preventing user edits. It also allows specifying a Data Type name or ID to use when the field is in read-only mode. + +#### Method Syntax + +```cs +MakeReadOnly(Predicate readOnlyExp, object dataTypeNameOrId) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.MakeReadOnly(ctx => ctx.EditorMode == EditorMode.Create, "myReadOnlyEditor"); +```` + +## Setting the Visibility of a Field + +### Using the `SetVisibility()` Method for Fields + +Controls field visibility at runtime. + +#### Method Syntax + +```cs +SetVisibility(Predicate visibilityExpression) : EditorFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetVisibility(ctx => ctx.EditorMode == EditorMode.Create); +```` diff --git a/16/umbraco-ui-builder/collections/entity-identifier-converters.md b/16/umbraco-ui-builder/collections/entity-identifier-converters.md new file mode 100644 index 00000000000..a1cb38c5447 --- /dev/null +++ b/16/umbraco-ui-builder/collections/entity-identifier-converters.md @@ -0,0 +1,36 @@ +--- +description: Using Umbraco entities as reference with an UI Builder collection +--- + +# Entity Identifier Converters + +Umbraco stores identifiers in UDI format for most Umbraco object types. + +You can read more about them in the [UDI Identifiers](../../umbraco-cms/reference/querying/udi-identifiers.md) section of the documentation. + +If you want to reference an Umbraco object in your model and retrieve its `Integer` or `Guid` value, you must convert the `UDI` value. + +Use one of UI Builder's converters - `EntityIdentifierToIntTypeConverter` or `EntityIdentifierToGuidTypeConverter`. Add it as a `[TypeConverterAttribute]` to your model's foreign key property. + +An entity that references an Umbraco object would look like this: + +```csharp + [TableName(TableName)] + [PrimaryKey("Id")] + public class MemberReview + { + public const string TableName = "MemberReview"; + + [PrimaryKeyColumn] + public int Id { get; set; } + + public string Title { get; set; } + + public string Content { get; set; } + + [TypeConverter(typeof(EntityIdentifierToIntTypeConverter))] + public int MemberId { get; set; } + } +``` + +You can also create a custom type converter. UI Builder will handle data persistence automatically. diff --git a/16/umbraco-ui-builder/collections/field-views.md b/16/umbraco-ui-builder/collections/field-views.md new file mode 100644 index 00000000000..4964d1a66e2 --- /dev/null +++ b/16/umbraco-ui-builder/collections/field-views.md @@ -0,0 +1,68 @@ +--- +description: Configuring Field Views in Umbraco UI Builder. +--- + +# Field Views + +Field Views allow customization of the markup used by a field when displayed in a list view. Field Views are implemented as .NET Core View Components, which are passed a `FieldViewsContext` argument containing information about the entity/field being rendered. + +## Defining a Field View + +You can define a field view in one of two ways: + +### Basic View File for the Built-In `FieldView` View Component + +For field views, place a view file in the `/Views/Shared/Components/FieldView` folder with the following markup. + +````csharp +@model Umbraco.UIBuilder.Web.Models.FieldViewContext + +```` + +WTo register the view, pass the name of the view file (excluding the `.cshtml` file extension) to the relevant API method. + +### Custom View Component + +For more complex field views, create a custom view component class that can use dependency injection for any required dependencies. Use the following signature: + +````csharp +// Example +public class MyComplexFieldViewViewComponent : ViewComponent +{ + public async Task InvokeAsync(FieldViewContext context) + { + // Do your custom logic here + + return View("Default", model); + } +} +```` + +{% hint style="info" %} +The `FieldViewContext` parameter in the `InvokeAsync` method **must** be named `context`. +{% endhint %} + +For the view component, place a `Default.cshtml` file into the `/Views/Shared/Components/MyComplexFieldView` folder with the following markup: + +````csharp +@model Namespace.Of.Model.Returned.By.Custom.ViewComponent + +```` + +## The Field View Context + +Field view components are passed a `FieldViewContext` object with the following properties: + +````csharp +public class FieldViewContext +{ + public string ViewName { get; set; } + public object Entity { get; set; } + public string PropertyName { get; set; } + public object PropertyValue { get; set; } +} +```` + +## Setting the Field View of a List View Field + +A field view is assigned to a list view field as part of the list view configuration. For more information, see the [List Views](list-views.md#setting-the-view-of-a-field) article. diff --git a/16/umbraco-ui-builder/collections/list-view-layouts.md b/16/umbraco-ui-builder/collections/list-view-layouts.md new file mode 100644 index 00000000000..f37338992f0 --- /dev/null +++ b/16/umbraco-ui-builder/collections/list-view-layouts.md @@ -0,0 +1,50 @@ +--- +description: Configuring list view layouts in Umbraco UI Builder, the backoffice UI builder for Umbraco. +--- + +# List View Layouts + +{% hint style="danger" %} +**List View Layouts** in Umbraco UI Builder are now considered deprecated. Moving forward, only the table list view will be supported. Whilst you can continue to use this feature for the time being, it will be removed in a future release. +{% endhint %} + +List view layouts allow you to provide custom angular views to be used by the list view UI. By default, there are two built-in layouts, `TableListViewLayout` which displays results in a tabular layout, and `GridListViewLayout` which displays results in a tiled grid layout. + +## Defining a list view layout + +To define a list view layout you create a class that inherits from the base class `ListViewLayout` and implements the abstract configuration properties. + +````csharp +// Example +public class MyCustomListViewLayout : ListViewLayout +{ + public GridListViewLayout() + { + Name = "My Custom List"; + Alias = "my-custom-list"; + Icon = "icon-list"; + View = "/app_plugins/myplugin/views/mycustomlist.htm"; + } +} +```` + +The required configuration options are: + +* **Name:** The name of the layout. +* **Alias:** A unique alias for the layout. +* **Icon:** An icon to display in the list view layouts dropdown. +* **View:** The path of the angular view to load by the list view. + +As well as defining the list view layout class you will also need to implement the relevant angular view and controller. This is a little out of scope for the Umbraco UI Builder documentation, however in summary you will need to: + +* Create a plugin folder in the root `App_Plugin` folder. +* Create a `package.manifest` file in your plugin folder. +* Create a HTML view to be loaded. +* Create an angular controller to control the view. +* Hook up the controller with the view using the `ng-controller` attribute. +* Add the controller JS file path to the `package.manifest`. +* Build your custom logic. + +## Changing the list view layout of a list view + +A list view layout is assigned to a list view as part of the list view configuration. For more information you can check the [List View API Documentation](list-views.md#changing-the-list-view-layout). diff --git a/16/umbraco-ui-builder/collections/list-views.md b/16/umbraco-ui-builder/collections/list-views.md new file mode 100644 index 00000000000..bfa6638e8fa --- /dev/null +++ b/16/umbraco-ui-builder/collections/list-views.md @@ -0,0 +1,159 @@ +--- +description: Configuring the list view of a collection in Umbraco UI Builder. +--- + +# List Views + +A list view displays a collection entity in a list format and includes features like pagination, custom data views, searching, and bulk actions. + +![A collection list view](../images/listview.png) + +## Configuring a List View + +The list view configuration is a sub-configuration of a [`Collection`](the-basics.md) config builder instance and can be accessed via the `ListView` method. + +### Using the `ListView()` Method + +Accesses the list view configuration for the specified collection. + +#### Method Syntax + +```cs +ListView(Lambda listViewConfig = null) : ListViewConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.ListView(listViewConfig => { + ... +}); +```` + +## Adding a Field to the List View + +### Using the `AddField()` Method + +Adds a specified property to the list view. + +#### Method Syntax + +```cs +AddField(Lambda propertyExpression, Lambda fieldConfig = null) : ListViewFieldConfigBuilder +``` + +#### Example + +````csharp +listViewConfig.AddField(p => p.FirstName, fieldConfig => { + ... +}); +```` + +## Changing the Heading of a Field + +### Using the `SetHeading()` Method + +Sets the heading for a field in the list view. + +#### Method Syntax + +```cs +SetHeading(string heading) : ListViewFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetHeading("First Name"); +```` + +## Formatting the Value of a Field + +### Using the `SetFormat()` Method + +Sets the format expression to the field in the list view. + +#### Method Syntax + +```cs +SetFormat(Lambda formatExpression) : ListViewFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetFormat((v, p) => $"{v} years old"); +```` + +## Setting the View of a Field + +You can customize the field's markup with field views, allowing richer visualizations of the content. For more details, see the [Field Views](field-views.md) article. + +### Using the `SetView()` Method + +Sets the view component for the list view field. + +#### Method Syntax + +```cs +SetView(string viewComponentName) : ListViewFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetView("ImageFieldView"); +```` + +### Using the `SetView()` Method + +Sets the view component for the list view field. + +#### Method Syntax + +```cs +SetView() : ListViewFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetView(); +```` + +## Setting the Visibility of a Field + +### Using the `SetVisibility()` Method + +Controls the runtime visibility of a field in the list view. + +#### Method Syntax + +```cs +SetVisibility(Predicate visibilityExpression) : ListViewFieldConfigBuilder +``` + +#### Example + +````csharp +fieldConfig.SetVisibility(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +## Changing the Page Size + +### Using the `SetPageSize` Method + +Sets the number of items per page for the list view. + +#### Method Syntax + +```cs +SetPageSize(int pageSize) : ListViewConfigBuilder +``` + +#### Example + +````csharp +listViewConfig.SetPageSize(20); +```` diff --git a/16/umbraco-ui-builder/collections/overview.md b/16/umbraco-ui-builder/collections/overview.md new file mode 100644 index 00000000000..b713e6a56a9 --- /dev/null +++ b/16/umbraco-ui-builder/collections/overview.md @@ -0,0 +1,17 @@ +--- +description: Configuring collection in Umbraco UI Builder to manage entity groups and define their UI integration. +--- + +# Collections + +A collection in Umbraco UI Builder represents a group of entities for a specific data model. It serves as the primary configuration object for defining how the collection integrates into the UI. + +You can configure its list view appearance and editing options. + +![A collection list view](../images/listview.png) + +Get started by reviewing the basics of collection configuration. + +{% content-ref url="the-basics.md" %} +[the-basics.md](the-basics.md) +{% endcontent-ref %} diff --git a/16/umbraco-ui-builder/collections/related-collections.md b/16/umbraco-ui-builder/collections/related-collections.md new file mode 100644 index 00000000000..f86baf799dc --- /dev/null +++ b/16/umbraco-ui-builder/collections/related-collections.md @@ -0,0 +1,200 @@ +--- +description: Configuring Many-to-Many Relationships in Umbraco UI Builder +--- + +# Related Collections + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +Related collections support the editing of many-to-many relationships in UI Builder. These are used when multiple entities from one collection are linked to multiple entities from another collection, commonly represented through a junction table. + +## Example Use Case + +A classic example is the relationship between `Students` and `Courses`, where each student takes many courses, and each course has many students. + +![Child Collection](../images/related_collections_child.png) + +![Parent Collection](../images/related_collections_parent.png) + +![Entity Picker](../images/entity_picker_config.png) + +## Collections Representation + +This is how the collections would be represented: + +![Related Collections Diagram](../images/related_collections_diagram.png) + +The models representing the entities would be as follows: + +```csharp +[TableName("Students")] +[PrimaryKey("Id")] +public class Student +{ + [PrimaryKeyColumn] + public int Id { get; set; } + + public string FirstName { get; set; } + + public string LastName { get; set; } + + public string Email { get; set; } +} +``` + +```csharp +[TableName("Courses")] +[PrimaryKey("Id")] +public class Course +{ + [PrimaryKeyColumn] + public int Id { get; set; } + + public string Title { get; set; } + + public string Description { get; set; } +} +``` + +```csharp +[TableName("StudentsCourses")] +[PrimaryKey(new[] { "StudentId", "CourseId" })] +public class StudentCourse +{ + [PrimaryKeyColumn] + public int StudentId { get; set; } + + [PrimaryKeyColumn] + public int CourseId { get; set; } +} +``` + +## Defining a Related Collection + +To define a related collection, follow these two steps: + +1. Add the collection definition +2. Add the related collection entity picker and definition + +### Collection definition + +Define a related collection by calling the `AddRelatedCollection` method on the collection config builder instance. + +### Using the `AddRelatedCollection()` Method + +This method adds a related collection to the current collection, specifying names, descriptions, and default icons. The ID property must be defined, and the relation configuration defines the junction entity with references to parent and child entities. + +#### Method Syntax + +```cs +AddRelatedCollection(Expression> idPropertyExpression, string nameSingular, string namePlural, Action> relationConfig) +``` + +#### Example + +```csharp +collectionConfig.AddRelatedCollection(x => x.Id, "Student Course", "Students Courses", relationConfig => +{ + relationConfig + .SetAlias("studentsCourses") + .SetJunction(x => x.StudentId, y => y.CourseId); +}); +``` + +### Configuring a Related Collection Entity Picker + +Define the child collection entity picker by calling the `AddRelatedCollectionPickerField` method on the parent collection's fieldset config. + +### Using the `AddRelatedCollectionPickerField()` Method + +This method adds an entity picker with the specified Data Type name to the parent collection editor. + +#### Method Syntax + +```cs +AddRelatedCollectionPickerField(string alias, string dataTypeName, string label) +``` + +#### Example + +```csharp +collectionConfig.Editor(editorConfig => +{ + editorConfig.AddTab("General", tabConfig => + tabConfig.AddFieldset("General", fieldsetConfig => + { + fieldsetConfig.AddField(x => x.FirstName).MakeRequired(); + fieldsetConfig.AddField(x => x.LastName).MakeRequired(); + fieldsetConfig.AddField(x => x.Email).MakeRequired(); + + fieldsetConfig.AddRelatedCollectionPickerField("studentsCourses", "Courses Related Picker", "Courses"); + })); +}); +``` + +{% hint style="info" %} +The relation config alias must match the related collection picker field alias, for example, `studentsCourses`. +{% endhint %} + +## Defining Repository Methods + +### Using the `GetRelationsByParentIdImpl<>()` Method + +Retrieves related collections based on the ID of the parent entity. + +#### Method Syntax + +```cs +IEnumerable GetRelationsByParentIdImpl(int parentId, string relationAlias) +``` + +#### Example + +```csharp +{ + var db = _scopeProvider.CreateScope().Database; + var sql = db.SqlContext.Sql() + .Select(new[] { "StudentId", "CourseId" } ) + .From("StudentsCourses") + .Where($"studentId = @0", parentId); + + var result = db.Fetch(sql); + + return result; +} +``` + +### Using the `SaveRelationImpl<>()` Method + +Adds a new related collection to the current parent entity. + +#### Method Syntax + +```cs +StudentCourse SaveRelationImpl(StudentCourse entity) +``` + +#### Example + +```csharp +{ + var db = _scopeProvider.CreateScope().Database; + + var type = entity.GetType(); + var studentId = type.GetProperty("StudentId").GetValue(entity); + var courseId = type.GetProperty("CourseId").GetValue(entity); + + // delete relation if exists + db.Execute("DELETE FROM StudentsCourses WHERE StudentId = @0 AND CourseId = @1", + studentId, + courseId); + + db.Execute("INSERT INTO StudentsCourses (StudentId, CourseId) VALUES (@0, @1)", + studentId, + courseId); + + return entity; +} +``` diff --git a/16/umbraco-ui-builder/collections/retrieve-child-collections.md b/16/umbraco-ui-builder/collections/retrieve-child-collections.md new file mode 100644 index 00000000000..aa2a195417a --- /dev/null +++ b/16/umbraco-ui-builder/collections/retrieve-child-collections.md @@ -0,0 +1,87 @@ +--- +description: Configuring one-to-many relationships in Umbraco UI Builder. +--- + +# Retrieve Child Collections + +{% hint style="warning" %} +This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. +{% endhint %} + +In one-to-many relationships, a parent entity is associated with multiple entities from another collection. In Umbraco UI Builder, retrieving child collections from such relationships is supported through child repositories. This enables you to access related data effectively, helping to maintain a well-organized backoffice UI. + +## Models Representation + +For a one-to-many relationship, you typically have two models: one for the parent entity and one for the child entity. + +```csharp +[TableName("Students")] +[PrimaryKey("Id")] +public class Student +{ + [PrimaryKeyColumn] + public int Id { get; set; } + + public string FirstName { get; set; } + + public string LastName { get; set; } + + public string Email { get; set; } +} +``` + +In the above example, the `Student` model represents the parent entity. A student can have multiple associated `StudentProjects`. + +```csharp +[TableName("StudentProjects")] +[PrimaryKey("Id")] +public class StudentProject +{ + [PrimaryKeyColumn] + public int Id { get; set; } + + public string Name { get; set; } + + public int StudentId { get; set; } +} +``` + +The `StudentProjects` model represents the child entity. The `StudentId` is a foreign key that links each `StudentProject` to the `Student` entity, establishing the one-to-many relationship. + +## Child Repositories + +To retrieve data from child collections, you can use the `IRepositoryFactory` to create child repository instances. These repositories provide methods to fetch child entities associated with a given parent entity. + +```csharp +public class StudentProjectController : Controller +{ + private readonly IRepositoryFactory _repositoryFactory; + + public StudentProjectController(IRepositoryFactory repositoryFactory) + { + _repositoryFactory = repositoryFactory; + } + + public IActionResult Index(int projectId) + { + var childRepository = _repositoryFactory.GetChildRepository(projectId); + + var list = childRepository.GetAll(); + + var count = childRepository.GetCount(); + + var listPaged = childRepository.GetPaged(); + + return View(list); + } +} +``` + +In this example: + +- The `StudentProjectController` is using the `IRepositoryFactory` to create a child repository for `StudentProject`. +- The `GetAll()`method retrieves all child entities related to the given parent. +- The `GetCount()` method returns the total number of child entities associated with the parent. +- The `GetPaged()` method allows for pagination of child entities, making it easier to manage large sets of data. + +This structure allows efficient retrieval and management of child entities, providing a well-organized way to interact with related data in Umbraco's backoffice. diff --git a/16/umbraco-ui-builder/collections/the-basics.md b/16/umbraco-ui-builder/collections/the-basics.md new file mode 100644 index 00000000000..891ed996608 --- /dev/null +++ b/16/umbraco-ui-builder/collections/the-basics.md @@ -0,0 +1,403 @@ +--- +description: An overview of the basics of configuring a collection in Umbraco UI Builder. +--- + +# The Basics + +A collection configuration in Umbraco UI Builder defines how collections are structured and displayed in the backoffice. This guide covers the core concepts, with additional options available in other configuration sections. + +## Defining a Collection + +A collection is defined using the `AddCollection` method on a [`Tree`](../areas/trees.md) or parent [`Folder`](../areas/folders.md) configuration instance. + +### Using the `AddCollection()` Method + +Adds a collection to the given container with the specified names, description, and default icons. The ID property must be defined. + +#### Method Syntax + +```cs +AddCollection(Lambda idFieldExpression, string nameSingular, string namePlural, string description, Lambda collectionConfig = null) : CollectionConfigBuilder +``` + +#### Example + +````csharp +folderConfig.AddCollection(p => p.Id, "Person", "People", "A collection of people", collectionConfig => { + ... +}); +```` + +### Using the `AddCollection()` Method with Icons + +Adds a collection to the given container with the specified names, description, and icons. The ID property must be defined. + +#### Method Syntax + +```cs +AddCollection(Lambda idFieldExpression, string nameSingular, string namePlural, string description, string iconSingular, string iconPlural, Lambda collectionConfig = null) : CollectionConfigBuilder +``` + +#### Example + +````csharp +folderConfig.AddCollection(p => p.Id, "Person", "People", "A collection of people", "icon-umb-users", "icon-umb-users", collectionConfig => { + ... +}); +```` + +## Changing a Collection Alias + +### Using the `SetAlias()` Method + +Sets the alias of the collection. + +**Optional:** When creating a new collection, an alias is automatically generated from the supplied name for you. To customize the alias, the `SetAlias` method can be used. + +#### Method Syntax + +```cs +SetAlias(string alias) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetAlias("person"); +```` + +## Changing a Collection Icon Color + +### Using the `SetIconColor()` Method + +Sets the collection icon color to the given color. The available options are `black`, `green`, `yellow`, `orange`, `blue`, or `red`. + +#### Method Syntax + +```cs +SetIconColor(string color) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetIconColor("blue"); +```` + +## Defining an Entity Name + +In Umbraco, every entity is expected to have a name property. To ensure the Umbraco UI Builder knows which property to use, you must specify it. + +If the entity lacks a dedicated name property, you can define how to construct a name using other properties. This is done using either the `SetNameProperty` or `SetNameFormat` methods on a `Collection` config builder instance. + +### Using the `SetNameProperty()` Method + +Specifies the entity property to use as the name, which must be of type `string`. This property serves as the label in trees and list views, appears in the editor interface header, and is automatically included in searchable properties. It is also used as the default sorting property. + +#### Method Syntax + +```cs +SetNameProperty(Lambda namePropertyExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetNameProperty(p => p.Name); +```` + +### Using the `SetNameProperty()` Method with Custom Heading + +Specifies which property of your entity should be used as the name property and defines a custom heading for the list view column. The property must be of type `string`. + +Setting a name property ensures its value is displayed as the label for the entity in trees and list views. It will also be editable in the editor interface's header region. + +Additionally, the property is automatically added to the searchable properties collection and used as the default sort property. + +#### Method Syntax + +```cs +SetNameProperty(Lambda namePropertyExpression, string heading) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetNameProperty(p => p.Name, "Person Name"); +```` + +### Using the `SetNameFormat()` Method + +Defines a format expression to dynamically generate a label for the entity in trees and list views. + +This method is used when there is no single name property available on the entity. As a result, none of the default behaviors of the `SetNameProperty` method, such as automatic sorting, searching, or header editing, will apply. + +#### Method Syntax + +```cs +SetNameFormat(Lambda nameFormatExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetNameFormat(p => $"{p.FirstName} {p.LastName}"); +```` + +## Defining a Default Sort Order + +### Using the `SetSortProperty()` Method + +Specifies the property used to sort the collection, with the default sort direction set to ascending. + +#### Method Syntax + +```cs +SetSortProperty(Lambda sortPropertyExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetSortProperty(p => p.FirstName); +```` + +### Using the `SetSortProperty()` Method with Sort Direction + +Defines the property of the entity to sort by, based on the specified sort direction. + +#### Method Syntax + +```cs +SetSortProperty(Lambda sortPropertyExpression, SortDirection sortDirection) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetSortProperty(p => p.FirstName, SortDirection.Descending); +```` + +## Defining Time Stamp Properties + +### Using the `SetDateCreatedProperty` Method + +Defines the property of the entity to use as the date created field. The property must be of type `DateTime`. When specified, this field will be automatically populated with the current date and time when a new entity is saved via the repository. + +#### Method Syntax + +```cs +SetDateCreatedProperty(Lambda dateCreatedProperty) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetDateCreatedProperty(p => p.DateCreated); +```` + +### Using the `SetDateModifiedProperty` Method + +Defines the property of the entity to use as the date modified field. The property must be of type `DateTime`. When specified, this field will be updated with the current date and time whenever the entity is saved via the repository. + +#### Method Syntax + +```cs +SetDateModifiedProperty(Lambda dateCreatedProperty) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetDateModifiedProperty(p => p.DateModified); +```` + +## Configuring Soft Deletes + +By default, entities deleted via the Umbraco UI Builder repository are permanently removed from the system. The `SetDeletedProperty` method marks records as deleted without removing them. This retains them in the data repository while hiding them from the UI. + +### Using the `SetDeletedProperty()` Method + +Defines the property of the entity to use as the deleted flag. The property must be of type `boolean` or `int`. When set, delete actions will mark the entity as deleted by setting the flag instead of removing the entity. + +For `boolean` properties, the flag is set to `True` when deleted. For `int` properties, the flag is set to a UTC Unix timestamp representing the deletion date. Additionally, fetch actions will automatically exclude deleted entities. + +#### Method Syntax + +```cs +SetDeletedProperty(Lambda deletedPropertyExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetDeletedProperty(p => p.Deleted); +```` + +## Disabling Create, Update, or Delete Features + +### Using the `DisableCreate()` Method + +Disables the option to create entities within the current collection. Entities can still be created programmatically, after which editing is allowed through the UI. + +#### Method Syntax + +```cs +DisableCreate() : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.DisableCreate(); +```` + +### Using the `DisableCreate()` Method with Conditions + +Disables entity creation within the current collection if the specified runtime predicate evaluates to true. Entities can still be created programmatically, after which editing is allowed in the UI. + +#### Method Syntax + +```cs +DisableCreate(Predicate disableExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.DisableCreate(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +### Using the `DisableUpdate()` Method + +Disables the option to update entities within the current collection. Entities can be created, but further editing is not permitted + +#### Method Syntax + +```cs +DisableUpdate() : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.DisableUpdate(); +```` + +### Using the `DisableUpdate()` Method with Conditions + +Disables the option to update entities within the current collection if the specified runtime predicate evaluates to true. Entities can be created, but further editing is not permitted. + +#### Method Syntax + +```cs +DisableUpdate(Predicate disableExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.DisableUpdate(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +### Using the `DisableDelete()` Method + +Disables the option to delete entities within the current collection. This is useful when data needs to be retained and visible. For more information, see the [Configuring Soft Deletes](#configuring-soft-deletes) section. + +#### Method Syntax + +```cs +DisableDelete() : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.DisableDelete(); +```` + +### Using the `DisableDelete()` Method with Conditions + +Disables the option to delete entities within the current collection if the specified runtime predicate evaluates to true. This is useful when data needs to be retained and visible. For more information, see the [Configuring Soft Deletes](#configuring-soft-deletes) section. + +#### Method Syntax + +```cs +DisableDelete(Predicate disableExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.DisableDelete(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +### Using the `MakeReadOnly()` Method + +Marks the collection as read-only, disabling all Create, Read, Update, and Delete (CRUD) operations via the UI. + +#### Method Syntax + +```cs +MakeReadOnly() : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.MakeReadOnly(); +```` + +### Using the `MakeReadOnly()` Method with Conditions + +Marks the collection as read-only if the specified runtime predicate evaluates to true. This disables all Create, Read, Update, and Delete (CRUD) operations via the UI. + +#### Method Syntax + +```cs +MakeReadOnly(Predicate disableExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.MakeReadOnly(ctx => ctx.UserGroups.Any(x => x.Alias == "editor")); +```` + +## Setting Collection Visibility + +### Using the `SetVisibility()` Method + +Sets the runtime visibility of the collection. + +#### Method Syntax + +```cs +SetVisibility(Predicate visibilityExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetVisibility(ctx => ctx.UserRoles.Any(x => x.Alias == "editor")); +```` + +## Changing a Collection Connection String + +By default, Umbraco UI Builder uses the Umbraco connection string for its database connection. You can override this by calling the `SetConnectionString` method on a `Collection` config builder instance. + +### Using the `SetConnectionString()` Method + +Defines the connection string for the collection repository. + +#### Method Syntax + +```cs +SetConnectionString(string connectionStringName) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetConnectionString("myConnectionStringName"); +```` diff --git a/16/umbraco-ui-builder/filtering/data-views-builders.md b/16/umbraco-ui-builder/filtering/data-views-builders.md new file mode 100644 index 00000000000..373d946d222 --- /dev/null +++ b/16/umbraco-ui-builder/filtering/data-views-builders.md @@ -0,0 +1,86 @@ +--- +description: Learn how to configure data views builders in Umbraco UI Builder. +--- + +# Data Views Builders + +Data views builders allow you to create a collection’s data views dynamically at runtime. By default, Umbraco UI Builder uses hard-coded data views from the configuration. However, if you need to generate data views dynamically, a data views builder is required. + +When resolving a data views builder, Umbraco UI Builder first attempts to retrieve it from the global Dependency Injection (DI) container. This allows injecting required dependencies into the builder. If no type is defined in the DI container, Umbraco UI Builder falls back to manually instantiating a new instance of the value mapper. + +## Defining a Data Views Builder + +To define a data views builder, create a class that inherits from `DataViewsBuilder` and implements the required abstract methods. + +````csharp +// Example +public class PersonDataViewsBuilder : DataViewsBuilder +{ + public override IEnumerable GetDataViews() + { + // Generate and return a list of data views + } + + public override Expression> GetDataViewWhereClause(string dataViewAlias) + { + // Return a where clause expression for the supplied data view alias + } +} +```` + +The required methods are: + +* **GetDataViews:** Returns the list of data views to choose from. +* **GetDataViewWhereClause:** Returns the boolean **where clause** expression for the given data views alias. + +## Setting the Data Views Builder of a Collection + +Setting a data views builder is controlled via the [Collections](../collections/overview.md) settings. + +### Using the `SetDataViewsBuilder()` Method + +Sets the collection's data views builder, allowing you to define data views dynamically at runtime. + +#### Method Syntax + +```cs +SetDataViewsBuilder() : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetDataViewsBuilder(); +```` + +### Using the `SetDataViewsBuilder(Type)` Method + +Sets the collection's data views builder, allowing you to define data views dynamically at runtime. + +#### Method Syntax + +```cs +SetDataViewsBuilder(Type dataViewsBuilderType) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetDataViewsBuilder(typeof(PersonDataViewsBuilder)); +```` + +### Using the `SetDataViewsBuilder(DataViewsBuilder)` Method + +Sets the collection's data views builder, allowing you to define data views dynamically at runtime. + +#### Method Syntax + +```cs +SetDataViewsBuilder(DataViewsBuilder dataViewsBuilder) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetDataViewsBuilder(new PersonDataViewsBuilder()); +```` diff --git a/16/umbraco-ui-builder/filtering/data-views.md b/16/umbraco-ui-builder/filtering/data-views.md new file mode 100644 index 00000000000..822e123be4c --- /dev/null +++ b/16/umbraco-ui-builder/filtering/data-views.md @@ -0,0 +1,45 @@ +--- +description: Learn how to configure data views in Umbraco UI Builder. +--- + +# Data Views + +Data views allow you to define multiple pre-filtered views of the same data source. This is useful when entities exist in different states and you need a way to toggle between them. + +![Data Views](../images/data_views.png) + +## Defining Data Views + +Data views are defined via the [Collections](../collections/overview.md) settings. + +### Using the `AddDataView()` Method + +Creates a data view with the specified name and a where clause filter expression. The expression must return a `boolean` value. + +#### Method Syntax + +```cs +AddDataView(string name, Lambda whereClauseExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddDataView("Active", p => p.IsActive); +```` + +### Using the `AddDataView()` Method with Group + +Creates a data view within a specified group, using a where clause filter expression. The expression must return a `boolean` value. + +#### Method Syntax + +```cs +AddDataView(string group, string name, Lambda whereClauseExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddDataView("Status", "Active", p => p.IsActive); +```` diff --git a/16/umbraco-ui-builder/filtering/filterable-properties.md b/16/umbraco-ui-builder/filtering/filterable-properties.md new file mode 100644 index 00000000000..848e47a26b9 --- /dev/null +++ b/16/umbraco-ui-builder/filtering/filterable-properties.md @@ -0,0 +1,126 @@ +--- +description: Learn how to configure filterable properties in Umbraco UI Builder. +--- + +# Filterable Properties + +Umbraco UI Builder dynamically constructs a filter dialog by choosing appropriate editor views based on basic property configurations. Properties of numeric or date types become range pickers, enums become select/checkbox lists, and other properties are text input filters. + +![Filterable Properties](../images/filterable_properties.png) + +## Defining Filterable Properties + +Defining filterable properties is controlled via the [Collections](../collections/overview.md) settings. + +### Using the `AddFilterableProperty()` Method + +Adds a given property to the filterable properties collection. + +#### Method Syntax + +```cs +AddFilterableProperty(Lambda filterablePropertyExpression, Lambda filterConfig = null) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.AddFilterableProperty(p => p.FirstName, filterConfig => filterConfig + // ... +); +```` + +## Changing the Label of a Filterable Property + +### Using the `SetLabel()` Method + +Sets the label for the filterable property. + +#### Method Syntax + +```cs +SetLabel(string label) : FilterablePropertyConfigBuilder +``` + +#### Example + +````csharp +filterConfig.SetLabel("First Name"); +```` + +## Adding a Description to a Filterable Property + +### Using the `SetDescription()` Method + +Sets a description for the filterable property. + +#### Method Syntax + +```cs +SetDescription(string description) : FilterablePropertyConfigBuilder +``` + +#### Example + +````csharp +filterConfig.SetDescription("The first name of the person"); +```` + +## Defining Basic Options for a Filterable Property + +### Using the `SetOptions()` Method + +Defines basic options for a filterable property. + +#### Method Syntax + +```cs +SetOptions(IDictionary options) : FilterablePropertyConfigBuilder +``` + +#### Example + +````csharp +filterConfig.SetOptions(new Dictionary { + { "Option1", "Option One" }, + { "Option2", "Option Two" } +}); +```` + +## Defining Options with Custom Compare Clauses for a Filterable Property + +### Using the `AddOption()` Method + +Defines options with custom comparison clauses for a filterable property. + +#### Method Syntax + +```cs +AddOption(object key, string label, Lambda compareExpression) : FilterablePropertyConfigBuilder +``` + +#### Example + +````csharp +filterConfig.AddOption("Option1", "Option One", (val) => val != "Option Two"); +```` + +## Configuring the Mode of a Filterable Property + +For filterable properties with options, you can configure whether the options should allow multiple or single selections. + +### Using the `SetMode()` Method + +Configures the mode of a filterable property (multiple or single choice). + +#### Method Syntax + +```cs +SetMode(FilterMode mode) : FilterablePropertyConfigBuilder +``` + +#### Example + +````csharp +filterConfig.SetMode(FilterMode.MultipleChoice); +```` diff --git a/16/umbraco-ui-builder/filtering/global-filters.md b/16/umbraco-ui-builder/filtering/global-filters.md new file mode 100644 index 00000000000..a3cec96d03c --- /dev/null +++ b/16/umbraco-ui-builder/filtering/global-filters.md @@ -0,0 +1,27 @@ +--- +description: Learn how to configure a global filter in Umbraco UI Builder. +--- + +# Global Filters + +Use global filters to work with a specific subset of data within a collection. These filters apply to all queries for a given collection. + +## Applying a Global Filter + +Configure global filters in the [Collections](../collections/overview.md) settings. + +### Using the `SetFilter()` Method + +Defines a filter using a **where clause** expression. The expression must return a `boolean` value. + +#### Method Syntax + +```cs +SetFilter(Lambda whereClauseExpression) : CollectionConfigBuilder +``` + +#### Example + +````csharp +collectionConfig.SetFilter(p => p.Current); +```` diff --git a/16/umbraco-ui-builder/filtering/overview.md b/16/umbraco-ui-builder/filtering/overview.md new file mode 100644 index 00000000000..d43244b99c1 --- /dev/null +++ b/16/umbraco-ui-builder/filtering/overview.md @@ -0,0 +1,21 @@ +--- +description: Learn how to configure filtering in Umbraco UI Builder. +--- + +# Filtering + +In addition to [Searching](../searching/overview.md), you may need to create specific views of a collection's data. Umbraco UI Builder provides multiple filtering mechanisms to help with this. + +![Filterable Properties](../images/filterable_properties.png) + +Choose a filtering method from the list below to find out more. + +{% content-ref url="global-filters.md" %} +[global-filters.md](global-filters.md) +{% endcontent-ref %} +{% content-ref url="data-views.md" %} +[data-views.md](data-views.md) +{% endcontent-ref %} +{% content-ref url="filterable-properties.md" %} +[filterable-properties.md](filterable-properties.md) +{% endcontent-ref %} diff --git a/16/umbraco-ui-builder/getting-started/configuration.md b/16/umbraco-ui-builder/getting-started/configuration.md new file mode 100644 index 00000000000..594495bdd6b --- /dev/null +++ b/16/umbraco-ui-builder/getting-started/configuration.md @@ -0,0 +1,60 @@ +--- +description: Learn how to configure Umbraco UI Builder in your project using two different approaches. +--- + +# Configuration + +You can configure Umbraco UI Builder either via a Composer or in the `Program.cs`. + +## Option 1: Configuring via a Composer + +A Composer is a common approach for registering and configuring services in Umbraco during application startup. + +To configure Umbraco UI Builder via a Composer: + +1. Create a file called `UIBuilderComposer.cs` in your project. +2. Implement the `IComposer` interface and add the configuration inside the `Compose` method: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.UIBuilder.Extensions; + +public class UIBuilderComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.AddUIBuilder(cfg => + { + // Apply your configuration here + }); + } +} +``` + +## Option 2: Configuring via `Program.cs` + +You can also configure Umbraco UI Builder directly in `Program.cs` using the `AddUIBuilder` extension method. + +To configure Umbraco UI Builder: + +1. Open the `Program.cs` file in your project. +2. Locate the `CreateUmbracoBuilder()` method. +3. Add `AddUIBuilder` before `AddComposers()`. + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddUIBuilder(cfg => { + // Apply your configuration here + }) + .AddDeliveryApi() + .AddComposers() + .Build(); +``` + +## Example Configuration + +For a complete sample configuration, see the [Creating your First Integration](../guides/creating-your-first-integration.md) article. + +The `AddUIBuilder` method accepts a delegate function, allowing you to configure your solution using fluent APIs. diff --git a/16/umbraco-ui-builder/getting-started/images/dashboard.png b/16/umbraco-ui-builder/getting-started/images/dashboard.png new file mode 100644 index 00000000000..5116e1a4b10 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/dashboard.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/editor.png b/16/umbraco-ui-builder/getting-started/images/editor.png new file mode 100644 index 00000000000..c8ba78fcb47 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/editor.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/installing-vs.png b/16/umbraco-ui-builder/getting-started/images/installing-vs.png new file mode 100644 index 00000000000..85d42a25b7c Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/installing-vs.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/section.png b/16/umbraco-ui-builder/getting-started/images/section.png new file mode 100644 index 00000000000..cb4ff19e786 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/section.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/tabs.png b/16/umbraco-ui-builder/getting-started/images/tabs.png new file mode 100644 index 00000000000..5f363844091 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/tabs.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/tree.png b/16/umbraco-ui-builder/getting-started/images/tree.png new file mode 100644 index 00000000000..ee5bdab7c4d Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/tree.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/ui_01.png b/16/umbraco-ui-builder/getting-started/images/ui_01.png new file mode 100644 index 00000000000..ac15c165bd9 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/ui_01.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/ui_02.png b/16/umbraco-ui-builder/getting-started/images/ui_02.png new file mode 100644 index 00000000000..572dfd49415 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/ui_02.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/ui_03.png b/16/umbraco-ui-builder/getting-started/images/ui_03.png new file mode 100644 index 00000000000..d25a28f89c7 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/ui_03.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/ui_04.png b/16/umbraco-ui-builder/getting-started/images/ui_04.png new file mode 100644 index 00000000000..d4d7fd6d9b1 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/ui_04.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/ui_05.png b/16/umbraco-ui-builder/getting-started/images/ui_05.png new file mode 100644 index 00000000000..e1b6bb2f91d Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/ui_05.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/ui_06.png b/16/umbraco-ui-builder/getting-started/images/ui_06.png new file mode 100644 index 00000000000..7d365bd1846 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/ui_06.png differ diff --git a/16/umbraco-ui-builder/getting-started/images/workspace-views.png b/16/umbraco-ui-builder/getting-started/images/workspace-views.png new file mode 100644 index 00000000000..ed46d1b9cb5 Binary files /dev/null and b/16/umbraco-ui-builder/getting-started/images/workspace-views.png differ diff --git a/16/umbraco-ui-builder/getting-started/installation.md b/16/umbraco-ui-builder/getting-started/installation.md new file mode 100644 index 00000000000..ddfe4fdd43d --- /dev/null +++ b/16/umbraco-ui-builder/getting-started/installation.md @@ -0,0 +1,46 @@ +--- +description: Follow the steps to install Umbraco UI Builder into your Umbraco CMS website. +--- + +# Installation + +In this article, you will learn how to install Umbraco UI Builder into your Umbraco CMS implementation. + +## Install via Command Line + +Run the following command in your web project: + +```sh +dotnet add package Umbraco.UIBuilder +``` + +For a class library without UI elements, install: + +```sh +dotnet add package Umbraco.UIBuilder.Startup +``` + +## Install via Visual Studio + +To install via Visual Studio, follow these steps: + +1. Open Visual Studio and load your project. +2. Go to **Tools** -> **NuGet Package Manager** -> **Manage NuGet Packages for Solution...** +3. Select the **Browse** tab and search for **Umbraco.UIBuilder**. + +![Installing Umbraco UI Builder via Visual Studio](images/installing-vs.png) + +4. Select a version from the **Version** drop-down based on the Umbraco CMS version you are using. +5. Click **Install**. +6. *[Optional]* Search for and install **Umbraco.UIBuilder.Startup** if installing without UI elements. +7. Ensure that the package reference is added to the **.csproj** file once the installation is complete: + +```cs + + + +``` + +## Installing a License + +For details on how to install a license, see the [Licensing](licensing-model.md#installing-your-license) article. diff --git a/16/umbraco-ui-builder/getting-started/licensing-model.md b/16/umbraco-ui-builder/getting-started/licensing-model.md new file mode 100644 index 00000000000..0a0bedb1358 --- /dev/null +++ b/16/umbraco-ui-builder/getting-started/licensing-model.md @@ -0,0 +1,141 @@ +--- +description: Learn about licensing, including coverage, installation, and validation options. +--- + +# Licensing + +Umbraco UI Builder is a commercial product. You can use Umbraco UI Builder locally without a license. When running Umbraco UI Builder on a public domain the usage is limited to a single editable collection. To remove these restrictions, a **valid license** is required. + +## How Licensing Works + +Licenses are sold per backoffice domain and applies to all subdomains. If you have alternative staging/QA environment domains, additional domains can be added to the license on request. + +{% hint style="info" %} +The licenses are not tied to a specific product version. They work across all versions of the related product. +{% endhint %} + +### Example License Coverage + +A license for `mysite.com` and requested dev domains (`devdomain.com` and `devdomain2.com`) will cover: + +* `localhost` +* `*.local` +* `*.mysite.com` +* `www.mysite.com` +* `devdomain.com` +* `www.devdomain.com` +* `devdomain2.com` +* `www.devdomain2.com` + +{% hint style="info" %} +Only one license per Umbraco installation is allowed. +{% endhint %} + +## What a License Covers? + +There are a few differences as to what the licenses cover: + +* A single license covers the installation of Umbraco UI Builder in one production backoffice domain, as well as in any requested development domains. +* The production domain includes **all subdomains** (e.g. `*.mysite.com`). +* The development domains work with or without the `www` subdomain. +* The license allows for an unlimited number of editable collections. +* The license also includes `localhost` and `*.local` as a valid domain. + +{% hint style="info" %} +If you have multiple backoffice domains pointing at the same installation, you can purchase and [add **additional domains**](licensing-model.md#add-additional-domains) to your license. + +This is an add-on domain for existing licenses. Refunds will not be given for this product. +{% endhint %} + +## Configuring Your License + +You can look at the pricing, features, and purchase a license on the [Umbraco UI Builder](https://umbraco.com/products/add-ons/ui-builder/) page. On this page, you can fill out the form with your project details and requirements. + +A member of the Sales team will manage this process. In the process, you will need to provide all domains you wish to have covered by the license such as primary and staging/QA domains. You should then receive a license code to be installed in your solution. + +### Adding Additional Domains + +If you require to add additional domains to the license, [reach out to the sales team](https://umbraco.com/products/add-ons/ui-builder/). They will manage your request and take care of the process. + +## Installing your license + +Once you have received your license code it needs to be installed on your site. + +1. Open the root directory of your project files. +2. Locate and open the `appSettings.json` file. +3. Add your Umbraco UI builder license key under `Umbraco:Licenses:Products:Umbraco.UIBuilder`: + +```json +"Umbraco": { + "Licenses": { + "Products": { + "Umbraco.UIBuilder": "YOUR_LICENSE_KEY" + } + } +} +``` + +{% hint style="info" %} +You might run into issues when using a period in the product name when using environment variables. Use an underscore in the product name instead, to avoid problems. + +```json +"Umbraco_UIBuilder": "YOUR_LICENSE_KEY" +``` + +{% endhint %} + +### Verifying the License + +To verify that your license is successfully installed: + +1. Log into Umbraco Backoffice. +2. Navigate to the **Settings** > **License** dashboard. +3. Verify the license status displayed on the dashboard. + +### Validating a License Without an Internet connection + +Some Umbraco installations will have a highly locked down production environment, with firewall rules that prevent outgoing HTTP requests. This will interfere with the normal process of license validation. + +On start-up, and periodically whilst Umbraco is running, the license component used by Umbraco UIBuilder will make an HTTP POST request to `https://license-validation.umbraco.com/api/ValidateLicense`. + +If it's possible to do so, the firewall rules should be adjusted to allow this request. + +If such a change is not feasible, there is another approach you can use. + +You will need to have a server, or serverless function, that is running and can make a request to the online license validation service. That needs to run on a daily schedule, making a request and relaying it onto the restricted Umbraco environment. + +To set this up, firstly ensure you have a reference to `Umbraco.Licenses` version 13.1 or higher. If the version of UIBuilder you are using depends on an earlier version, you can add a direct package reference for `Umbraco.Licenses`. + +Then configure a random string as an authorization key in configuration. This is used as protection to ensure only valid requests are handled. You can also disable the normal regular license checks - as there is no point in these running if they will be blocked: + +```json + "Umbraco": { + "Licenses": { + "Umbraco.UIBuilder": "" + }, + "LicensesOptions": { + "EnableScheduledValidation": false, + "ValidatedLicenseRelayAuthKey": "" + } +``` + +Your Internet enabled server should make a request of the following form to the online license validation service: + +``` +POST https://license-validation.umbraco.com/api/ValidateLicense +{ + "ProductId": "Umbraco.UIBuilder", + "LicenseKey": "", + "Domain": "" +} +``` + +The response should be relayed exactly via an HTTP request to your restricted Umbraco environment: + +``` +POST http:///umbraco/licenses/validatedLicense/relay?productId=&licenseKey= +``` + +A header with a key of `X-AUTH-KEY` and value of the authorization key you have configured should be provided. + +This will trigger the same processes that occur when the normal scheduled validation completes ensuring your product is considered licensed. diff --git a/16/umbraco-ui-builder/getting-started/requirements.md b/16/umbraco-ui-builder/getting-started/requirements.md new file mode 100644 index 00000000000..cc86d217515 --- /dev/null +++ b/16/umbraco-ui-builder/getting-started/requirements.md @@ -0,0 +1,28 @@ +--- +description: >- + Get started with Umbraco UI Builder by understanding its system requirements, + versioning, and installation prerequisites. +--- + +# Requirements + +In this article, you will find the requirements to get started with Umbraco UI Builder. Umbraco UI Builder allows you to create and manage custom UI elements for your Umbraco backoffice. + +## Prerequisites + +* Umbraco 15+ website configured and ready to install Umbraco UI Builder. + +{% hint style="info" %} +For instructions on installing Umbraco, see the [Umbraco CMS Documentation](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/install). +{% endhint %} + +## System Requirements + +To use Umbraco UI Builder, your setup must meet these minimum requirements: + +* **Umbraco CMS version 15+** +* **SQL Server Database** (SQLite is acceptable for testing but not recommended for live deployments) + +## Versioning + +Umbraco UI Builder is an add-on product for Umbraco CMS, and follows the [versioning strategy laid out for Umbraco CMS](https://umbraco.com/products/knowledge-center/versioning-and-release-cadence/). diff --git a/16/umbraco-ui-builder/getting-started/user-interface.md b/16/umbraco-ui-builder/getting-started/user-interface.md new file mode 100644 index 00000000000..c056435abaf --- /dev/null +++ b/16/umbraco-ui-builder/getting-started/user-interface.md @@ -0,0 +1,61 @@ +--- +description: Key User Interface Concepts used by Umbraco UI Builder. +--- + +# User Interface + +Before diving into Umbraco UI Builder, it’s important to understand some of the fundamental concepts of the Umbraco UI. This knowledge will help you navigate and leverage the UI Builder more effectively, as it uses the same UI components to construct interfaces. + +## Section + +A section in Umbraco is a distinct area within the backoffice where related content and functionality are grouped. For example, the Content section is where content management happens, while the Media section handles media files. + +![Section View](images/section.png) + +## Tree + +The tree represents the hierarchical structure of items within a section. It organizes content, settings, and data, for quick navigation and locating items. For example, the content tree shows the pages of a website in a nested format. + +![Tree View](images/tree.png) + +## Dashboard + +Each section in the Umbraco backoffice typically starts with a dashboard. This is an introductory screen for the section. It often includes useful links or shortcuts, providing an overview or quick access to the most commonly used features. + +![Dashboard View](images/dashboard.png) + +## Collection + +The collection displays a list of items in a tree or grid view. It provides an overview of content or data in a table format, with sortable columns and the option to filter or search through the items. This view is used when you need to work with multiple items at once. + +![Collection View](images/ui_02.png) + +## Editor + +The editor is where the main content editing occurs. It is structured using tabs, fieldsets, and fields. Tabs organize different sections of content, and fieldsets group related fields together. Each field represents a specific piece of data, such as a text box or an image upload. + +![Editor](images/ui_03.png) + +## Workspace Views + +Workspace Views are additional functionality that can be added to an editor. They provide extra features based on the content of the item being edited. For instance, a media Workspace View might allow you to resize or crop an image directly from the editor. + +![Workspace Views](images/workspace-views.png) + +## Tabs + +Tabs are used to organize content within the editor, allowing users to switch between different sections of a content item. For example, one tab might contain the general settings, while another contains media or advanced options. + +![Tabs](images/tabs.png) + +## Menu Item + +A menu item represents an action within the context of a tree node or a list item. It is a clickable item that triggers specific tasks, such as deleting or editing an item. + +![Menu Item](images/ui_04.png) + +## Bulk Action + +Bulk actions allow you to perform an operation on multiple items in the list view at once. For example, you might use a bulk action to delete multiple content items or update their status in a single step. + +![Bulk Action](images/ui_05.png) diff --git a/16/umbraco-ui-builder/guides/creating-your-first-integration.md b/16/umbraco-ui-builder/guides/creating-your-first-integration.md new file mode 100644 index 00000000000..5f191a74cdd --- /dev/null +++ b/16/umbraco-ui-builder/guides/creating-your-first-integration.md @@ -0,0 +1,150 @@ +--- +description: Creating your first integration with Umbraco UI Builder. +--- + +# Creating Your First Umbraco UI Builder Integration + +This guide walks you through a basic implementation of Umbraco UI Builder to manage a custom database table. + +{% hint style="info" %} +By default, Umbraco UI Builder uses a database for data storage. However, you can configure this using a custom [Repository](../advanced/repositories.md) class instead. +{% endhint %} + +## Setting Up the Database + +Umbraco UI Builder uses PetaPoco as its default persistence layer. + +In this section, you will create a `Person` table to store data. + +To create a `Person` table, run the following script in SQL Server Management Studio (SSMS). + +```sql +CREATE TABLE [Person] ( + [Id] int IDENTITY (1,1) NOT NULL, + [Name] nvarchar(255) NOT NULL, + [JobTitle] nvarchar(255) NOT NULL, + [Email] nvarchar(255) NOT NULL, + [Telephone] nvarchar(255) NOT NULL, + [Age] int NOT NULL, + [Avatar] nvarchar(255) NOT NULL +); +``` + +This script creates a table for storing people’s details. You may want to populate it with some dummy data for testing. + +## Setting Up the Model + +With the database table created, define the `Person` model in your project. + +To create a Model: + +1. Create a new folder called **Models** in your project. +2. Add a new class file called `Person.cs`. +3. Add the following code: + +```csharp +using NPoco; +using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; + +[TableName("Person")] +[PrimaryKey("Id")] +public class Person +{ + [PrimaryKeyColumn] + public int Id { get; set; } + public string? Name { get; set; } + public string? JobTitle { get; set; } + public string? Email { get; set; } + public string? Telephone { get; set; } + public int Age { get; set; } + public string? Avatar { get; set; } +} +``` + +## Configure Umbraco UI Builder + +With the database and model set up, it is time to configure Umbraco UI Builder to work with the `Person` model. This will allow you to manage `Person` entities from the Umbraco backoffice. + +{% hint style="info" %} +You can configure Umbraco UI Builder either through a Composer or by using the `AddUIBuilder` extension method in `Program.cs`. +{% endhint %} + +The following steps cover the `Program.cs` approach. For more details, including configuring via a Composer, see the the [Configuration](../getting-started/configuration.md) article. + +### Configuring via `Program.cs` + +1. Open the `Program.cs` file in your project. +2. Locate the `CreateUmbracoBuilder()` method. +3. Add `AddUIBuilder` before `AddComposers()`. + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .AddUIBuilder(cfg => { + // Apply your configuration here + }) + .Build(); +``` + +### Example Configuration + +Here’s an example configuration defining a section, a list view, and an editor for managing `Person` entities: + +```csharp +... +.AddUIBuilder(cfg => { + + cfg.AddSectionAfter("media", "Repositories", sectionConfig => sectionConfig + .Tree(treeConfig => treeConfig + .AddCollection(x => x.Id, "Person", "People", "A person entity", "icon-umb-users", "icon-umb-users", collectionConfig => collectionConfig + .SetNameProperty(p => p.Name) + .ListView(listViewConfig => listViewConfig + .AddField(p => p.JobTitle).SetHeading("Job Title") + .AddField(p => p.Email) + ) + .Editor(editorConfig => editorConfig + .AddTab("General", tabConfig => tabConfig + .AddFieldset("General", fieldsetConfig => fieldsetConfig + .AddField(p => p.JobTitle).MakeRequired() + .AddField(p => p.Age) + .AddField(p => p.Email).SetValidationRegex("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+") + .AddField(p => p.Telephone).SetDescription("inc area code") + ) + .AddFieldset("Media", fieldsetConfig => fieldsetConfig + .AddField(p => p.Avatar).SetDataType("Upload File") + ) + ) + ) + ) + ) + ); + +}) +... +``` + +## Accessing the Umbraco Backoffice + +After defining the configuration, compile and run your project. To access the newly defined section, you need to give permission to the backoffice user account: + +1. Login to the Umbraco backoffice. +2. Go to the **Users** section. +3. Navigate to the user group you wish to assign the newly defined section. + +![User group permissions](images/permissions.png) + +4. Submit the changes. +5. Refresh the browser to view the new section. + +![Newly defined section](images/new-section.png) + +If you click on a person's name, you will see the following screen: + +![People editor](images/people-editor.png) + +## Summary + +This setup allows you to extend and customize your Umbraco site by managing data and entities directly in the backoffice. The simplicity of the implementation allows to create dynamic, user-friendly interfaces for your own data models. diff --git a/16/umbraco-ui-builder/guides/images/new-section.png b/16/umbraco-ui-builder/guides/images/new-section.png new file mode 100644 index 00000000000..c4fe23c5f5b Binary files /dev/null and b/16/umbraco-ui-builder/guides/images/new-section.png differ diff --git a/16/umbraco-ui-builder/guides/images/people-editor.png b/16/umbraco-ui-builder/guides/images/people-editor.png new file mode 100644 index 00000000000..167bd6b872a Binary files /dev/null and b/16/umbraco-ui-builder/guides/images/people-editor.png differ diff --git a/16/umbraco-ui-builder/guides/images/permissions.png b/16/umbraco-ui-builder/guides/images/permissions.png new file mode 100644 index 00000000000..ebb680c3fe3 Binary files /dev/null and b/16/umbraco-ui-builder/guides/images/permissions.png differ diff --git a/16/umbraco-ui-builder/images/bulk_actions.png b/16/umbraco-ui-builder/images/bulk_actions.png new file mode 100644 index 00000000000..9447f4d3179 Binary files /dev/null and b/16/umbraco-ui-builder/images/bulk_actions.png differ diff --git a/16/umbraco-ui-builder/images/bulk_actions_menu.png b/16/umbraco-ui-builder/images/bulk_actions_menu.png new file mode 100644 index 00000000000..0de260da545 Binary files /dev/null and b/16/umbraco-ui-builder/images/bulk_actions_menu.png differ diff --git a/16/umbraco-ui-builder/images/cards.png b/16/umbraco-ui-builder/images/cards.png new file mode 100644 index 00000000000..31e2c20c3af Binary files /dev/null and b/16/umbraco-ui-builder/images/cards.png differ diff --git a/16/umbraco-ui-builder/images/child_collection_groups.png b/16/umbraco-ui-builder/images/child_collection_groups.png new file mode 100644 index 00000000000..4cb9e5ca297 Binary files /dev/null and b/16/umbraco-ui-builder/images/child_collection_groups.png differ diff --git a/16/umbraco-ui-builder/images/child_collections.png b/16/umbraco-ui-builder/images/child_collections.png new file mode 100644 index 00000000000..b0f844ceeb8 Binary files /dev/null and b/16/umbraco-ui-builder/images/child_collections.png differ diff --git a/16/umbraco-ui-builder/images/comments_listview.png b/16/umbraco-ui-builder/images/comments_listview.png new file mode 100644 index 00000000000..fee43943a15 Binary files /dev/null and b/16/umbraco-ui-builder/images/comments_listview.png differ diff --git a/16/umbraco-ui-builder/images/container_actions_menu.png b/16/umbraco-ui-builder/images/container_actions_menu.png new file mode 100644 index 00000000000..1e6871db48d Binary files /dev/null and b/16/umbraco-ui-builder/images/container_actions_menu.png differ diff --git a/16/umbraco-ui-builder/images/content_apps.png b/16/umbraco-ui-builder/images/content_apps.png new file mode 100644 index 00000000000..23604f20f04 Binary files /dev/null and b/16/umbraco-ui-builder/images/content_apps.png differ diff --git a/16/umbraco-ui-builder/images/context_app.png b/16/umbraco-ui-builder/images/context_app.png new file mode 100644 index 00000000000..b9f509ddfd8 Binary files /dev/null and b/16/umbraco-ui-builder/images/context_app.png differ diff --git a/16/umbraco-ui-builder/images/dashboard.png b/16/umbraco-ui-builder/images/dashboard.png new file mode 100644 index 00000000000..6e7f09e3d8b Binary files /dev/null and b/16/umbraco-ui-builder/images/dashboard.png differ diff --git a/16/umbraco-ui-builder/images/dashboards.png b/16/umbraco-ui-builder/images/dashboards.png new file mode 100644 index 00000000000..aec51a0777f Binary files /dev/null and b/16/umbraco-ui-builder/images/dashboards.png differ diff --git a/16/umbraco-ui-builder/images/data_views.png b/16/umbraco-ui-builder/images/data_views.png new file mode 100644 index 00000000000..c577f854dc5 Binary files /dev/null and b/16/umbraco-ui-builder/images/data_views.png differ diff --git a/16/umbraco-ui-builder/images/entity_actions_menu.png b/16/umbraco-ui-builder/images/entity_actions_menu.png new file mode 100644 index 00000000000..2757026dd17 Binary files /dev/null and b/16/umbraco-ui-builder/images/entity_actions_menu.png differ diff --git a/16/umbraco-ui-builder/images/entity_picker_config.png b/16/umbraco-ui-builder/images/entity_picker_config.png new file mode 100644 index 00000000000..fee19974ea0 Binary files /dev/null and b/16/umbraco-ui-builder/images/entity_picker_config.png differ diff --git a/16/umbraco-ui-builder/images/entity_picker_picked.png b/16/umbraco-ui-builder/images/entity_picker_picked.png new file mode 100644 index 00000000000..a09f97ee97b Binary files /dev/null and b/16/umbraco-ui-builder/images/entity_picker_picked.png differ diff --git a/16/umbraco-ui-builder/images/entity_picker_search.png b/16/umbraco-ui-builder/images/entity_picker_search.png new file mode 100644 index 00000000000..5278a64ffcf Binary files /dev/null and b/16/umbraco-ui-builder/images/entity_picker_search.png differ diff --git a/16/umbraco-ui-builder/images/entity_picker_setup.png b/16/umbraco-ui-builder/images/entity_picker_setup.png new file mode 100644 index 00000000000..2f202127cea Binary files /dev/null and b/16/umbraco-ui-builder/images/entity_picker_setup.png differ diff --git a/16/umbraco-ui-builder/images/filterable_properties.png b/16/umbraco-ui-builder/images/filterable_properties.png new file mode 100644 index 00000000000..161eac28ede Binary files /dev/null and b/16/umbraco-ui-builder/images/filterable_properties.png differ diff --git a/16/umbraco-ui-builder/images/listview.png b/16/umbraco-ui-builder/images/listview.png new file mode 100644 index 00000000000..b9a90f0f82e Binary files /dev/null and b/16/umbraco-ui-builder/images/listview.png differ diff --git a/16/umbraco-ui-builder/images/menu_items.png b/16/umbraco-ui-builder/images/menu_items.png new file mode 100644 index 00000000000..3662552ba18 Binary files /dev/null and b/16/umbraco-ui-builder/images/menu_items.png differ diff --git a/16/umbraco-ui-builder/images/related_collections_child.png b/16/umbraco-ui-builder/images/related_collections_child.png new file mode 100644 index 00000000000..16f9bf58cfb Binary files /dev/null and b/16/umbraco-ui-builder/images/related_collections_child.png differ diff --git a/16/umbraco-ui-builder/images/related_collections_diagram.png b/16/umbraco-ui-builder/images/related_collections_diagram.png new file mode 100644 index 00000000000..007436a85bf Binary files /dev/null and b/16/umbraco-ui-builder/images/related_collections_diagram.png differ diff --git a/16/umbraco-ui-builder/images/related_collections_parent.png b/16/umbraco-ui-builder/images/related_collections_parent.png new file mode 100644 index 00000000000..7c763aebab5 Binary files /dev/null and b/16/umbraco-ui-builder/images/related_collections_parent.png differ diff --git a/16/umbraco-ui-builder/images/row_actions_menu.png b/16/umbraco-ui-builder/images/row_actions_menu.png new file mode 100644 index 00000000000..a0fcf0ef886 Binary files /dev/null and b/16/umbraco-ui-builder/images/row_actions_menu.png differ diff --git a/16/umbraco-ui-builder/images/save_actions_menu.png b/16/umbraco-ui-builder/images/save_actions_menu.png new file mode 100644 index 00000000000..cf818ba674a Binary files /dev/null and b/16/umbraco-ui-builder/images/save_actions_menu.png differ diff --git a/16/umbraco-ui-builder/images/search.png b/16/umbraco-ui-builder/images/search.png new file mode 100644 index 00000000000..3892741bbfd Binary files /dev/null and b/16/umbraco-ui-builder/images/search.png differ diff --git a/16/umbraco-ui-builder/images/sections.png b/16/umbraco-ui-builder/images/sections.png new file mode 100644 index 00000000000..bfcea850b44 Binary files /dev/null and b/16/umbraco-ui-builder/images/sections.png differ diff --git a/16/umbraco-ui-builder/images/tree.png b/16/umbraco-ui-builder/images/tree.png new file mode 100644 index 00000000000..c9956e07e08 Binary files /dev/null and b/16/umbraco-ui-builder/images/tree.png differ diff --git a/16/umbraco-ui-builder/images/virtual-sub-tree.png b/16/umbraco-ui-builder/images/virtual-sub-tree.png new file mode 100644 index 00000000000..a2d4f5763b1 Binary files /dev/null and b/16/umbraco-ui-builder/images/virtual-sub-tree.png differ diff --git a/16/umbraco-ui-builder/known-issues.md b/16/umbraco-ui-builder/known-issues.md new file mode 100644 index 00000000000..a1519a55079 --- /dev/null +++ b/16/umbraco-ui-builder/known-issues.md @@ -0,0 +1,19 @@ +--- +description: A list of known limitations and issues in Umbraco UI Builder +--- + +# Known Issues + +Umbraco UI Builder strives to closely mimic the content pipeline while adhering to public and supported APIs. This ensures full compatibility with the Data Type suite for property editing. However, some features in the Umbraco Core rely on internal methods, making full support for certain functionalities challenging. Below is a list of known issues. + +## Property Editors + +### Tags + +While Umbraco UI Builder supports persisting tag values, it currently does not write these tags to the `cmsTags` database table. This functionality is managed by the internal `tagsRepository`, which is not publicly accessible, preventing direct saving in the same manner as Umbraco Core. + +### Block Editors + +Block Editors (Block List/Block Grid) are not currently supported due to casting errors between the JSON string representation and collection property. + +An implementation to address this is investigated and will be scheduled for a future major release. diff --git a/16/umbraco-ui-builder/miscellaneous/conventions.md b/16/umbraco-ui-builder/miscellaneous/conventions.md new file mode 100644 index 00000000000..c1302190fae --- /dev/null +++ b/16/umbraco-ui-builder/miscellaneous/conventions.md @@ -0,0 +1,32 @@ +--- +description: Guidelines for fluent configuration and naming conventions in Umbraco UI Builder. +--- + +# Conventions + +## Fluent Conventions + +Umbraco UI Builder follows a fluent configuration style, allowing method chaining for concise and readable code. Alternatively, a lambda expression can be used for a more structured approach. + +### Chaining Example + +```csharp +config.AddSection("Repositories") + .Tree() + .AddCollection(p => p.Id, "Person", "People"); +``` + +### Lambda Expression Example Example + +```csharp +config.AddSection("Repositories", sectionConfig => { + sectionConfig.Tree(treeConfig => { + treeConfig.AddCollection(p => p.Id, "Person", "People"); + }); +}); +``` + +## Naming Conventions + +* Methods prefixed with **Add** allow multiple configurations. +* Methods prefixed with **Set** permit only one instance within the current configuration context. diff --git a/16/umbraco-ui-builder/miscellaneous/umbraco-aliases.md b/16/umbraco-ui-builder/miscellaneous/umbraco-aliases.md new file mode 100644 index 00000000000..5331940d17b --- /dev/null +++ b/16/umbraco-ui-builder/miscellaneous/umbraco-aliases.md @@ -0,0 +1,92 @@ +--- +description: Common Umbraco aliases used in Umbraco UI Builder for Sections, Dashboards, Workspace Views, and Trees. +--- + +# Umbraco Aliases + +Umbraco UI Builder requires aliases for different elements, such as sections, context apps, and dashboards. While aliases for elements defined in the UI Builder config are straightforward, finding aliases for existing Umbraco instances can be challenging. Below is a list of known aliases for reference. + +## Dashboard Aliases + +### Content + +| Name | Alias | +| -- | -- | +| Getting Started | `contentIntro` | +| Redirect URL Management | `contentRedirectManager` | + +### Media + +| Name | Alias | +| -- | -- | +| Content | `mediaFolderBrowser` | + +### Settings + +| Name | Alias | +| -- | -- | +| Welcome | `settingsWelcome` | +| Examine Management | `settingsExamine` | +| Published Status | `settingsPublishedStatus` | +| Models Builder | `settingsModelsBuilder` | +| Health Check | `settingsHealthCheck` | + +### Members + +| Name | Alias | +| -- | -- | +| Getting Started | `memberIntro` | + +## Workspace Views Aliases + +### Content + +| Name | Alias | +| -- | -- | +| Content | `umbContent` | +| Info | `umbInfo` | + +### Media + +| Name | Alias | +| -- | -- | +| Content | `umbContent` | +| Info | `umbInfo` | + +### Members + +| Name | Alias | +| -- | -- | +| Content | `umbContent` | +| Info | `umbInfo` | + +### ContentTypes + +| Name | Alias | +| -- | -- | +| Design | `design` | +| List View | `listView` | +| Permissions | `permissions` | +| Templates | `templates` | + +## Section Aliases + +| Name | Alias | +| -- | -- | +| Content | `content` | +| Media | `media` | +| Settings | `settings` | +| Packages | `packages` | +| Users | `users` | +| Members | `member` | +| Forms | `forms` | +| Translation | `translation` | + +## Tree Aliases + +| Name | Alias | +| -- | -- | +| Content | `content` | +| Media | `media` | +| Members | `member` | +| Member Groups | `memberGroups` | diff --git a/16/umbraco-ui-builder/property-editors/entity-picker.md b/16/umbraco-ui-builder/property-editors/entity-picker.md new file mode 100644 index 00000000000..694803ecc90 --- /dev/null +++ b/16/umbraco-ui-builder/property-editors/entity-picker.md @@ -0,0 +1,58 @@ +--- +description: Configure and use the Entity Picker property editor in Umbraco UI Builder to select entities from a collection. +--- + +# Entity Picker + +The Entity Picker property editor allows selecting one or more entities from an Umbraco UI Builder collection. + +## Configuring an Entity Picker + +To configure an entity picker, follow these steps: + +1. Go to the **Settings** section in the Umbraco backoffice. +2. Create a **New Data Type**. +3. Select **UI Builder Entity Picker** from the **Property Editor** field. + +![Data Type config](../images/entity_picker_config.png) + +4. Enter a **Name** for the picker and click **Save**. +5. Select the **Section** the collection is located in. +6. Select the **Collection** to pick the entities from. +7. *[Optional]* Select a list view **Data View**, if configured. +8. Enter a **Minimum number of items** and **Maximum number of items** that can be selected. +9. Click **Save**. + +After defining the entity picker Data Type, add it to the desired Document Type. + +![Document Type config](../images/entity_picker_setup.png) + +## Using an Entity Picker + +The entity picker functions similarly to the content picker. + +To pick an entity, follow these steps: + +1. Go to the Document Type where the entity picker Data Type is added. +2. Click **Add** to open the picker dialog, displaying a paginated list of entities. +3. *[Optional]* If searchable fields are configured, use the search input field to filter results. + +![Entity picker dialog](../images/entity_picker_search.png) + +4. Click on the entity names. +5. Click **Submit**. + The picker displays a summary of selected entities, which can be reordered by dragging them. +6. Click **Save** or **Save and publish** to save the changes. + +![Entity picker values](../images/entity_picker_picked.png) + +## Retrieving the Value of an Entity Picker + +The entity picker property editor includes a built-in [value converter](https://docs.umbraco.com/umbraco-cms/customizing/property-editors/property-value-converters). Retrieving the property value from Umbraco returns the selected entities, converting them to the relevant type. + +````csharp +// Example +foreach(var p in Model.People){ + ... +} +```` diff --git a/16/umbraco-ui-builder/property-editors/overview.md b/16/umbraco-ui-builder/property-editors/overview.md new file mode 100644 index 00000000000..d1611bfec45 --- /dev/null +++ b/16/umbraco-ui-builder/property-editors/overview.md @@ -0,0 +1,13 @@ +--- +description: Available property editors in Umbraco UI Builder for managing data in Umbraco content nodes. +--- + +# Property Editors + +Umbraco UI Builder provides property editors for managing data inside Umbraco content nodes. + +The available property editors are: + +{% content-ref url="entity-picker.md" %} +[Entity Picker](entity-picker.md) +{% endcontent-ref %} diff --git a/16/umbraco-ui-builder/release-notes.md b/16/umbraco-ui-builder/release-notes.md new file mode 100644 index 00000000000..dc416a01410 --- /dev/null +++ b/16/umbraco-ui-builder/release-notes.md @@ -0,0 +1,72 @@ +--- +description: >- + Get an overview of the things changed and fixed in each version of Umbraco UI + Builder. +--- + +# Release Notes + +This section summarizes the changes and fixes introduced in each version of Umbraco UI Builder. Each release includes a link to the [UI Builder issue tracker](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues), where you can find a list of resolved issues. Individual issues are also linked for more details. + +If there are any breaking changes or other issues to be aware of when upgrading they are also noted here. + +{% hint style="info" %} +If you are upgrading to a new major version, check the breaking changes in the [Version Specific Upgrade Notes](upgrading/version-specific.md) article. +{% endhint %} + +## Release History + +Below are the release notes for Umbraco UI Builder 15, detailing all changes in this version. + +#### [**15.1.2**](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.1.2) **(April 4th 2025)** + +* Removed global registration of `UDI` converters [#144](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/144), [#136](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/136), and introduced new [Entity Identifier Converters](./collections/entity-identifier-converters.md). +* Fixed `Create` action button [#137](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/137). +* Added collection list view refresh feature following an entity action [#139](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/139). +* Fixed collection visibility [#134](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/134). +* Enabled rendering of sidebar properties. +* Fixed an issue that prevented the creation of multiple sections. + +#### [**15.1.1**](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.1.1) **(March 21st 2025)** + +* Extended `UdiConverter` with options to convert to `GUID` [#108](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/108) +* Update `Save` action visibility for readonly collections [#129](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/129) +* Fixed value editor configuration object impacting the use of custom property editors for collection properties [#122](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/122) +* Enable the display of markup from custom field views [#119](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/119) +* Fixed an issue causing sort properties not being sent to repository [#118](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/118) + +#### [**15.1.0**](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.1.0) **(March 4th 2025)** + +* Updated licensing engine. +* Fixed issue with import entity action for Umbraco Cloud websites [#92](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/92). +* Added feature to allow server-side complex validation using [repository events](advanced/events.md). +* Enable sorting a list view based on the `Name` column. +* Fixed issue with `SetHeading` collection property. +* Fixed issue with setting a list view page size programmatically using `SetPageSize`. + +#### [**15.0.3**](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.3) **(February 5th 2025)** + +* Fixed an issue with filter input values persistence for filterable properties. +* Filterable properties UI updates + +#### [**15.0.2**](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.2) **(January 22nd 2025)** + +* Added updates to the licensing engine. +* Fixed an error in the entity update action. + +#### [**15.0.1**](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.1) **(December 16th 2024)** + +* Added previously validated license resolver, to validate a license if a validation process was already executed successfully in the past 7 days. +* Fixed an issue caused by `where` clauses for filter expression and deleted property. +* Allow entity properties to be searched based on pattern: `StartsWith` | `Contains` [#116](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/116). +* Switch entity create/edit header to label view for read-only collections [#111](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues/111). + +#### [**15.0.0**](https://github.com/umbraco/Umbraco.UIBuilder.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.0) **(November 14th 2024)** + +* Product migrated to support the new Web Component-based Umbraco. + +You can read more about the new Backoffice in the [Umbraco CMS documentation](https://docs.umbraco.com/umbraco-cms/extending/customize-the-editing-experience). + +## Legacy Release Notes + +You can find the release notes for **Konstrukt** in the [Change log file on GitHub](changelog-archive/changelog.md). diff --git a/16/umbraco-ui-builder/searching/overview.md b/16/umbraco-ui-builder/searching/overview.md new file mode 100644 index 00000000000..fa2c3d0b4b0 --- /dev/null +++ b/16/umbraco-ui-builder/searching/overview.md @@ -0,0 +1,15 @@ +--- +description: Configure search functionality in Umbraco UI Builder. +--- + +# Searching + +Umbraco UI Builder includes a search API for filtering and locating specific entities within a collection. This enhances usability, especially in collections with large datasets. + +![Search](../images/search.png) + +Get started by reviewing how to define searchable properties. + +{% content-ref url="searchable-properties.md" %} +[searchable-properties.md](searchable-properties.md) +{% endcontent-ref %} diff --git a/16/umbraco-ui-builder/searching/searchable-properties.md b/16/umbraco-ui-builder/searching/searchable-properties.md new file mode 100644 index 00000000000..f1c0ba12d26 --- /dev/null +++ b/16/umbraco-ui-builder/searching/searchable-properties.md @@ -0,0 +1,44 @@ +--- +description: Configure searchable properties in Umbraco UI Builder. +--- + +# Searchable Properties + +Searchable properties allow you to define any `String` based properties in a model. It can be searched via Umbraco UI Builder's list view and entity picker search controls. + +Both direct `String` properties and `String` properties within nested objects can be made searchable, provided the parent object is not `null`. + +![Search](../images/search.png) + +## Defining Searchable Properties + +### Using `AddSearchableProperty()` Method + +Use `AddSearchableProperty` to specify which properties should be included in search functionality. + +#### Method Syntax + +```cs +AddSearchableProperty(Lambda searchablePropertyExpression) : CollectionConfigBuilder +``` + +#### Example + +````cs +collectionConfig.AddSearchableProperty(p => p.FirstName); +collectionConfig.AddSearchableProperty(p => p.Address.Street); +```` + +## Search Expression Pattern + +The search behavior differs based on the version: + +- Up to version 15.0.1: Search uses the `StartsWith` method, meaning results include entries that begin with the search term. +- Version 15.0.1 and later: Search can be configured to use `Contains`, allowing results that include the search term anywhere within the property value. + +### Example + +````csharp +collectionConfig.AddSearchableProperty(p => p.FirstName); // will search for keywords that start with. +collectionConfig.AddSearchableProperty(p => p.FirstName, SearchExpressionPattern.Contains); // will search for keywords that are contained. +```` diff --git a/16/umbraco-ui-builder/upgrading/migrating-from-konstrukt-to-umbraco-ui-builder.md b/16/umbraco-ui-builder/upgrading/migrating-from-konstrukt-to-umbraco-ui-builder.md new file mode 100644 index 00000000000..f4d78f4949d --- /dev/null +++ b/16/umbraco-ui-builder/upgrading/migrating-from-konstrukt-to-umbraco-ui-builder.md @@ -0,0 +1,118 @@ +--- +description: Step-by-step guide to migrating a Konstrukt solution to Umbraco UI Builder. +--- + +# Migrate from Konstrukt to Umbraco UI Builder + +This guide walks you through migrating a default Konstrukt solution to Umbraco UI Builder. + +## Key Changes + +Before starting, review these key changes that impact the migration process. + +### Project, Package, and Namespace changes + +| Konstrukt | Umbraco UI Builder | +| ------------------------------- | --------------------------------------- | +| Konstrukt.Core | Umbraco.UIBuilder.Core | +| Konstrukt.Infrastructure | Umbraco.UIBuilder.Infrastructure | +| Konstrukt.Web | Umbraco.UIBuilder.Web | +| Konstrukt.Web.UI | Umbraco.UIBuilder.Web.StaticAssets | +| Konstrukt.Startup | Umbraco.UIBuilder.Startup | +| Konstrukt | Umbraco.UIBuilder | + +### Code and UI Changes + +
+ +C# Class Changes + +* Namespace changes as mentioned above. +* Most `Konstrukt`-prefixed classes have had the prefix removed. + * Examples: `IKonstruktRepository` -> `IRepository` + * Exceptions: + * `KonstruktConfig` and `KonstruktConfigBuilder` now use a `UIBuilder` prefix. + * `AddKonstrukt` extension for `IUmbracoBuilder` is now `AddUIBuilder` + +
+ +
+ +JavaScript Changes + +* All `Konstrukt` controllers are now under the `Umbraco.UIBuilder` namespace. +* All `Konstrukt` prefixed directives, services, and resources now use `uibuilder`. + +
+ +
+ +UI Changes + +* All static UI assets are now served via a Razor Compiled Library (RCL) instead of being stored in the `App_Plugins` folder. +* The `App_Plugins/Konstrukt` folder is now `App_Plugins/UmbracoUIBuilder`. + +
+ +## Step 1: Replace Dependencies + +Replace all existing Konstrukt dependencies with Umbraco UI Builder dependencies. + +1. Remove existing Konstrukt packages: + +```bash +dotnet remove package Konstrukt +``` + +2. Delete the Konstrukt `App_Plugins` folder: + +```bash +rmdir App_Plugins\Konstrukt +``` + +3. Install `Umbraco.UIBuilder`: + +```bash +dotnet add package Umbraco.UIBuilder +``` + +4. Compile your project against .NET 7.0. + +## Step 2: Update Namespaces and Entity Names + +Update all Konstrukt references to their Umbraco UI Builder alternatives. Ensure you update any Views/Partials that also reference these. See the [Key Changes](./#key-changes) section for reference. + +## Step 3: Update Configuration + +If your configuration is in a single statement, replace `AddKonstrukt` with `AddUIBuilder`. + +For multi-step configurations using `Action` or `Card` classes, update the **config builders** and **base classes** to their UI Builder alternatives as described in [Key Changes](./#key-changes). + +```csharp +builder.CreateUmbracoBuilder() + .AddBackOffice() + .AddWebsite() + .AddDeliveryApi() + .AddComposers() + .AddUIBuilder(cfg => { + // The rest of your configuration + }) + .Build(); +``` + +## Step 4: Finalize the Migration + +1. Delete `obj/bin` folders for a clean build. +2. Recompile all projects and ensure all dependencies are restored correctly. +3. Remove existing **Konstrukt** license files from `umbraco\Licenses` folder. +4. Add your **Umbraco.UIBuilder** license key to the `appSettings.json` file: + +```json +"Umbraco": { + "Licenses": { + "Umbraco.UIBuilder": "YOUR_LICENSE_KEY" + } +} +``` + +5. Run the project. diff --git a/16/umbraco-ui-builder/upgrading/upgrade.md b/16/umbraco-ui-builder/upgrading/upgrade.md new file mode 100644 index 00000000000..cc66c3caa75 --- /dev/null +++ b/16/umbraco-ui-builder/upgrading/upgrade.md @@ -0,0 +1,65 @@ +--- +description: Learn how to manually upgrade Umbraco UI Builder to the latest version. +--- + +# Upgrading Umbraco UI Builder + +This article explains how to manually upgrade Umbraco UI Builder to the latest version. Before upgrading Umbraco UI Builder, see the [Version Specific Upgrade Notes](version-specific.md) for potential breaking changes and common pitfalls. + +{% hint style="warning" %} +Before upgrading, take a complete backup of your site and database. +{% endhint %} + +## Get the latest version of Umbraco UI Builder + +To get the latest version of Umbraco UI Builder, you can upgrade using either of the two options: + +- [NuGet](#nuget) +- [Visual Studio](#visual-studio) + +### NuGet + +- To install the latest version via NuGet: + +```sh +dotnet add package Umbraco.UIBuilder +``` + +- To specify a package version: + +```sh +dotnet add package Umbraco.UIBuilder --version +``` + +- After adding the package reference, restore dependencies: + +```sh +dotnet restore +``` + +### Visual Studio + +1. Open Visual Studio. +2. Navigate to `Tools` -> `NuGet Package Manager` -> `Manage NuGet Packages for Solution...`. +3. Select **Umbraco.UIBuilder**. +4. Choose the latest version from the drop-down and click **Install**. +5. After installation, verify the update in your **.csproj** file: + +```xml + + + +``` + +## Upgrade Sub-Packages + +If you are using any of the following sub-packages, upgrade them as well: + +| Sub-package | Description | +| -- | -- | +| Umbraco.UIBuilder.Core | Core functionality without infrastructure dependencies | +| Umbraco.UIBuilder.Infrastructure | Infrastructure-specific implementations | +| Umbraco.UIBuilder.Web | Core logic requiring a web context | +| Umbraco.UIBuilder.Web.StaticAssets |Static assets for the presentation layer | +| Umbraco.UIBuilder.Startup | Registers UI Builder with Umbraco | +| Umbraco.UIBuilder | The main UI Builder package | diff --git a/16/umbraco-ui-builder/upgrading/version-specific.md b/16/umbraco-ui-builder/upgrading/version-specific.md new file mode 100644 index 00000000000..7e2461ee6a6 --- /dev/null +++ b/16/umbraco-ui-builder/upgrading/version-specific.md @@ -0,0 +1,20 @@ +--- +description: >- + Version specific documentation for upgrading to major versions of Umbraco UI Builder. +--- + +# Version Specific Upgrade Notes + +This article provides upgrade instructions for major versions of Umbraco UI Builder. + +{% hint style="info" %} + For minor or patch upgrades, check the [Release Notes](../release-notes.md) for breaking changes. +{% endhint %} + +## Upgrade to Version 14 + +Version 14 introduces breaking changes from the previous Konstrukt product. For full migration details, see the [Migrate from Konstrukt to Umbraco UI Builder](./migrating-from-konstrukt-to-umbraco-ui-builder.md) article. + +## Legacy Version Upgrade Notes + +For out-of-support versions, see the [Legacy documentation on GitHub](https://github.com/umbraco/UmbracoDocs/tree/umbraco-eol-versions). diff --git a/16/umbraco-workflow/.gitbook.yaml b/16/umbraco-workflow/.gitbook.yaml new file mode 100644 index 00000000000..b047897620f --- /dev/null +++ b/16/umbraco-workflow/.gitbook.yaml @@ -0,0 +1,8 @@ +root: ./ + +​structure: + readme: README.md + summary: SUMMARY.md + +redirects: + diff --git a/16/umbraco-workflow/.gitbook/assets/Community.png b/16/umbraco-workflow/.gitbook/assets/Community.png new file mode 100644 index 00000000000..2755aceaf8a Binary files /dev/null and b/16/umbraco-workflow/.gitbook/assets/Community.png differ diff --git a/16/umbraco-workflow/.gitbook/assets/Documentation_blogpost_styleguide_b (1).png b/16/umbraco-workflow/.gitbook/assets/Documentation_blogpost_styleguide_b (1).png new file mode 100644 index 00000000000..cd175671fe8 Binary files /dev/null and b/16/umbraco-workflow/.gitbook/assets/Documentation_blogpost_styleguide_b (1).png differ diff --git a/16/umbraco-workflow/.gitbook/assets/Documentation_blogpost_styleguide_b.png b/16/umbraco-workflow/.gitbook/assets/Documentation_blogpost_styleguide_b.png new file mode 100644 index 00000000000..cd175671fe8 Binary files /dev/null and b/16/umbraco-workflow/.gitbook/assets/Documentation_blogpost_styleguide_b.png differ diff --git a/16/umbraco-workflow/.gitbook/assets/Documentations Icons_Umbraco_Workflow_Content_Approval.png b/16/umbraco-workflow/.gitbook/assets/Documentations Icons_Umbraco_Workflow_Content_Approval.png new file mode 100644 index 00000000000..f4863303fa6 Binary files /dev/null and b/16/umbraco-workflow/.gitbook/assets/Documentations Icons_Umbraco_Workflow_Content_Approval.png differ diff --git a/16/umbraco-workflow/.gitbook/assets/Documentations Icons_Umbraco_Workflow_Installing.png b/16/umbraco-workflow/.gitbook/assets/Documentations Icons_Umbraco_Workflow_Installing.png new file mode 100644 index 00000000000..18ac98283f1 Binary files /dev/null and b/16/umbraco-workflow/.gitbook/assets/Documentations Icons_Umbraco_Workflow_Installing.png differ diff --git a/16/umbraco-workflow/.gitbook/assets/Documentations Icons_Umbraco_Workflow_Section_Overview.png b/16/umbraco-workflow/.gitbook/assets/Documentations Icons_Umbraco_Workflow_Section_Overview.png new file mode 100644 index 00000000000..43f756927aa Binary files /dev/null and b/16/umbraco-workflow/.gitbook/assets/Documentations Icons_Umbraco_Workflow_Section_Overview.png differ diff --git a/16/umbraco-workflow/.gitbook/assets/umbraco-workflow-1.png b/16/umbraco-workflow/.gitbook/assets/umbraco-workflow-1.png new file mode 100644 index 00000000000..cb0fb06fa0c Binary files /dev/null and b/16/umbraco-workflow/.gitbook/assets/umbraco-workflow-1.png differ diff --git a/16/umbraco-workflow/README.md b/16/umbraco-workflow/README.md new file mode 100644 index 00000000000..c564278d4fa --- /dev/null +++ b/16/umbraco-workflow/README.md @@ -0,0 +1,26 @@ +--- +meta.Title: Umbraco Workflow Documentation +description: Documentation on how to work with Umbraco Workflow in just a few steps +--- + +# Umbraco Workflow Documentation + +Umbraco Workflow allows the creation of multi-stage approval workflows when writing and publishing content. Umbraco Workflow extends Umbraco's out-of-the-box publishing model with multi-stage and configurable approval workflows. A workflow process comprises multiple steps and multiple users assigned to the group responsible for providing approval at each step. + +[Learn more or purchase Umbraco Workflow to get all the features and support.](https://umbraco.com/products/umbraco-workflow/) + +
Installing Umbraco WorkflowInstall Umbraco Workflow in a few stepsinstalling-workflow.mdumbraco-workflow-1.png
Content Approval Workflows for UmbracoAllows you to design the approval process to fit your organizationapproval-groups.mdCommunity.png
Workflow Section OverviewApproving, rejecting, content reviews, and scheduling workflows are natural additions to the existing toolbox.workflow-section-dashboard.mdDocumentation_blogpost_styleguide_b (1) (1).png
+ +## Quick Links + +{% content-ref url="getting-started/dashboards-and-buttons.md" %} +[dashboards-and-buttons.md](getting-started/dashboards-and-buttons.md) +{% endcontent-ref %} + +{% content-ref url="getting-started/notifications.md" %} +[notifications.md](getting-started/notifications.md) +{% endcontent-ref %} + +{% content-ref url="getting-started/configuration.md" %} +[configuration.md](getting-started/configuration.md) +{% endcontent-ref %} diff --git a/16/umbraco-workflow/SUMMARY.md b/16/umbraco-workflow/SUMMARY.md new file mode 100644 index 00000000000..55097094079 --- /dev/null +++ b/16/umbraco-workflow/SUMMARY.md @@ -0,0 +1,43 @@ +# Table of contents + +* [Umbraco Workflow Documentation](README.md) +* [Legacy Documentation](legacy-documentation.md) +* [Release notes](release-notes.md) + +## Installation + +* [Installing Umbraco Workflow](installation/installing-workflow.md) +* [Licensing](installation/licensing.md) + +## Upgrading + +* [Upgrading Umbraco Workflow](upgrading/upgrading.md) +* [Version Specific Upgrade Notes](upgrading/version-specific.md) +* [Migrate from Plumber to Workflow](upgrading/migrating-workflow.md) + +## Getting Started + +* [Dashboards and Buttons](getting-started/dashboards-and-buttons.md) +* [Submitting Content for Approval](getting-started/submitting-changes.md) +* [Workspace View](getting-started/workflow-workspace-view.md) +* [Notifications](getting-started/notifications.md) +* [Configuration](getting-started/configuration.md) +* [Approval thresholds](getting-started/approval-thresholds.md) +* [History Cleanup](getting-started/history-cleanup.md) + +## Workflow Section + +* [Workflow Section](workflow-section/workflow-section-dashboard.md) +* [Active Workflows](workflow-section/active-workflows.md) +* [Approval Groups](workflow-section/approval-groups.md) +* [Content Reviews](workflow-section/content-reviews.md) +* [Workflow History](workflow-section/workflow-history.md) +* [Workflow Settings](workflow-section/workflow-settings.md) + +## Advanced Search + +* [Advanced Search dashboard](advanced-search/advanced-search-dashboard.md) + +## Data Generator + +* [Data Generator](data-generator/data-generator.md) diff --git a/16/umbraco-workflow/advanced-search/advanced-search-dashboard.md b/16/umbraco-workflow/advanced-search/advanced-search-dashboard.md new file mode 100644 index 00000000000..873949ce19d --- /dev/null +++ b/16/umbraco-workflow/advanced-search/advanced-search-dashboard.md @@ -0,0 +1,41 @@ +# Advanced Search Dashboard + +Advanced Search further expands Workflow's functionality outside its original content-approval focus, adding a new dashboard for performing deep searches of your website content. + +The Advanced Search dashboard is added in the content section for all users. + +![Workflow Advanced Search Dashboard in the Content Section](../advanced-search/images/workflow-advanced-search-v14.png) + +Advanced Search allows searching any number of content types, optionally filtered to a subset of variants. The search can be performed across all indexed fields, a subset of fields, or all fields using a particular Data Type or Property Editor. + +You can do an approximate Search using Lucene's default similarity measurement algorithm. + +![Workflow Advanced Search with selected content types](../advanced-search/images/approximate-search.png) + +## Search Types + +The search types are described below: + +* **All properties**: Searches for a single value across all indexed fields for the selected content types. +* **Some properties**: Searches the selected properties. A different search term can be provided for each selected property. +* **Single property**: Searches for a single value in the selected property. +* **Data Type**: Searches for a single value in all fields where the indexed property uses the selected Data Type (for example, all Textstring type). +* **Property Editor**: Searches for a single value in all fields where the indexed property uses the selected Property Editor (for example, all types using the Umbraco.TextBox editor). + +![Workflow Advanced Search with selected search type](../advanced-search/images/single-property-search-type.png) + +## Optional Fields + +Searches can be further refined by restricting results to particular editors, created, or updated date ranges. + +The additional fields are all optional. + +![Workflow Advanced Search optional fields](../advanced-search/images/additonal-optional-fields.png) + +## Search results + +Results are displayed in a familiar format, linking to nodes in an infinite editors, which allows users to retain their search results. + +Search results include published, unpublished and trashed content, and are filtered according to the current user's content start node(s). + +![Workflow Advanced Search search results](../advanced-search/images/search-type.png) \ No newline at end of file diff --git a/16/umbraco-workflow/advanced-search/images/additonal-optional-fields.png b/16/umbraco-workflow/advanced-search/images/additonal-optional-fields.png new file mode 100644 index 00000000000..cb270928dd5 Binary files /dev/null and b/16/umbraco-workflow/advanced-search/images/additonal-optional-fields.png differ diff --git a/16/umbraco-workflow/advanced-search/images/approximate-search.png b/16/umbraco-workflow/advanced-search/images/approximate-search.png new file mode 100644 index 00000000000..7f52f6227ec Binary files /dev/null and b/16/umbraco-workflow/advanced-search/images/approximate-search.png differ diff --git a/16/umbraco-workflow/advanced-search/images/search-type.png b/16/umbraco-workflow/advanced-search/images/search-type.png new file mode 100644 index 00000000000..d91ea28f8ce Binary files /dev/null and b/16/umbraco-workflow/advanced-search/images/search-type.png differ diff --git a/16/umbraco-workflow/advanced-search/images/single-property-search-type.png b/16/umbraco-workflow/advanced-search/images/single-property-search-type.png new file mode 100644 index 00000000000..da597a383de Binary files /dev/null and b/16/umbraco-workflow/advanced-search/images/single-property-search-type.png differ diff --git a/16/umbraco-workflow/advanced-search/images/workflow-advanced-search-v14.png b/16/umbraco-workflow/advanced-search/images/workflow-advanced-search-v14.png new file mode 100644 index 00000000000..3aed4eb27d4 Binary files /dev/null and b/16/umbraco-workflow/advanced-search/images/workflow-advanced-search-v14.png differ diff --git a/16/umbraco-workflow/data-generator/data-generator.md b/16/umbraco-workflow/data-generator/data-generator.md new file mode 100644 index 00000000000..90db9d30da3 --- /dev/null +++ b/16/umbraco-workflow/data-generator/data-generator.md @@ -0,0 +1,63 @@ +# Data Generator + +The Umbraco Workflow DataGenerator tool is an extension package for quickly generating Umbraco users and Workflow approval groups and permissions. + +The generator gets you up and running for testing or product evaluation without having to manually create any Workflow configuration. + +## Installation + +{% hint style="info" %} +The package must only be installed into an empty Umbraco application. +{% endhint %} + +To install the Umbraco Workflow DataGenerator package (Umbraco.Workflow.DataGenerator), follow these steps: +1. Update appSettings.development.json to enable the Workflow test license. This removes limits on group creation, and enables all features: + +``` +{ + ... + "Umbraco": { + "Workflow": { + "EnableTestLicense": true + } + } +} +``` + +2. Run the following command to add the required package references to your Umbraco project: + +``` +dotnet add package Umbraco.Workflow // if not already installed +dotnet add package Umbraco.Workflow.DataGenerator +``` + +3. Restart the web application using the following command: + +``` +dotnet run +``` + +When the application restarts, it will automatically install [The Starter Kit](https://docs.umbraco.com/umbraco-cms/tutorials/starter-kit). + +## Getting started + +The package adds an additional view in the Workflow settings, which provides controls for the data generation task. + +
Data Generator dashboard
+ +The available settings are explained below. + +* **Number of approval groups** - determines how many Workflow approval groups will be created. Defaults to two. +* **Number of users** - determines how many Umbraco users will be created. Defaults to two. +* **Number of groups per workflow** - determines how the created groups are allocated into the generated workflows. Defaults to 0, which allocates a random number of groups to each workflow. +* **Number of users per group** - determines how the created users are allocated into the generated workflow approval groups. Defaults to 0, which allocates a random number of users to each approval group. + +When the generator task completes, you will be prompted to take a Workflow tour. The tours can be resumed at any time from the Data generation view. + +Groups and users are created with arbitrary names, feel free to rename these to suit. + +### Reset + +Once Workflow configuration has been updated, the environment must be reset before regenerating. Resetting cancels all active workflows and deletes all workflow configuration. Umbraco users are not deleted, but will be reused in future data generation actions. + +
Data Generator dashboard - reset
diff --git a/16/umbraco-workflow/data-generator/images/data-gen-dashboard.png b/16/umbraco-workflow/data-generator/images/data-gen-dashboard.png new file mode 100644 index 00000000000..31447236a39 Binary files /dev/null and b/16/umbraco-workflow/data-generator/images/data-gen-dashboard.png differ diff --git a/16/umbraco-workflow/data-generator/images/data-gen-reset.png b/16/umbraco-workflow/data-generator/images/data-gen-reset.png new file mode 100644 index 00000000000..03e4aaf02c9 Binary files /dev/null and b/16/umbraco-workflow/data-generator/images/data-gen-reset.png differ diff --git a/16/umbraco-workflow/getting-started/approval-thresholds.md b/16/umbraco-workflow/getting-started/approval-thresholds.md new file mode 100644 index 00000000000..7be22b3e15b --- /dev/null +++ b/16/umbraco-workflow/getting-started/approval-thresholds.md @@ -0,0 +1,59 @@ +--- +description: >- + Use thresholds to configure how many approvals a workflow in Umbraco Workflow + requires to be considered complete. +--- + +# Approval thresholds + +{% hint style="info" %} +This feature requires a license - learn more about [Workflow's licensing model](https://umbraco.com/products/umbraco-workflow) +{% endhint %} + +Umbraco Workflow's default behavior requires one member of an approval group to approve a pending task to advance it through the workflow. + +The approval thresholds feature introduces configuration options to set the required number of approvals for a given workflow stage. + +The threshold options are: + +| Option | Description | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| One (_default_) | Pending tasks require approval from **any** member of the assigned approval group. | +| Most |

Pending tasks require approval from an absolute majority of group members.
Example: A group with 3 members requires 2 approvals and a group with 4 members requires 3 approvals.

| +| All | Pending tasks require approval from **all** group members. | + +The workflow detail UI displays the following: + +* The status of the current task. +* Approval status for members of the current group. +* Progress towards meeting the threshold for the current approval stage. +* Future tasks and the assigned group and its users. + +![Tasklist with approval thresholds](images/tasklist-with-approval-thresholds-v14.png) + +Approving a task as an administrator immediately satisfies the approval threshold for the task, and will advance to the next workflow stage. + +When a task is rejected in a workflow stage where the approval threshold is Most or All, existing approvals can be managed via configuration: + +* Existing approvals can be reset, resetting progress toward the approval threshold. In this case, all users in the approval group will be able to approve the resubmitted content. +* Existing approvals can be kept. In this case, users in the approval group who have already approved the task will not be able to approve the resubmitted content. + +## Related settings and configuration + +Approval thresholds are managed via settings in the Workflow section or in the `appsettings.json` file. Node-specific thresholds are set directly on the workflow configuration in the Workflow content app. + +### Settings + +The settings below can be set from the Backoffice or via settings customization in the `appsettings.json` file (refer to [Settings customization](configuration.md#settingscustomization) for implementation instructions). + +| Setting | Default | Description | +| ---------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------ | +| Approval threshold | `0` (One) | Sets the global approval threshold. | +| Rejection resets approvals | `false` | When `true`, and the approval threshold is Most or All, rejecting a task resets the previous approvals for the workflow stage. | +| Configure approval threshold | `false` | When `true`, enables setting the approval threshold for any stage of a workflow (on a content node or Document Type). | + +### Configuration + +The approval threshold for an individual workflow stage can be set using the control below the stage name. Setting the stage threshold requires the **Configuring approval threshold** setting to be `true`. + +![Setting approval threshold for individual workflow stages](images/approval-flow-with-thresholds-v14.png) diff --git a/16/umbraco-workflow/getting-started/configuration.md b/16/umbraco-workflow/getting-started/configuration.md new file mode 100644 index 00000000000..ad849ee5aff --- /dev/null +++ b/16/umbraco-workflow/getting-started/configuration.md @@ -0,0 +1,277 @@ +--- +description: >- + Get an overview of various options for customizing the configuration of your + Umbraco Workflow installation. +--- + +# Configuration + +With Umbraco Workflow, it is possible to customize the functionality with different configuration values. + +## Editing configuration values + +All configuration for Umbraco Workflow is held in the `appSettings.json` file found at the root of your Umbraco website. If the configuration has been customized to use another source, then the same keys and values discussed in this article can be applied there. + +The convention for Umbraco configuration is to have package-based options stored as a child structure. The child structure is added below the Umbraco element and as a sibling of the CMS. Workflow configuration follows this pattern, i.e.: + +```json +{ + ... + "Umbraco": { + "CMS": { + ... + }, + "Workflow": { + ... + } + } +} +``` + +All Workflow configuration is optional and will fallback to defaults, if not set. The following structure represents the full set of configuration options along with the default values: + +```json +{ + "Workflow": { + "ReminderNotificationPeriod": Timespan.FromHours(8), + "EnableTestLicense": false, + "EmailTemplatePath": "~/Views/Partials/WorkflowEmails", + "DateFormats": { + "DateFormat": "MMMM d, yyyy h:mm tt", + "DateFormatNoMinute": "MMMM d, yyy h tt", + "DateFormatShort": "MMMM d, yyyy", + "TimeFormat": "h:mm tt", + "TimeFormatShort": "HH:mm" + }, + "SettingsCustomization": {...} + } +``` + +### Workflow Configuration + +#### ReminderNotificationPeriod + +A `TimeSpan` representing the period between checking for, and sending, reminder notifications for overdue workflows. This setting is used in conjunction with `ReminderDelay` to determine if a workflow is overdue. + +#### EnableTestLicense + +A `bool` value used to enable or disable the test license. When true, and running Umbraco in development mode, all licensed features are available on local domains. + +#### EmailTemplatePath + +A `string` value representing the path to the email notification templates. + +#### DateFormats + +An instance of `DateTimeSettings` allowing customization of date string formats. The `DateTimeSettings` class contains properties for long and short date and time strings, plus a long date variation with no minutes. + +#### Colors + +An instance of `ColorSettings` allowing customization of colors used in email notifications. Allows setting alternate values for red, orange, and green use to highlight workflow status in emails. + +## SettingsCustomization + +All Workflow settings can be customized in the `appSettings.json` file. Settings can be read-only or hidden entirely in the BackOffice. Optionally you can set the values here. + +The `SettingsCustomization` object has two child properties: + +* `General` +* `ContentReviews` + +Both are dictionaries of `SettingsCustomizationDetail` objects. The value is set to the following structure that contains three settings: + +```json +{ + … + "MySettingKey": { + "IsHidden": false, + "IsReadOnly": false, + "Value": 42 + } + … +} +``` + +* `IsHidden` - When true, the corresponding property is not displayed in the backoffice UI +* `IsReadOnly` - When true, the corresponding property is displayed in the backoffice UI but is not editable +* `Value` - Sets the value for the corresponding property. This value takes priority over existing values set via the backoffice + +All available `SettingsCustomization` options are illustrated below along with their respective values: + +```json +{ + "Workflow": { + … + "SettingsCustomization": { + "General": { + "FlowType": 0|1|2 matching the FlowType enum values, + "ApprovalThreshold": 0|1|2 matching the ApprovalThreshold enum values, + "ConfigureApprovalThreshold": bool, + "RejectionResetsApprovals": bool, + "LockIfActive": bool, + "MandatoryComments": bool, + "AllowAttachments": bool, + "AllowScheduling": bool, + "RequireUnpublish": bool, + "ExtendPermissions": bool, + "SendNotifications": bool, + "Email": string, + "ReminderDelay": int, + "EditUrl": string, + "SiteUrl": string, + "NewNodeApprovalFlow": *, + "DocumentTypeApprovalFlow": *, + "ExcludeNodes": *, + }, + "ContentReviews": { + "EnableContentReviews": bool, + "ReviewPeriod": int, + "ReminderThreshold": int, + "SendNotifications": bool, + "PublishIsReview": bool + } + } + } +} +``` + +{% hint style="info" %} +These are complex types and are not recommended to have values set from Configuration. Instead, these values can be set from the BackOffice to hidden or read-only to prevent further changes. +{% endhint %} + +### General + +#### FlowType (int) + +Sets the workflow type to one of Explicit (0), Implicit (1), or Exclude (2): + +| Value | Name | Description | +| ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| 0 (_default_) | Explicit | Requires all steps be approved, including steps where the original change author is a group member. | +| 1 | Implicit | Auto-approves steps where the author is a member of the approving group. | +| 2 | Exclude | Behaves similarly to Explicit, but excludes the original author from any notifications (that is the author can not approve their own work). | + +#### ApprovalThreshold (int, requires a license) + +Sets the default approval threshold to one of One (0), Most (1), or All (2): + +| Value | Name | Description | +| ------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 0 (_default_) | One | Pending tasks require approval from **any** member of the assigned approval group. | +| 1 | Most |

Pending tasks require approval from an absolute majority of group members.
Example: A group with 3 members requires 2 approvals and a group with 4 members requires 3 approvals.

| +| 2 | All | Pending tasks require approval from **all** group members. | + +#### ConfigureApprovalThreshold (bool, requires a license) + +When true, allows configuring the approval threshold on individual workflow stages. + +#### RejectionResetsApprovals (bool, requires a license) + +When true, and ApprovalThreshold is Most or All, rejecting a task resets progress towards the approval threshold for the current workflow stage. + +#### LockIfActive (bool) + +When true, prevents editing content where the node is in an active workflow. When false, content can be edited at any stage of a workflow. + +#### MandatoryComments (bool) + +When true (default), comments are required when approving a workflow task. When false, comments are optional when approving a workflow task. Comments are always required when submitting changes for approval. + +#### AllowAttachments (bool) + +When true, displays an optional media picker when initiating a workflow. The selected media item can be used to provide further context or explanation of the content changes. + +#### AllowScheduling (bool) + +When true, displays optional controls for scheduling publish/unpublish when initiating a workflow. The scheduling uses Umbraco's existing content scheduling functionality. + +#### RequireUnpublish (bool) + +When true, content must be approved via a workflow when unpublishing. When false, user with appropriate permission can unpublish content without workflow approval. + +#### ExtendPermissions (bool) + +When true, Workflow adds additional buttons to the editor footer (Request publish and Request unpublish, if the latter is required). When false, Workflow replaces the existing editor footer buttons. + +#### SendNotifications (bool) + +When true, Workflow will send email notifications in response to workflow changes. When false, no emails are sent. + +#### Email (string) + +The from address for email notifications. + +#### ReminderDelay (int) + +The number of days after which to start sending reminder emails for incomplete workflows. + +#### EditUrl (string) + +The URL at which editors access the BackOffice eg `https://edit.mysite.com`. Used for generating links to nodes in email notifications. Must be fully qualified and not include the `/umbraco` path. + +#### SiteUrl (string) + +The URL at which users access the live site eg `https://mysite.com`. Used for generating links in email notifications. Must be fully qualified. + +#### NewNodeApprovalFlow (complex type) + +When set, this flow is used for all new nodes on the first approval request. Subsequent workflows use the permissions set on the node (or content type, or inherited from an ancestor node). This is a complex type and ideally would not be set via configuration. + +#### DocumentTypeApprovalFlow (complex type, requires a license) + +Sets workflow permissions for Document Types (that is: all items of `BlogItem` type use the same workflow). The Document Type flow is used when a content node has no explicit permissions set. This is a complex type and ideally should not be set via configuration. + +#### ExcludeNodes (complex type, requires a license) + +Allows excluding segments of the content tree from the workflow model. This is a complex type and ideally would not be set via configuration. + +### ContentReviews + +#### EnableContentReviews (bool) + +When true, the content review engine will monitor publication dates to determine content review requirements. + +#### ReviewPeriod (int) + +Sets the number of days between mandatory reviews. This is a global value that can be overridden at the node or content type level. + +#### ReminderThreshold (int) + +Sets the date on which to send notification emails, prior to the review date elapsing. For example, if the `ReviewPeriod` is 20 and the `ReminderThreshold` is 3, notifications will be sent in 17 days or 3 days before the review date. + +#### SendNotifications (bool) + +When true, Workflow will send email notifications to approval groups, with a digest of expiring and expired content. + +#### PublishIsReview (bool) + +When true, publishing a node is treated as a review, and will generate a new review date. When false, content must be explicitly reviewed via the review banner rendered at the top of the editor. + +For example: To set the site URL, hide it in the backoffice, and set the content review period but keep the property read-only. The configuration would look like this: + +```json +{ + "Workflow": { + "SettingsCustomization": { + "General": { + "SiteUrl": { + "IsHidden": true, + "Value": "https://www.myawesomesite.com" + } + }, + "ContentReviews": { + "ReviewPeriod": { + "IsReadOnly": true, + "Value": 42 + } + } + } + } +} +``` + +Your Integrated Development Environment (IDE) will provide intellisense for the available settings but does not provide the valid value types. Settings are validated on startup and Umbraco will throw an exception if a known setting is provided with an invalid value. + +{% hint style="info" %} +It is possible to include settings outside of those referenced by Workflow. These can be useful for providing values for use in extensions and customizations. These settings are not validated on startup so can have any value. +{% endhint %} diff --git a/16/umbraco-workflow/getting-started/dashboards-and-buttons.md b/16/umbraco-workflow/getting-started/dashboards-and-buttons.md new file mode 100644 index 00000000000..5f76ecececa --- /dev/null +++ b/16/umbraco-workflow/getting-started/dashboards-and-buttons.md @@ -0,0 +1,32 @@ +# Dashboards and Buttons + +Umbraco Workflow has its default Dashboards. By default, when you install Umbraco Workflow, you receive two Dashboards: the _User Dashboard_ and the _Admin Dashboard_. Additionally, Umbraco Workflow replaces the default Umbraco button set in the editor drawer. + +## Dashboards + +Umbraco Workflow adds two Dashboards to your Umbraco project: + +* **User Dashboard** - This Workflow Dashboard is added in the **Content** section. It displays the tasks requiring approval from the user, current user’s submissions, and stale content (content that needs to be reviewed). + + ![Workflow Dashboard in the Content Section](../images/WorkflowDashboard-ContentSection-v14.png) +* **Admin Dashboard** - This Workflow Dashboard is the default view in the **Workflow** section. It displays a chart of recent workflow activity, chart of content review activity, licensing details, and any relevant upgrade-related messages. You can also view the workflow and content review activity chart for the specified range of days. + + ![Workflow Dashboard in the Workflow Section](../images/Workflow-Admin-Dashboard-v14.png) + +## Buttons + +When a workflow is active on the current node, the **Publish** button is replaced, linking to the workflow content app. + +![Buttons](../images/Buttons.png) + +When no workflow is active, the button state is determined by the current user's permissions. + +Umbraco Workflow overrides Umbraco's User/Group publishing permissions. If the user has permission to update the node, they will be able to initiate a workflow process on that node. Umbraco Workflow shifts Umbraco from a centrally administered publishing model (controlled by a site administrator) to a distributed model. In this model, editors publish content based on their responsibilities assigned during the workflows. + +In cases, where the content is already in a workflow, a notification is displayed at the top of the editor. Depending on the Workflow **Settings**, you can enable/disable editing access on a content node in a workflow. + +![Disabled content edits](../images/blocked_content.png) + +For nodes where the workflow has been disabled, the default Umbraco options are displayed. + +![Default Button](../images/Default_Buttons.png) diff --git a/16/umbraco-workflow/getting-started/history-cleanup.md b/16/umbraco-workflow/getting-started/history-cleanup.md new file mode 100644 index 00000000000..401a0094fbc --- /dev/null +++ b/16/umbraco-workflow/getting-started/history-cleanup.md @@ -0,0 +1,141 @@ +# History Cleanup + +Every new workflow stores multiple records in the database - one for the workflow instance and one for each task in the workflow. In a multi-lingual site, depending on how you use Workflow, there may also be records generated for each culture variation. These records are used to build the workflow history views in the Umbraco backoffice. + +Depending on your requirements, this information may not be required or may only be useful for a short period of time. + +{% hint style="info" %} +The workflow History exists in addition to Umbraco's audit trail information. It will always show the identity of the user who completes the workflow. +{% endhint %} + +Umbraco Workflow 11.1.0 introduces a history cleanup feature similar to those already available in Umbraco CMS and Umbraco Forms. + +## How it works + +The History Cleanup feature is disabled by default. Applying the default history cleanup policy will: + +* Delete history older than 28 days. See the `KeepHistoryForDays` setting. +* Only delete history where the workflow status is `Approved`, `Cancelled`, `CancelledByThirdParty`, or `Errored`. See the `StatusesToDelete` setting. + +The feature can be enabled in the `appSettings.json`: + +```json +{ + "Umbraco": { + "Workflow": { + "HistoryCleanupPolicy": { + "EnableCleanup": true, + // Below settings are optional + "FirstRunTime": string; the time to first run the scheduled cleanup task, in crontab format + "Period": string; how often to run the task, in timespan format + "KeepHistoryForDays": int; delete history after this many days + "StatusesToDelete": refer to StatusesToDelete configuration below + "CleanupRules": refer to Configuration examples below + } + } + } +} +``` + +## Overriding global settings + +For sites with stricter or more complex requirements, it is possible to override the global settings for individual content nodes and Document Types. This is also managed through `appSettings.json` configuration. Configuration rules defined in application settings are prioritized over any rules set via the backoffice. It allows the developers to restrict clean up of critical history, while allowing site administrators flexibility to manage non-critical history. + +## Configuration examples + +The below example will apply the following policies: + +* History cleanup is enabled globally. +* History items with `Approved` or `Cancelled` status are deleted after 90 days. +* Workflow history for node `dcf18a51-6919-4cf8-89d1-36b94ce4d963` will never be deleted. +* Workflow history for node `31523089-f648-4883-9087-ef9a0b83129f` will be deleted after 10 days for the statuses defined in the global `StatusesToDelete` property. +* Workflow history for all nodes using the `ContentPage` Document Type will never be deleted. +* Workflow history with `Cancelled` status for all nodes using the `NewsItem` Document Type will be deleted after 100 days (see also [StatusesToDelete configuration](history-cleanup.md#statusestodelete-configuration)). + +```json +{ + "Umbraco": { + "Workflow": { + "HistoryCleanupPolicy": { + "EnableCleanup": true, + "KeepHistoryForDays": 90, + "StatusesToDelete": { + "Approved": true, + "Cancelled": true, + "CancelledByThirdParty": false, + "Errored": false + } + "CleanupRules": { + "dcf18a51-6919-4cf8-89d1-36b94ce4d963": { + "EnableCleanup": false + }, + "31523089-f648-4883-9087-ef9a0b83129f": { + "KeepHistoryForDays": 10 + }, + "ContentPage": { + "EnableCleanup": false + }, + "NewsItem": { + "KeepHistoryForDays": 100, + "StatusesToDelete": { + "Approved": false, + "Cancelled": true, + "CancelledByThirdParty": false, + "Errored": false + } + } + } + } + } + } +} +``` + +When calculating node and Document Type policies, the Document Type rules will not be processed if the current workflow instance matches a node rule. Using the above configuration as an example, consider both nodes in the `CleanupRules` dictionary are using the Document Type `ContentPage`. In this case, the Document Type rules will not be applied as the node rules are prioritized. + +If a value is omitted from the node or Document Type policy, the global value will be used instead. In the above example, the node policy for `31523089-f648-4883-9087-ef9a0b83129f` uses the `StatusesToDelete` value from the global policy that is deleting `Approved` or `Cancelled` workflow history. + +### StatusesToDelete configuration + +`StatusesToDelete` uses a dictionary built from the `WorkflowStatus` enum type. The default configuration is: + +```json + "HistoryCleanupPolicy": { + "StatusesToDelete": { + "Approved": true, + "Cancelled": true, + "CancelledByThirdParty": true, + "Errored": true, + "PendingApproval": false, + "Rejected": false, + "NotRequired": false, + "Resubmitted": false + } + } +``` + +It is possible for a cleanup rule (or the global configuration) to declare a `StatusesToDelete` property without the full set of status keys. This will not modify the default values. + +For example, adding `"Approved": false` will remove `Approved` from the deletable statuses, but all other default values will remain. Therefore, to delete approved workflows only, the configuration would look like below, where the default values have been negated: + +```json + "HistoryCleanupPolicy": { + "EnableCleanup": true, + "StatusesToDelete": { + "Approved": true, + "Cancelled": false, + "CancelledByThirdParty": false, + "Errored": false + } + } +``` + +## Backoffice configuration + +Backoffice users with access to the Workflow section will have permission to modify history cleanup rules, while all backoffice users have read-only access. + +Rules for content items and their Document Type are set from the History tab of the Workflow content app. The History view in the Workflow section provides a read-only overview of all the history cleanup rules and global configuration. + +Content items with no custom cleanup rules defined will display the global defaults. + +![Workflow History Cleanup Modal](images/workflow-history-cleanup-v14.png) diff --git a/16/umbraco-workflow/getting-started/images/Active-Workflow-detailed-info-v14.png b/16/umbraco-workflow/getting-started/images/Active-Workflow-detailed-info-v14.png new file mode 100644 index 00000000000..7abde933dfd Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/Active-Workflow-detailed-info-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/Active-workflow-initiate-request.png b/16/umbraco-workflow/getting-started/images/Active-workflow-initiate-request.png new file mode 100644 index 00000000000..0478888a065 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/Active-workflow-initiate-request.png differ diff --git a/16/umbraco-workflow/getting-started/images/Buttons.png b/16/umbraco-workflow/getting-started/images/Buttons.png new file mode 100644 index 00000000000..3cc8d7e7ad1 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/Buttons.png differ diff --git a/16/umbraco-workflow/getting-started/images/Configuration-sub-section-v14.png b/16/umbraco-workflow/getting-started/images/Configuration-sub-section-v14.png new file mode 100644 index 00000000000..b930d80dfa5 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/Configuration-sub-section-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/Content-reviews-v14.png b/16/umbraco-workflow/getting-started/images/Content-reviews-v14.png new file mode 100644 index 00000000000..7a3c7878f53 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/Content-reviews-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/Default-Buttons.png b/16/umbraco-workflow/getting-started/images/Default-Buttons.png new file mode 100644 index 00000000000..45cace64303 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/Default-Buttons.png differ diff --git a/16/umbraco-workflow/getting-started/images/History-sub-section-v14.png b/16/umbraco-workflow/getting-started/images/History-sub-section-v14.png new file mode 100644 index 00000000000..7c4d0c402d7 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/History-sub-section-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/Workflow-Content-app-Details-overlay-v14.png b/16/umbraco-workflow/getting-started/images/Workflow-Content-app-Details-overlay-v14.png new file mode 100644 index 00000000000..cfe50524e20 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/Workflow-Content-app-Details-overlay-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/Workflow-section.png b/16/umbraco-workflow/getting-started/images/Workflow-section.png new file mode 100644 index 00000000000..9bc148d2e37 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/Workflow-section.png differ diff --git a/16/umbraco-workflow/getting-started/images/WorkflowDashboard-ContentSection.png b/16/umbraco-workflow/getting-started/images/WorkflowDashboard-ContentSection.png new file mode 100644 index 00000000000..b1a885dc671 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/WorkflowDashboard-ContentSection.png differ diff --git a/16/umbraco-workflow/getting-started/images/approval-flow-types.png b/16/umbraco-workflow/getting-started/images/approval-flow-types.png new file mode 100644 index 00000000000..c58ac608eb9 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/approval-flow-types.png differ diff --git a/16/umbraco-workflow/getting-started/images/approval-flow-with-thresholds-v14.png b/16/umbraco-workflow/getting-started/images/approval-flow-with-thresholds-v14.png new file mode 100644 index 00000000000..60f82da35b7 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/approval-flow-with-thresholds-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/approval-groups-roles-v14.png b/16/umbraco-workflow/getting-started/images/approval-groups-roles-v14.png new file mode 100644 index 00000000000..911c1dba850 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/approval-groups-roles-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/approval-request-overlay-detailed-v14.png b/16/umbraco-workflow/getting-started/images/approval-request-overlay-detailed-v14.png new file mode 100644 index 00000000000..46cf7efc278 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/approval-request-overlay-detailed-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/approval-request-overlay-variants-v14.png b/16/umbraco-workflow/getting-started/images/approval-request-overlay-variants-v14.png new file mode 100644 index 00000000000..c9a7782081d Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/approval-request-overlay-variants-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/assign-rejected-task.png b/16/umbraco-workflow/getting-started/images/assign-rejected-task.png new file mode 100644 index 00000000000..365b4969a4b Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/assign-rejected-task.png differ diff --git a/16/umbraco-workflow/getting-started/images/blocked-content.png b/16/umbraco-workflow/getting-started/images/blocked-content.png new file mode 100644 index 00000000000..0f23d2b8114 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/blocked-content.png differ diff --git a/16/umbraco-workflow/getting-started/images/content-approval-flow-v14.png b/16/umbraco-workflow/getting-started/images/content-approval-flow-v14.png new file mode 100644 index 00000000000..43369a7cda3 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/content-approval-flow-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/tasklist-with-approval-thresholds-v14.png b/16/umbraco-workflow/getting-started/images/tasklist-with-approval-thresholds-v14.png new file mode 100644 index 00000000000..7ec1fe7f805 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/tasklist-with-approval-thresholds-v14.png differ diff --git a/16/umbraco-workflow/getting-started/images/workflow-history-cleanup-v14.png b/16/umbraco-workflow/getting-started/images/workflow-history-cleanup-v14.png new file mode 100644 index 00000000000..f9f45c16f01 Binary files /dev/null and b/16/umbraco-workflow/getting-started/images/workflow-history-cleanup-v14.png differ diff --git a/16/umbraco-workflow/getting-started/notifications.md b/16/umbraco-workflow/getting-started/notifications.md new file mode 100644 index 00000000000..2f5c60bf953 --- /dev/null +++ b/16/umbraco-workflow/getting-started/notifications.md @@ -0,0 +1,86 @@ +# Notifications + +Umbraco Workflow uses Notifications to allow you to hook into the processes for the backoffice. For example, you might want to execute some code every time an approval group is updated. Notifications allow you to do that. For more information on how Umbraco implements Notifications, see the [Using Notifications](https://docs.umbraco.com/umbraco-cms/reference/notifications) article. + +## Notifications + +All notifications reside in the `Umbraco.Workflow.Core.Notifications` namespace and are postfixed with `Notification`. + +Typically, available notifications exist in pairs, with a "before" and "after" notification. For example, the `SettingsService` class publishes both a `WorkflowSettingsSavingNotification` and a `WorkflowSettingsSavedNotification` when settings are modified. + +Which one you want to use depends on what you want to achieve. If you want to cancel the action, you will use the "before" notification and use the CancelOperation method on the notification to cancel it. If you want to execute some code after the settings have been updated, then you would use the "after" notification. + +## ContentReviewService Notifications + +| Notification | Members | Description | +| ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| WorkflowContentReviewsConfigSavingNotification |
  • IEnumerable SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when ContentReviewService.SaveContentReviewConfig is called in the API.
SavedEntities: Gets the collection of IWorkflowConfig objects being saved.

| +| WorkflowContentReviewsConfigSavedNotification |
  • IEnumerable SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when ContentReviewService.SaveContentReviewConfig is called in the API after the entities have been saved.
SavedEntities: Gets the collection of saved IWorkflowConfig objects.

| +| WorkflowContentReviewsEmailNotificationsSendingNotification |
  • Dictionary<UserGroupPoco, List<ContentReviewConfigPoco>> Target
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when ContentReviewReminderEmailer.SendReviewReminders is called in the API before email notifications are sent.
Target: Gets a dictionary containing information about the nodes requiring review, and the assigned review groups.

| +| WorkflowContentReviewsEmailNotificationsSentNotification |
  • Dictionary<UserGroupPoco, List<ContentReviewConfigPoco>> Target
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when ContentReviewReminderEmailer.SendReviewReminders is called in the API after email notifications are sent.
Target: Gets a dictionary containing information about the nodes requiring review, and the assigned review groups.

| +| WorkflowContentReviewsReviewingNotification |
  • ContentReviewNodePoco Target
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when ContentReviewService.MarkAsReviewed is called in the API before the node review status is updated.
Target: Get an object with information about the node being reviewed.

| +| WorkflowContentReviewsReviewedNotification |
  • ContentReviewNodePoco Target
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when ContentReviewService.MarkAsReviewed is called in the API after the node review status is updated.
Target: Get an object with information about the reviewed node.

| + +## ConfigService Notifications + +| Notification | Members | Description | +| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WorkflowContentTypeConfigDeletingNotification |
  • IEnumerable<IWorkflowConfig> DeletedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when ConfigService.DeleteContentTypeConfig is called in the API before the config items are deleted.
DeletedEntities: Gets the collection of IWorkflowConfig objects being deleted.

| +| WorkflowContentTypeConfigDeletedNotification |
  • IEnumerable<IWorkflowConfig> DeletedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when ConfigService.DeleteContentTypeConfig is called in the API after the config items are deleted.
DeletedEntities: Gets the collection of deleted IWorkflowConfig objects. Note these items are no longer in the database and exist only in memory.

| +| WorkflowContentTypeConfigSavingNotification |
  • IEnumerable<IWorkflowConfig> SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when ConfigService.UpdateContentTypeConfig is called in the API.
SavedEntities: Gets the collection of IWorkflowConfig objects being saved.

| +| WorkflowContentTypeConfigSavedNotification |
  • IEnumerable<IWorkflowConfig> SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when ConfigService.UpdateContentTypeConfig is called in the API after the entities have been saved.
SavedEntities: Gets the collection of saved IWorkflowConfig objects.

| +| WorkflowNodeConfigDeletingNotification |
  • IEnumerable<IWorkflowConfig> DeletedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when ConfigService.DeleteNodeConfig is called in the API before the config items are deleted.
DeletedEntities: Gets the collection of IWorkflowConfig objects being deleted.

| +| WorkflowNodeConfigDeletedNotification |
  • IEnumerable<IWorkflowConfig> DeletedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when ConfigService.DeleteNodeConfig is called in the API after the config items are deleted.
DeletedEntities: Gets the collection of deleted IWorkflowConfig objects. Note these items are no longer in the database and exist only in memory.

| +| WorkflowNodeConfigSavingNotification |
  • IEnumerable<IWorkflowConfig> SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when ConfigService.UpdateNodeConfig is called in the API.
SavedEntities: Gets the collection of IWorkflowConfig objects being saved.

| +| WorkflowNodeConfigSavedNotification |
  • IEnumerable<IWorkflowConfig> SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when ConfigService.UpdateNodeConfig is called in the API after the entities have been saved.
SavedEntities: Gets the collection of saved IWorkflowConfig objects.

| + +## NotificationsService Notifications + +| Notification | Members | Description | +| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WorkflowEmailNotificationsSendingNotification |
  • IEnumerable<IWorkflowInstance> Target
  • EmailType EmailType
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when NotificationsService.SendEmailNotifications is called in the API before email notifications are generated and sent.
Target: Gets the object describing the workflow instance used to build the email messages
EmailType: Gets the enum value describing the email type

| +| WorkflowEmailNotificationsSentNotification |
  • IHtmlEmailModel Target
  • List<EmailUserModel> Recipients
  • EmailType EmailType
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowReminderEmailer.Send is called in the API after email notifications are sent.
Target: Gets the object describing the email
Recipients: Gets the collection of email recipients
EmailType: Gets the enum value describing the email type

| +| WorkflowEmailRemindersSendingNotification |
  • IEnumerable<IWorkflowInstance> Target
  • EmailType EmailType
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when NotificationsService.SendEmailReminders is called in the API before email notifications are generated and sent.
Target: Gets the collection of objects describing the workflow instances used to build the email messages
EmailType: Gets the enum value describing the email type. Will always be `EmailType.Reminder`

| +| WorkflowEmailRemindersSentNotification |
  • IEnumerable<IWorkflowInstance> Target
  • List&EmailTaskListModel> Tasks
  • EmailType EmailType
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowReminderEmailer.Send is called in the API after email notifications are sent.
Target: Gets the collection of objects describing the workflow instances used to build the email messages
Tasks: Gets the collection of objects describing the overdue workflows for each notified user
EmailType: Gets the enum value describing the email type. Will always be `EmailType.Reminder`

| + +## GroupService Notifications + +| Notification | Members | Description | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| WorkflowGroupCreatingNotification |
  • IWorkflowGroup SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when GroupService.CreateUserGroupAsync is called in the API before the entity is created.
CreatedEntity: Gets the created IWorkflowGroup object.

| +| WorkflowGroupCreatedNotification |
  • IWorkflowGroup SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when GroupService.CreateUserGroupAsync is called in the API after the entity has been created.
CreatedEntity: Gets the created IWorkflowGroup object.

| +| WorkflowGroupDeletingNotification |
  • IEnumerable<IWorkflowGroup> DeletedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when GroupService.DeleteUserGroupAsync is called in the API before the group is deleted.
DeletedEntities: Gets the collection of IWorkflowGroup objects being deleted.

| +| WorkflowGroupDeletedNotification |
  • IEnumerable<IWorkflowGroup> DeletedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when GroupService.DeleteUserGroupAsync is called in the API after the group is deleted.
DeletedEntities: Gets the collection of deleted IWorkflowGroup objects.

| +| WorkflowGroupSavingNotification |
  • IEnumerable<IWorkflowGroup> SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when GroupService.UpdateUserGroupAsync is called in the API before the group is updated.
SavedEntities: Gets the collection of IWorkflowGroup objects being saved.

| +| WorkflowGroupSavedNotification |
  • IEnumerable<IWorkflowGroup> SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when GroupService.UpdateUserGroupAsync is called in the API after the group is updated.
SavedEntities: Gets the collection of saved IWorkflowGroup objects.

| + +## WorkflowProcess Notifications + +| Notification | Members | Description | +| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WorkflowInstanceApprovingNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when WorkflowProcess.ActionWorkflow is called in the API before the workflow stage is approved.
Target: Gets the IWorkflowInstance object being approved.
Action: Gets the WorkflowAction being executed. Will be WorkflowAction.Approve.

| +| WorkflowInstanceApprovedNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowProcess.ActionWorkflow is called in the API after the workflow stage is approved.
Target: Gets the approved IWorkflowInstance object.
Action: Gets the WorkflowAction being executed. Will be WorkflowAction.Approve.

| +| WorkflowInstanceCancellingNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when WorkflowProcess.ActionWorkflow is called in the API before the workflow stage is cancelled.
Target: Gets the IWorkflowInstance object being cancelled.
Action: Gets the WorkflowAction being executed. Will be WorkflowAction.Cancel.

| +| WorkflowInstanceCancelledNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowProcess.ActionWorkflow is called in the API after the workflow stage is cancelled.
Target: Gets the cancelled IWorkflowInstance object.
Action: Gets the WorkflowAction being executed. Will be WorkflowAction.Cancel.

| +| WorkflowInstanceCompletedNotification |
  • IWorkflowInstance Target
  • WorkflowType WorkflowType
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowProcess.HandleCompleteNow or WorkflowProcess.HandleCompleteLater is called in the API after the workflow is completed.
Target: Gets the completed IWorkflowInstance object.
WorkflowType: Gets the WorkflowType enum value representing the workflow type. Will be either Publish or Unpublish.

| +| WorkflowInstanceCreatingNotification |
  • IWorkflowInstance CreatedEntity
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when WorkflowProcess.InitiateWorkflow is called in the API before the workflow is initiated.
CreatedEntity: Gets the IWorkflowInstance object being created.

| +| WorkflowInstanceCreatedNotification |
  • IWorkflowInstance CreatedEntity
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowProcess.InitiateWorkflow is called in the API after the workflow is initiated.
CreatedEntity: Gets the created IWorkflowInstance object.

| +| WorkflowInstanceRejectingNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when WorkflowProcess.ActionWorkflow is called in the API before the workflow stage is rejected.
Target: Gets the IWorkflowInstance object being rejected.
Action: Gets the WorkflowAction being executed. Will be WorkflowAction.Reject.

| +| WorkflowInstanceRejectedNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowProcess.ActionWorkflow is called in the API after the workflow stage is rejected.
Target: Gets the rejected IWorkflowInstance object.
Action: Gets the WorkflowAction being executed. Will be WorkflowAction.Reject.

| +| WorkflowInstanceResubmittingNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when WorkflowProcess.ResubmitWorkflow is called in the API before the workflow stage is resubmitted.
Target: Gets the IWorkflowInstance object being resubmitted.
Action: Gets the WorkflowAction being executed. Will be WorkflowAction.Resubmit.

| +| WorkflowInstanceResubmittedNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowProcess.ResubmitWorkflow is called in the API after the workflow stage is resubmitted.
Target: Gets the resubmitted IWorkflowInstance object.
Action: Gets the WorkflowAction being executed. Will be WorkflowAction.Resubmit.

| +| WorkflowInstanceUpdatingNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Base notification class for Approving, Cancelling, Creating, Rejecting, Resubmitting. Can be used in place of these, using the Action value to identify the executed workflow action.
Published when WorkflowProcess.ResubmitWorkflow is called in the API before the workflow is updated.
Target: Gets the IWorkflowInstance object being updated.
Action: Gets the WorkflowAction being executed.

| +| WorkflowInstanceUpdatedNotification |
  • IWorkflowInstance Target
  • WorkflowAction Action
  • EventMessages Messages
  • IDictionary<string,object> State
|

Base notification class for Approved, Cancelled, Created, Rejected, Resubmitted. Can be used in place of these, using the Action value to identify the executed workflow action.
Published when WorkflowProcess.ResubmitWorkflow is called in the API after the workflow stage is updated.
Target: Gets the updated IWorkflowInstance objects.
Action: Gets the WorkflowAction being executed.

| +| WorkflowResubmitTaskCreatingNotification |
  • IWorkflowInstance CreatedEntity
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when WorkflowProcess.ResubmitWorkflow is called in the API before the workflow task is persisted.
CreatedEntity: Gets the IWorkflowTask object being created.

| +| WorkflowResubmitTaskCreatedNotification |
  • IWorkflowInstance CreatedEntity
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowProcess.ResubmitWorkflow is called in the API after the workflow task is persisted.
CreatedEntity: Gets the created IWorkflowTask.

| +| WorkflowTaskCreatingNotification |
  • IWorkflowInstance CreatedEntity
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when WorkflowTaskManager.CreateApprovalTask is called in the API before the workflow task is persisted.
CreatedEntity: Gets the IWorkflowTask object being created.

| +| WorkflowTaskCreatedNotification |
  • IWorkflowInstance CreatedEntity
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowTaskManager.CreateApprovalTask is called in the API after the workflow task is persisted.
CreatedEntity: Gets the created IWorkflowTask.

| +| WorkflowTaskUpdatingNotification |
  • IWorkflowInstance Target
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when WorkflowTaskManager.ResubmitWorkflow is called in the API before the workflow task is updated.
CreatedEntity: Gets the IWorkflowTask object being updated.

| +| WorkflowTaskUpdatedNotification |
  • IWorkflowInstance Target
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when WorkflowTaskManager.ResubmitWorkflow is called in the API after the workflow task is updated.
CreatedEntity: Gets the updated IWorkflowTask.

| + +## SettingsService Notifications + +| Notification | Members | Description | +| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| WorkflowSettingsSavingNotification |
  • IEnumerable<ISettings> SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
  • bool Cancel
|

Published when SettingsService.UpdateSettings is called in the API before the settings are saved.
SavedEntities: Gets the collection of ISettings objects being saved.

| +| WorkflowSettingsSavedNotification |
  • IEnumerable<ISettings> SavedEntities
  • EventMessages Messages
  • IDictionary<string,object> State
|

Published when SettingsService.UpdateSettings SavedEntities: Gets the collection of saved ISettings objects.

| diff --git a/16/umbraco-workflow/getting-started/submitting-changes.md b/16/umbraco-workflow/getting-started/submitting-changes.md new file mode 100644 index 00000000000..fd420a87e82 --- /dev/null +++ b/16/umbraco-workflow/getting-started/submitting-changes.md @@ -0,0 +1,54 @@ +--- +description: >- + Learn how to submit content changes for Workflow approval +--- + +# Submitting Content for Approval + +When requesting workflow approval for content changes, editors must provide additional information detailing the change. + +To submit the content changes, click the **Request publish** button in the editor footer. + +![Buttons](../images/Buttons.png) + +The button opens the request approval overlay: + +![Request approval overlay](images/approval-request-overlay-detailed-v14.png) + +Depending on the Document Type and Workflow settings, the overlay will provide inputs for: + +| Fields | Description | Visibility Conditions | +|---|---|---| +| **Describe the changes** | A field for adding comments to describe the changes made to the content. | Always visible. | +| **Action** | Allows to choose the workflow type - either Publish or Unpublish. | Visible only when **Use Workflow for unpublish** is set to true. To enable this setting, go to **Workflow** > **Settings** > **Use Workflow for unpublish**. | +| **Attachment** | Upload media or files attachment. | Visible only when **Allow attachments** is set to true. | +| **Publish on** | A date picker for scheduling the content's publishing date. | Editable only when **Allow scheduling** is set to true and the workflow type is **Publish**. It is not possible to schedule a **Publish on** date in an Unpublish workflow. | +| **Unpublish on** | A date picker for scheduling the content's unpublishing date. | Visible only when **Allow scheduling** is set to true. | +| **Variants** | Allows selection of language variants to publish. | Visible only for variant content. | + +It is possible to schedule both **Publish on** and **Unpublish on** dates in a Publish workflow. Once content has been unpublished, a new workflow process is required to republish the content. + +## Variant Workflows + +If the document varies by culture, the editor must select one or more variants to submit for approval. + +When a document is invariant, the variants selector is not displayed, and the approval flow follows the [default permissions inheritance pattern](workflow-content-app.md#approval-flow-types). + +![Request approval overlay](images/approval-request-overlay-variants-v14.png) + +The editor will not be able to select variants where: + +* They do not have permission to edit the language, or +* The variant is already in a workflow. + +When submitting multiple variants, a workflow process is started for each variant, using the [default permissions inheritance pattern](workflow-content-app.md#approval-flow-types). Newly created variants are automatically assigned the configuration from the default language. + +Alternatively, all variants can be submitted in an invariant workflow, where they will be approved in a single workflow process. Invariant workflows use the permissions set on the default language. Editors must have permission to edit all the current node's variants to be able to initiate an invariant workflow. + +The invariant workflow will publish all variants, regardless of their node state, that are not already in workflows. This means that previously unpublished variants will be republished when using invariant workflows. In most cases, it is preferable to select the individual variants. + +## Content Validation and Pending Changes + +When submitting for approval, Workflow will automatically save variants with pending changes. + +Validation errors are reported in the UI using Umbraco's validation messages. diff --git a/16/umbraco-workflow/getting-started/workflow-workspace-view.md b/16/umbraco-workflow/getting-started/workflow-workspace-view.md new file mode 100644 index 00000000000..5d1bd4aabf4 --- /dev/null +++ b/16/umbraco-workflow/getting-started/workflow-workspace-view.md @@ -0,0 +1,102 @@ +# Workspace View + +Umbraco Workflow adds a [Workspace View](https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/workspaces/workspace-views) to all content nodes in the **Content** section where a workflow is enabled. The Workflow workspace view includes three sub-sections: + +* [Active Workflow](workflow-workspace-view.md#active-workflow) +* [Configuration](workflow-workspace-view.md#configuration) +* [History](workflow-workspace-view.md#history) + +## Active Workflow + +The Active workflow sub-section provides an interface for managing workflows for the current content node. + +When the current node is pending workflow approval, the **Active workflow** sub-section displays detailed information such as: + +* Option to [approve, reject, or cancel pending workflow tasks](workflow-workspace-view.md#approve-reject-or-cancel-pending-workflow-tasks). +* View change description and track differences across pending and completed workflows. +* View the group responsible for approving the pending workflow. +* View pending language variant(s) workflow. +* View the workflow activity (eg. pending approval/task approvals/rejects) for the current workflow process. + +![Active Workflow sub-section](images/Active-Workflow-detailed-info-v14.png) + +You can access Active Workflows from two places - the **Content** section and the **Workflow** section (depending on your user permission). Workflow Administrators (those users with access to the Workflow section) can access workflows assigned to a different group. In the **Workflow History**, these are noted as being performed by the admin. + +### Approve, Reject, or Cancel pending workflow tasks + +#### Approve Workflow Tasks + +To approve a Workflow task, click on the **Approve** button in the Action section. + +#### Reject Workflow Tasks + +To reject a Workflow task, click on the **Reject** button in the Action section. Depending on the approval stage, the reviewer can decide where to send the rejected task. + +For first-stage approvals, the rejected task is sent back to the original editor/author. For second-stage approvals and above, the reviewer can send the rejected task either to the original editor or any other previous workflow group. + +![Reject Workflow Tasks](../../../10/umbraco-workflow/getting-started/images/assign-rejected-task.png) + +#### Cancel pending Workflow Tasks + +To cancel a pending Workflow task, click on the **Cancel** button in the Action section. + +## Configuration + +The Configuration sub-section provides an interface for configuring the content approval flow for the current node. It also displays any Inherited or Document type approval flows applied to the current content node. + +In multi-lingual sites, each variant can have its own approval flow. By default, new variants inherit the configuration set on the default language. + +For example, German variants can be approved by the German speakers group, while English variants are approved by the English speakers group. + +![Configuration sub-section](images/Configuration-sub-section-v14.png) + +### Content Approval Flow + +You can add different groups for different stages of content approval flow. Content Approval flow groups can be reordered via drag and drop. You can also apply the approval flow either for publish and unpublish workflows or only publish workflow. + +![Content approval flow](images/content-approval-flow-v14.png) + +#### Approval Flow Types + +Approval Flows are available in three types: Content approval flow, Inherited approval flow, and Document type approval flow. + +A given content node may have all three approval flow types applied but only one will be applied as per the following order of priority: + +| Flow Type | Description | Priority | +|---|---|---| +| **Content approval flow** | Set directly on a content node via the **Configuration** section in the **Workflow** tab. | Highest | +| **Document type approval flow** | Set in the **Settings** section. Applies to all content nodes of the selected Document Type unless overridden by a Content approval flow set directly on the node. Requires a license. | Secondary | +| **Inherited approval flow** | Used when a content node has no Content approval flow set, nor a flow applied to its Document Type. Umbraco Workflow will traverse the content tree upwards to find a Content approval flow. | Lowest | + +![Approval Flow Types](images/content-approval-flow-v14.png) + +Review the current Permissions for Approval Groups in the **Approval Groups** section for **Node-based approvals** and **Document type approvals** only. For more information see the [Roles](../workflow-section/approval-groups.md#roles) section in the [Approval Groups](../workflow-section/approval-groups.md) article. + +![Approval Groups Roles](images/approval-groups-roles-v14.png) + +Document type approval flows may contain conditional stages, such as including **Translators** in the workflow only when the **Description** property has changed. For more information on settings conditions in Document type approval flows, see the [Document type approval flows](../workflow-section/workflow-settings.md#document-type-approval-flows) section in the [Workflow Settings](../workflow-section/workflow-settings.md) article. + +Configuration cannot be modified when a content node is in a workflow process. + +#### Content reviews + +Content reviews is a tool that allows content editors to keep their content up-to-date. For more information, see the [Content reviews](../workflow-section/content-reviews.md) section. + +![Content reviews](images/Content-reviews-v14.png) + +## History + +The History sub-section provides a chronological audit trail of workflow activity for the current node. It displays a table containing the following information: + +* Type of Publish +* Who the workflow is requested by +* The date the workflow was requested +* Comments + +![History sub-section](images/History-sub-section-v14.png) + +You can also **Filter** the records based on the information listed above. Additionally, you can adjust the total number of records displayed on a page. + +The **Detail** button at the end of the record displays an overlay with content similar to the Active workflow sub-section. + +![Details overlay](images/Workflow-Content-app-Details-overlay-v14.png) diff --git a/16/umbraco-workflow/images/Active-workflow-initiate-request.png b/16/umbraco-workflow/images/Active-workflow-initiate-request.png new file mode 100644 index 00000000000..0478888a065 Binary files /dev/null and b/16/umbraco-workflow/images/Active-workflow-initiate-request.png differ diff --git a/16/umbraco-workflow/images/Active_Workflow_detailed_info.png b/16/umbraco-workflow/images/Active_Workflow_detailed_info.png new file mode 100644 index 00000000000..a10f9ca1800 Binary files /dev/null and b/16/umbraco-workflow/images/Active_Workflow_detailed_info.png differ diff --git a/16/umbraco-workflow/images/Approval-group-settings-v14.png b/16/umbraco-workflow/images/Approval-group-settings-v14.png new file mode 100644 index 00000000000..1360288c3fd Binary files /dev/null and b/16/umbraco-workflow/images/Approval-group-settings-v14.png differ diff --git a/16/umbraco-workflow/images/Approval-groups.png b/16/umbraco-workflow/images/Approval-groups.png new file mode 100644 index 00000000000..5c16278c585 Binary files /dev/null and b/16/umbraco-workflow/images/Approval-groups.png differ diff --git a/16/umbraco-workflow/images/Buttons.png b/16/umbraco-workflow/images/Buttons.png new file mode 100644 index 00000000000..3cc8d7e7ad1 Binary files /dev/null and b/16/umbraco-workflow/images/Buttons.png differ diff --git a/16/umbraco-workflow/images/Configuration-sub-section.png b/16/umbraco-workflow/images/Configuration-sub-section.png new file mode 100644 index 00000000000..a48ae7e7507 Binary files /dev/null and b/16/umbraco-workflow/images/Configuration-sub-section.png differ diff --git a/16/umbraco-workflow/images/Content-review-dashboard-v14.png b/16/umbraco-workflow/images/Content-review-dashboard-v14.png new file mode 100644 index 00000000000..e99aa91a062 Binary files /dev/null and b/16/umbraco-workflow/images/Content-review-dashboard-v14.png differ diff --git a/16/umbraco-workflow/images/Content-review-permissions-v14.png b/16/umbraco-workflow/images/Content-review-permissions-v14.png new file mode 100644 index 00000000000..094af804328 Binary files /dev/null and b/16/umbraco-workflow/images/Content-review-permissions-v14.png differ diff --git a/16/umbraco-workflow/images/ContentSectionAfterInstall.png b/16/umbraco-workflow/images/ContentSectionAfterInstall.png new file mode 100644 index 00000000000..46c4c1c4899 Binary files /dev/null and b/16/umbraco-workflow/images/ContentSectionAfterInstall.png differ diff --git a/16/umbraco-workflow/images/Create-approval-group-v14.png b/16/umbraco-workflow/images/Create-approval-group-v14.png new file mode 100644 index 00000000000..9531f844d4f Binary files /dev/null and b/16/umbraco-workflow/images/Create-approval-group-v14.png differ diff --git a/16/umbraco-workflow/images/Default_Buttons.png b/16/umbraco-workflow/images/Default_Buttons.png new file mode 100644 index 00000000000..45cace64303 Binary files /dev/null and b/16/umbraco-workflow/images/Default_Buttons.png differ diff --git a/16/umbraco-workflow/images/Enable-content-reviews-v14.png b/16/umbraco-workflow/images/Enable-content-reviews-v14.png new file mode 100644 index 00000000000..af1f4b37517 Binary files /dev/null and b/16/umbraco-workflow/images/Enable-content-reviews-v14.png differ diff --git a/16/umbraco-workflow/images/Getting-Started-workflow.png b/16/umbraco-workflow/images/Getting-Started-workflow.png new file mode 100644 index 00000000000..bcf83a62547 Binary files /dev/null and b/16/umbraco-workflow/images/Getting-Started-workflow.png differ diff --git a/16/umbraco-workflow/images/History-sub-section.png b/16/umbraco-workflow/images/History-sub-section.png new file mode 100644 index 00000000000..1315413ea85 Binary files /dev/null and b/16/umbraco-workflow/images/History-sub-section.png differ diff --git a/16/umbraco-workflow/images/Inherited-group-membership-v14.png b/16/umbraco-workflow/images/Inherited-group-membership-v14.png new file mode 100644 index 00000000000..d99af1cba53 Binary files /dev/null and b/16/umbraco-workflow/images/Inherited-group-membership-v14.png differ diff --git a/16/umbraco-workflow/images/Manage-packages-v11.png b/16/umbraco-workflow/images/Manage-packages-v11.png new file mode 100644 index 00000000000..5be8f8f03db Binary files /dev/null and b/16/umbraco-workflow/images/Manage-packages-v11.png differ diff --git a/16/umbraco-workflow/images/Manage_packages_v10.png b/16/umbraco-workflow/images/Manage_packages_v10.png new file mode 100644 index 00000000000..0478d7ffdb7 Binary files /dev/null and b/16/umbraco-workflow/images/Manage_packages_v10.png differ diff --git a/16/umbraco-workflow/images/Manage_packages_v11.png b/16/umbraco-workflow/images/Manage_packages_v11.png new file mode 100644 index 00000000000..97c3312c20e Binary files /dev/null and b/16/umbraco-workflow/images/Manage_packages_v11.png differ diff --git a/16/umbraco-workflow/images/Notifications-tab-v14.png b/16/umbraco-workflow/images/Notifications-tab-v14.png new file mode 100644 index 00000000000..518288eb332 Binary files /dev/null and b/16/umbraco-workflow/images/Notifications-tab-v14.png differ diff --git a/16/umbraco-workflow/images/VS_Installation-v14.png b/16/umbraco-workflow/images/VS_Installation-v14.png new file mode 100644 index 00000000000..ae250a8d574 Binary files /dev/null and b/16/umbraco-workflow/images/VS_Installation-v14.png differ diff --git a/16/umbraco-workflow/images/Workflow-Admin-Dashboard-v14.png b/16/umbraco-workflow/images/Workflow-Admin-Dashboard-v14.png new file mode 100644 index 00000000000..43e0e45066e Binary files /dev/null and b/16/umbraco-workflow/images/Workflow-Admin-Dashboard-v14.png differ diff --git a/16/umbraco-workflow/images/Workflow-Content-app-Details-overlay.png b/16/umbraco-workflow/images/Workflow-Content-app-Details-overlay.png new file mode 100644 index 00000000000..0c019a88c6a Binary files /dev/null and b/16/umbraco-workflow/images/Workflow-Content-app-Details-overlay.png differ diff --git a/16/umbraco-workflow/images/WorkflowDashboard-ContentSection-v14.png b/16/umbraco-workflow/images/WorkflowDashboard-ContentSection-v14.png new file mode 100644 index 00000000000..d5f4091f23a Binary files /dev/null and b/16/umbraco-workflow/images/WorkflowDashboard-ContentSection-v14.png differ diff --git a/16/umbraco-workflow/images/WorkflowDashboard_WorkflowSection.png b/16/umbraco-workflow/images/WorkflowDashboard_WorkflowSection.png new file mode 100644 index 00000000000..66d6181a8ce Binary files /dev/null and b/16/umbraco-workflow/images/WorkflowDashboard_WorkflowSection.png differ diff --git a/16/umbraco-workflow/images/Workflow_dashboard.png b/16/umbraco-workflow/images/Workflow_dashboard.png new file mode 100644 index 00000000000..10402b30313 Binary files /dev/null and b/16/umbraco-workflow/images/Workflow_dashboard.png differ diff --git a/16/umbraco-workflow/images/Workflow_section.png b/16/umbraco-workflow/images/Workflow_section.png new file mode 100644 index 00000000000..9bc148d2e37 Binary files /dev/null and b/16/umbraco-workflow/images/Workflow_section.png differ diff --git a/16/umbraco-workflow/images/active-workflow-detail-overlay.png b/16/umbraco-workflow/images/active-workflow-detail-overlay.png new file mode 100644 index 00000000000..9c015834a93 Binary files /dev/null and b/16/umbraco-workflow/images/active-workflow-detail-overlay.png differ diff --git a/16/umbraco-workflow/images/active-workflows-section.png b/16/umbraco-workflow/images/active-workflows-section.png new file mode 100644 index 00000000000..816bda36569 Binary files /dev/null and b/16/umbraco-workflow/images/active-workflows-section.png differ diff --git a/16/umbraco-workflow/images/add-approval-flow-v14.png b/16/umbraco-workflow/images/add-approval-flow-v14.png new file mode 100644 index 00000000000..e3ba5f262bd Binary files /dev/null and b/16/umbraco-workflow/images/add-approval-flow-v14.png differ diff --git a/16/umbraco-workflow/images/add-doc-type-approval-flows-settings-v14.png b/16/umbraco-workflow/images/add-doc-type-approval-flows-settings-v14.png new file mode 100644 index 00000000000..1166617a49b Binary files /dev/null and b/16/umbraco-workflow/images/add-doc-type-approval-flows-settings-v14.png differ diff --git a/16/umbraco-workflow/images/add-group-member-v14.png b/16/umbraco-workflow/images/add-group-member-v14.png new file mode 100644 index 00000000000..b4c769ed60c Binary files /dev/null and b/16/umbraco-workflow/images/add-group-member-v14.png differ diff --git a/16/umbraco-workflow/images/approval-flow-types.png b/16/umbraco-workflow/images/approval-flow-types.png new file mode 100644 index 00000000000..c58ac608eb9 Binary files /dev/null and b/16/umbraco-workflow/images/approval-flow-types.png differ diff --git a/16/umbraco-workflow/images/approval-group-history-v14.png b/16/umbraco-workflow/images/approval-group-history-v14.png new file mode 100644 index 00000000000..5e59bd5aaa9 Binary files /dev/null and b/16/umbraco-workflow/images/approval-group-history-v14.png differ diff --git a/16/umbraco-workflow/images/approval-group-members-v14.png b/16/umbraco-workflow/images/approval-group-members-v14.png new file mode 100644 index 00000000000..ebb48dfb7b8 Binary files /dev/null and b/16/umbraco-workflow/images/approval-group-members-v14.png differ diff --git a/16/umbraco-workflow/images/approval-groups-role-v14.png b/16/umbraco-workflow/images/approval-groups-role-v14.png new file mode 100644 index 00000000000..2c61e4460a2 Binary files /dev/null and b/16/umbraco-workflow/images/approval-groups-role-v14.png differ diff --git a/16/umbraco-workflow/images/approval-groups-roles.png b/16/umbraco-workflow/images/approval-groups-roles.png new file mode 100644 index 00000000000..281b1d36a29 Binary files /dev/null and b/16/umbraco-workflow/images/approval-groups-roles.png differ diff --git a/16/umbraco-workflow/images/assign-rejected-task.png b/16/umbraco-workflow/images/assign-rejected-task.png new file mode 100644 index 00000000000..365b4969a4b Binary files /dev/null and b/16/umbraco-workflow/images/assign-rejected-task.png differ diff --git a/16/umbraco-workflow/images/blocked_content.png b/16/umbraco-workflow/images/blocked_content.png new file mode 100644 index 00000000000..0f23d2b8114 Binary files /dev/null and b/16/umbraco-workflow/images/blocked_content.png differ diff --git a/16/umbraco-workflow/images/content-app.png b/16/umbraco-workflow/images/content-app.png new file mode 100644 index 00000000000..312a09792dd Binary files /dev/null and b/16/umbraco-workflow/images/content-app.png differ diff --git a/16/umbraco-workflow/images/content-approval-flow.gif b/16/umbraco-workflow/images/content-approval-flow.gif new file mode 100644 index 00000000000..b2b078cacb3 Binary files /dev/null and b/16/umbraco-workflow/images/content-approval-flow.gif differ diff --git a/16/umbraco-workflow/images/content-item-reviews-select-content-v14.png b/16/umbraco-workflow/images/content-item-reviews-select-content-v14.png new file mode 100644 index 00000000000..01e7bf2372d Binary files /dev/null and b/16/umbraco-workflow/images/content-item-reviews-select-content-v14.png differ diff --git a/16/umbraco-workflow/images/content-item-reviews-settings.png b/16/umbraco-workflow/images/content-item-reviews-settings.png new file mode 100644 index 00000000000..8b68fb47d94 Binary files /dev/null and b/16/umbraco-workflow/images/content-item-reviews-settings.png differ diff --git a/16/umbraco-workflow/images/content-item-reviews-v14.png b/16/umbraco-workflow/images/content-item-reviews-v14.png new file mode 100644 index 00000000000..c60a9cac09c Binary files /dev/null and b/16/umbraco-workflow/images/content-item-reviews-v14.png differ diff --git a/16/umbraco-workflow/images/content-review-date-v14.png b/16/umbraco-workflow/images/content-review-date-v14.png new file mode 100644 index 00000000000..f51e5fc0ae6 Binary files /dev/null and b/16/umbraco-workflow/images/content-review-date-v14.png differ diff --git a/16/umbraco-workflow/images/content-review-message-banner-v14.png b/16/umbraco-workflow/images/content-review-message-banner-v14.png new file mode 100644 index 00000000000..0b0aa54e4ca Binary files /dev/null and b/16/umbraco-workflow/images/content-review-message-banner-v14.png differ diff --git a/16/umbraco-workflow/images/content-reviews-filter-v14.png b/16/umbraco-workflow/images/content-reviews-filter-v14.png new file mode 100644 index 00000000000..7e26e61ceaa Binary files /dev/null and b/16/umbraco-workflow/images/content-reviews-filter-v14.png differ diff --git a/16/umbraco-workflow/images/content-reviews-general-settings-v14.png b/16/umbraco-workflow/images/content-reviews-general-settings-v14.png new file mode 100644 index 00000000000..33aa0f55415 Binary files /dev/null and b/16/umbraco-workflow/images/content-reviews-general-settings-v14.png differ diff --git a/16/umbraco-workflow/images/content-reviews-pagesize-v14.png b/16/umbraco-workflow/images/content-reviews-pagesize-v14.png new file mode 100644 index 00000000000..249401a2058 Binary files /dev/null and b/16/umbraco-workflow/images/content-reviews-pagesize-v14.png differ diff --git a/16/umbraco-workflow/images/details-overlay.png b/16/umbraco-workflow/images/details-overlay.png new file mode 100644 index 00000000000..8790cad0869 Binary files /dev/null and b/16/umbraco-workflow/images/details-overlay.png differ diff --git a/16/umbraco-workflow/images/doc-type-approval-flows-v14.png b/16/umbraco-workflow/images/doc-type-approval-flows-v14.png new file mode 100644 index 00000000000..c330b4cdc64 Binary files /dev/null and b/16/umbraco-workflow/images/doc-type-approval-flows-v14.png differ diff --git a/16/umbraco-workflow/images/document-type-review-settings-v13.png b/16/umbraco-workflow/images/document-type-review-settings-v13.png new file mode 100644 index 00000000000..f2989cd709a Binary files /dev/null and b/16/umbraco-workflow/images/document-type-review-settings-v13.png differ diff --git a/16/umbraco-workflow/images/document-type-review-settings.png b/16/umbraco-workflow/images/document-type-review-settings.png new file mode 100644 index 00000000000..5a2084b7036 Binary files /dev/null and b/16/umbraco-workflow/images/document-type-review-settings.png differ diff --git a/16/umbraco-workflow/images/document-type-reviews-select-content-v14.png b/16/umbraco-workflow/images/document-type-reviews-select-content-v14.png new file mode 100644 index 00000000000..9ed524ff80b Binary files /dev/null and b/16/umbraco-workflow/images/document-type-reviews-select-content-v14.png differ diff --git a/16/umbraco-workflow/images/document-type-reviews-v14.png b/16/umbraco-workflow/images/document-type-reviews-v14.png new file mode 100644 index 00000000000..4e4a5ac3091 Binary files /dev/null and b/16/umbraco-workflow/images/document-type-reviews-v14.png differ diff --git a/16/umbraco-workflow/images/edit-doc-type-approval-flows-settings-v14.png b/16/umbraco-workflow/images/edit-doc-type-approval-flows-settings-v14.png new file mode 100644 index 00000000000..ae6c6f9ccb9 Binary files /dev/null and b/16/umbraco-workflow/images/edit-doc-type-approval-flows-settings-v14.png differ diff --git a/16/umbraco-workflow/images/edit-doc-type-approval-flows-v14.png b/16/umbraco-workflow/images/edit-doc-type-approval-flows-v14.png new file mode 100644 index 00000000000..501dc8ecd27 Binary files /dev/null and b/16/umbraco-workflow/images/edit-doc-type-approval-flows-v14.png differ diff --git a/16/umbraco-workflow/images/exclude-nodes-v14.png b/16/umbraco-workflow/images/exclude-nodes-v14.png new file mode 100644 index 00000000000..4c73fbf02ce Binary files /dev/null and b/16/umbraco-workflow/images/exclude-nodes-v14.png differ diff --git a/16/umbraco-workflow/images/general-settings-v13.png b/16/umbraco-workflow/images/general-settings-v13.png new file mode 100644 index 00000000000..bab01c20694 Binary files /dev/null and b/16/umbraco-workflow/images/general-settings-v13.png differ diff --git a/16/umbraco-workflow/images/general-settings.png b/16/umbraco-workflow/images/general-settings.png new file mode 100644 index 00000000000..e4a6b20446e Binary files /dev/null and b/16/umbraco-workflow/images/general-settings.png differ diff --git a/16/umbraco-workflow/images/history-detail-button.png b/16/umbraco-workflow/images/history-detail-button.png new file mode 100644 index 00000000000..660014094ca Binary files /dev/null and b/16/umbraco-workflow/images/history-detail-button.png differ diff --git a/16/umbraco-workflow/images/history-filter-v14.png b/16/umbraco-workflow/images/history-filter-v14.png new file mode 100644 index 00000000000..e936604f13f Binary files /dev/null and b/16/umbraco-workflow/images/history-filter-v14.png differ diff --git a/16/umbraco-workflow/images/history-pagesize.png b/16/umbraco-workflow/images/history-pagesize.png new file mode 100644 index 00000000000..8d55160e9f9 Binary files /dev/null and b/16/umbraco-workflow/images/history-pagesize.png differ diff --git a/16/umbraco-workflow/images/lic.png b/16/umbraco-workflow/images/lic.png new file mode 100644 index 00000000000..ac07a7f0428 Binary files /dev/null and b/16/umbraco-workflow/images/lic.png differ diff --git a/16/umbraco-workflow/images/new-node-approval-flow-v14.png b/16/umbraco-workflow/images/new-node-approval-flow-v14.png new file mode 100644 index 00000000000..3436bff17f9 Binary files /dev/null and b/16/umbraco-workflow/images/new-node-approval-flow-v14.png differ diff --git a/16/umbraco-workflow/images/select-content-from-tree-v14.png b/16/umbraco-workflow/images/select-content-from-tree-v14.png new file mode 100644 index 00000000000..8e065b8a608 Binary files /dev/null and b/16/umbraco-workflow/images/select-content-from-tree-v14.png differ diff --git a/16/umbraco-workflow/images/workflow-content-app-configuration.png b/16/umbraco-workflow/images/workflow-content-app-configuration.png new file mode 100644 index 00000000000..20f3d9ec942 Binary files /dev/null and b/16/umbraco-workflow/images/workflow-content-app-configuration.png differ diff --git a/16/umbraco-workflow/images/workflow-history-v14.png b/16/umbraco-workflow/images/workflow-history-v14.png new file mode 100644 index 00000000000..d9a6d22ae08 Binary files /dev/null and b/16/umbraco-workflow/images/workflow-history-v14.png differ diff --git a/16/umbraco-workflow/images/workflow-section-v14.png b/16/umbraco-workflow/images/workflow-section-v14.png new file mode 100644 index 00000000000..1493d5e21de Binary files /dev/null and b/16/umbraco-workflow/images/workflow-section-v14.png differ diff --git a/16/umbraco-workflow/images/workflow-settings-v14.png b/16/umbraco-workflow/images/workflow-settings-v14.png new file mode 100644 index 00000000000..58d540aac88 Binary files /dev/null and b/16/umbraco-workflow/images/workflow-settings-v14.png differ diff --git a/16/umbraco-workflow/installation/installing-workflow.md b/16/umbraco-workflow/installation/installing-workflow.md new file mode 100644 index 00000000000..425ac1bb83a --- /dev/null +++ b/16/umbraco-workflow/installation/installing-workflow.md @@ -0,0 +1,71 @@ +# Installation + +In this article, we will cover the steps required to install Umbraco Workflow on your website. + +## Prerequisites + +* [Microsoft Visual Studio](https://visualstudio.microsoft.com/) + +### Video Tutorial + +{% embed url="https://www.youtube.com/embed/OUD-PbWESAs?rel=0" %} +Installing Umbraco Workflow. +{% endembed %} + +## Umbraco Workflow Installation + +There are different ways to install Umbraco Workflow: + +* [.Net CLI Installation](installing-workflow.md#net-cli-installation) +* [Visual Studio Installation](installing-workflow.md#visual-studio-installation) + +### .Net CLI Installation + +To install the Umbraco Workflow package (Umbraco.Workflow), follow these steps: + +1. Run the following command to add a package reference to your Umbraco project: + +``` +dotnet add package Umbraco.Workflow +``` + +2. Restart the web application using the following command: + +``` +dotnet run +``` + +### Visual Studio Installation + +To install via Visual Studio, follow these steps: + +1. Open your project in Visual Studio. +2. Go to **Tools** -> **NuGet Package Manager** -> **Manage NuGet Packages for Solution...**. +3. Browse for **Umbraco.Workflow**. +4. Select the appropriate version from the Version drop-down depending on the Umbraco version you are using. +5. Click **Install**. + + ![Installing Umbraco Workflow](../images/VS_Installation-v14.png) +6. Once the package is installed, open the **.csproj** file to make sure the package reference is added: + +```xml + + + +``` + +{% hint style="info" %} +To test-drive Umbraco Workflow consider installing the [Umbraco.Workflow.DataGenerator package](../data-generator/data-generator). +{% endhint %} + +## Using Umbraco Workflow + +Once the installation is completed, you will see the following in the Umbraco Backoffice: + +### A Workflow Dashboard + +![Workflow dashboard.](../images/ContentSectionAfterInstall.png) + +### A Workflow section + +![Workflow section.](../images/workflow-section-v14.png) diff --git a/16/umbraco-workflow/installation/licensing.md b/16/umbraco-workflow/installation/licensing.md new file mode 100644 index 00000000000..e9e6ba474df --- /dev/null +++ b/16/umbraco-workflow/installation/licensing.md @@ -0,0 +1,153 @@ +# Licensing + +Umbraco Workflow is a licensed product that does not require a purchase. New installations default to a trial license while the paid license is available for purchase. + +## Purchasing an Umbraco Workflow License + +If you want to buy an Umbraco Workflow license, use [the contact form to get in touch](https://umbraco.com/products/add-ons/workflow#order). + +### Free vs licensed versions + +Umbraco Workflow is available in free and licensed versions. While the licensed version includes all features and no restrictions, the free version has some limitations. + +In the free version, the following features are disabled: + +- Document Type workflow configuration +- Document Type content review configuration +- History cleanup and related configuration +- Approval thresholds and related configuration +- Content comparison +- Exclude nodes + +In the free version, a maximum of five approval groups can be created. + +## Installing your license + +Once you have received your license code it needs to be installed on your site. + +1. Open the root directory for your project files. +2. Locate and open the `appSettings.json` file. +3. Add your Umbraco Workflow license key to `Umbraco:Licenses:Umbraco.Workflow`: + +```json +"Umbraco": { + "Licenses": { + "Products": { + "Umbraco.Workflow": "YOUR_LICENSE_KEY" + } + } +} +``` + +### Verify the license installation + +You can verify that your license is successfully installed by logging into your project's backoffice and navigating to the settings section. Here you will see a licenses dashboard which should display the status of your license. + +### When and how to configure an `UmbracoApplicationUrl` + +The website domain used for validating the license is determined from your Umbraco instance. To ensure the correct one is used, you can configure the `UmbracoApplicationUrl`. + +If you are running on a single domain for both your frontend and backend environments, it's not necessary to configure a `UmbracoApplicationUrl`. + +If you have different domains for your frontend and backend, then it's advised that you configure an `UmbracoApplicationUrl` set to your backoffice URL. This helps the licensing engine know which URL should be used for validation checks. Without this configuration setting, the licensing engine will try and work out the domain to validate from the HTTP request object. This can lead to errors when switching between domains. + +An `UmbracoApplicationUrl` can be configured in your `appSettings.json` file like so: + +```json +{ + "Umbraco": { + "CMS": { + "WebRouting": { + "UmbracoApplicationUrl": "https://admin.my-custom-domain.com/" + } + } + } +} +``` + +See the [Fixed Application URL](https://docs.umbraco.com/umbraco-cms/extending/health-check/guides/fixedapplicationurl) documentation for more details about this setting. + +#### Configuring `UmbracoApplicationUrl` on Umbraco Cloud + +If you are hosting on Umbraco Cloud you will find the configuration described above won't be reflected in your environment. The reason for this is that Umbraco Cloud sets this value as an environment variable set to the Cloud project domain (`.umbraco.io`). This overrides what is set via the `appSettings.json` file. + +There are two options in this case: +- Either the domains for each of your Cloud environments can be added to your license. +- Or, for more control and to ensure this value is set correctly for other reasons, you can apply the configuration via code. + +For example, in your `Program.cs` file: + +```csharp +builder.Services.Configure(o => o.UmbracoApplicationUrl = ""); +``` + +In practice, you will probably want to make this a bit more sophisticated. You can read the value from another configuration key, removing the need to hard-code it and have it set as appropriate in different environments. You can also move this code into a composer or an extension method if you prefer not to clutter up the `Program.cs` file. + +### Using a Trial License + +The trial license introduces some restrictions around advanced features but is otherwise a full-featured workflow platform. The paid license is valid for one top-level domain and all its subdomains. + +To impersonate the full license on a local site, set `EnableTestLicense` to `true` in the `appSettings.json` file: + +```json +{ + "Umbraco": { + "Workflow": { + "EnableTestLicense": true + } + } +} +``` + +{% hint style="info" %} +The test license is restricted to sites running in a development environment with a debugger attached. Hit F5 in Visual Studio, in Debug mode to enable the test license. +{% endhint %} + +### Validating a license without an outgoing Internet connection + +Some Umbraco installations will have a highly locked down production environment, with firewall rules that prevent outgoing HTTP requests. This will interfere with the normal process of license validation. + +On start-up, and periodically whilst Umbraco is running, the license component used by Umbraco Workflow will make an HTTP POST request to `https://license-validation.umbraco.com/api/ValidateLicense`. + +If it's possible to do so, the firewall rules should be adjusted to allow this request. + +If such a change is not feasible, there is another approach you can use. + +You will need to have a server, or serverless function, that is running and can make a request to the online license validation service. That needs to run on a daily schedule, making a request and relaying it onto the restricted Umbraco environment. + +To set this up, firstly ensure you have a reference to `Umbraco.Licenses` version 13.1 or higher. If the version of Workflow you are using depends on an earlier version, you can add a direct package reference for `Umbraco.Licenses`. + +Then configure a random string as an authorization key in configuration. This is used as protection to ensure only valid requests are handled. You can also disable the normal regular license checks - as there is no point in these running if they will be blocked: + +```json + "Umbraco": { + "Licenses": { + "Umbraco.Workflow": "" + }, + "LicensesOptions": { + "EnableScheduledValidation": false, + "ValidatedLicenseRelayAuthKey": "" + } + } +``` + +Your Internet enabled server should make a request of the following form to the online license validation service: + +``` +POST https://license-validation.umbraco.com/api/ValidateLicense +{ + "ProductId": "Umbraco.Workflow", + "LicenseKey": "", + "Domain": "" +} +``` + +The response should be relayed exactly via an HTTP request to your restricted Umbraco environment: + +``` +POST http:///umbraco/licenses/validatedLicense/relay?productId=&licenseKey= +``` + +A header with a key of `X-AUTH-KEY` and value of the authorization key you have configured should be provided. + +This will trigger the same processes that occur when the normal scheduled validation completes ensuring your product is considered licensed. diff --git a/16/umbraco-workflow/legacy-documentation.md b/16/umbraco-workflow/legacy-documentation.md new file mode 100644 index 00000000000..721d81f2a37 --- /dev/null +++ b/16/umbraco-workflow/legacy-documentation.md @@ -0,0 +1,7 @@ +# Legacy Documentation + +This documentation platform covers only major versions of the Umbraco Workflow since Umbraco 9+. If you are using Umbraco Plumber, you will need to go elsewhere. + +The documentation for Umbraco 7 and 8 lives on [our.umbraco.com](https://our.umbraco.com/documentation/Add-ons/). + +
Umbraco 11 Documentationhttps://github.com/umbraco/UmbracoDocs/tree/umbraco-eol-versions/11/umbraco-workflow
Umbraco 8 Documentationhttps://our.umbraco.com/documentation/Add-ons/Umbraco-Plumber/
diff --git a/16/umbraco-workflow/release-notes.md b/16/umbraco-workflow/release-notes.md new file mode 100644 index 00000000000..eebdafa5180 --- /dev/null +++ b/16/umbraco-workflow/release-notes.md @@ -0,0 +1,66 @@ +--- +description: Get an overview of the changes and fixes in each version of Umbraco Workflow. +--- + +# Release notes + +In this section, we have summarized the changes to Umbraco Workflow that were released in each version. Each version is presented with a link to the [Workflow issue tracker](https://github.com/umbraco/Umbraco.Workflow.Issues/issues) showing a list of issues resolved in the release. We also link to the individual issues themselves from the detail. + +If there are any breaking changes or other issues to be aware of when upgrading they are also noted here. + +{% hint style="info" %} +Check the [Version Specific Upgrade Notes](upgrading/version-specific.md) article for breaking changes when upgrading to a new major version. +{% endhint %} + +## Release History + +This section contains the release notes for Umbraco Workflow 15 including all changes for this version. + +### 15.1.2 (April 2 2025) +* Improves culture variant handling in Advanced Search +* Ensure case-insensitive culture comparison when fetching tasks + +### 15.1.1 (March 20 2025) +* Fixes an intermittent issue where fetching approval groups in a mapper resulted in a scoping error + +### 15.1.0 (https://github.com/umbraco/Umbraco.Workflow.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.1.0) (March 7 2025 ) +* Dependency update for Umbraco.Licenses (making this release a minor) +* Fixes pagination in assigned-to task table [#96](https://github.com/umbraco/Umbraco.Workflow.Issues/issues/91) +* Fixes off-by-one bug when calculating approval thresholds with implicit approval [#97](https://github.com/umbraco/Umbraco.Workflow.Issues/issues/97) +* Allow searching for empty fields in advanced search. For example, search for all Product documents with no SKU + +### 15.0.4 (March 3, 2025) +* Fixes an issue where Workflow's content lock was always applied on documents where Workflow was not configured. +* Fixes a related issue where the content lock was never applied on invariant documents with no Workflow configuration. + +### 15.0.3 (February 14, 2025) +* Fixes SQLite migration bug where async methods were causing a race condition. + +### [15.0.2](https://github.com/umbraco/Umbraco.Workflow.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F15.0.2) (January 16 2025 ) +* Fixes workflow task summary generation in email body [#91](https://github.com/umbraco/Umbraco.Workflow.Issues/issues/91) +* Fixes localization in email body +* Updates Umbraco.Licenses dependency +* Refactors migration plan naming to align with the broader DXP product suite. + +### 15.0.1 (December 16th 2024) +* Fixes column type mismatch in migration +* Correctly implements delay time in History Cleanup hosted service + +### 15.0.0 (November 14th, 2024) +* Compatibility with Umbraco 15 +* Replaces entity action wrappers with `umbExtensionRegistry.appendCondition()` +* Adds abstraction over `UmbContentWorkspaceContext.readOnlyState` to consistently implement readonly document workspaces. +* Fixes invariant culture handling when unlocking a scheduled document. + +### 15.0.0-rc3 (November 8th, 2024) +* Compatibility with Umbraco 15-rc3 + +### 15.0.0-rc2 (October 23rd, 2024) +* Compatibility with Umbraco 15-rc2 + +### 15.0.0-rc1 (October 9th, 2024) +* Compatibility with Umbraco 15-rc1 + +## Legacy release notes + +You can find the release notes for versions out of support in the [Legacy documentation on GitHub](https://github.com/umbraco/UmbracoDocs/blob/umbraco-eol-versions/11/umbraco-workflow/release-notes.md) diff --git a/16/umbraco-workflow/upgrading/migrating-workflow.md b/16/umbraco-workflow/upgrading/migrating-workflow.md new file mode 100644 index 00000000000..bd08c7ec8b8 --- /dev/null +++ b/16/umbraco-workflow/upgrading/migrating-workflow.md @@ -0,0 +1,33 @@ +# Migrate from Plumber to Workflow + +Umbraco Workflow is backwards compatible with Plumber data. However, with a new default namespace constituting a major breaking change any existing customization or extension needs to be updated. + +To migrate from an Umbraco installation with an existing Plumber installation to Umbraco Workflow, follow these steps: + +{% tabs %} +{% tab title="Site running on SQL Server database" %} +1. Uninstall Plumber and remove the `/App_Plugins/Plumber` folder. +2. Upgrade your project to Umbraco 11. +3. Install Umbraco Workflow 11. See the [Installing Umbraco Workflow](../installation/installing-workflow.md) article. +4. Build the application. + +{% hint style="info" %} +SQL is the preferred database provider for production websites. +{% endhint %} +{% endtab %} + +{% tab title="Site running on SQLite database" %} +1. Uninstall Plumber and remove the `/App_Plugins/Plumber` folder. +2. Upgrade your project to Umbraco 11. +3. Make a copy of the `Value` column from the `WorkflowSettings` table. +4. Delete the `WorkflowSettings` table. +5. Update `WorkflowTaskInstance` table to allow null values in the GroupId column. +6. Install Umbraco Workflow 11. See the [Installing Umbraco Workflow](../installation/installing-workflow.md) article. +7. Build the application. +8. Update the `WorkflowSettings` table to restore the previous data to the `Value` column. +{% endtab %} +{% endtabs %} + +{% hint style="info" %} +All your existing workflow data and settings are not affected and will be available on your upgraded site. +{% endhint %} diff --git a/16/umbraco-workflow/upgrading/upgrading.md b/16/umbraco-workflow/upgrading/upgrading.md new file mode 100644 index 00000000000..5dd85d868b7 --- /dev/null +++ b/16/umbraco-workflow/upgrading/upgrading.md @@ -0,0 +1,36 @@ +# Upgrading + +This article shows how to manually upgrade Umbraco Workflow to run the latest version. Umbraco Workflow displays a prompt in the **Workflow** section when a new version is available. + +{% hint style="info" %} +If you are migrating from Plumber to Umbraco Workflow, see the [Migrate from Plumber to Workflow](migrating-workflow.md) article. +{% endhint %} + +## Get the latest version of Umbraco Workflow + +To get the latest version of Umbraco Workflow, you can upgrade using either of the two options: + +* [NuGet](upgrading.md#nuget) +* [Visual Studio](upgrading.md#visual-studio) + +### NuGet + +* NuGet installs the latest version of the package when you use the `dotnet add package Umbraco.Workflow` command unless you specify a package version: + + `dotnet add package Umbraco.Workflow --version ` +* Run `dotnet restore` to install the package. + +### Visual Studio + +* Go to `Tools` -> `NuGet Package Manager` -> `Manage NuGet Packages for Solution...` in Visual Studio, to upgrade Umbraco Workflow: +* Select **Umbraco.Workflow**. +* Select the latest version from the **Version** drop-down and click **Install**. + + ![NuGet Package Manager](../images/VS_Installation-v14.png) +* Open the **.csproj** file to make sure the package reference is updated: + + ```xml + + + + ``` diff --git a/16/umbraco-workflow/upgrading/version-specific.md b/16/umbraco-workflow/upgrading/version-specific.md new file mode 100644 index 00000000000..5a47bbb9f4f --- /dev/null +++ b/16/umbraco-workflow/upgrading/version-specific.md @@ -0,0 +1,43 @@ +--- +description: >- + Version specific documentation for upgrading to new major versions of Umbraco + Workflow. +--- + +# Version Specific Upgrade Notes + +This page covers specific upgrade documentation for when migrating to Umbraco Workflow version 14. + +{% hint style="info" %} +If you are upgrading to a new minor or patch version, you can find information about the breaking changes in the [Release Notes](../release-notes.md) article. +{% endhint %} + +## Version Specific Upgrade Notes History + +Version 14 of Umbraco Workflow has a minimum dependency on Umbraco CMS core of `14.1.0`. It runs on .NET 8. + +#### **Breaking changes** + +Version 14 contains a number of breaking changes, primarily due to the new backoffice introduced in Umbraco 14. The details are listed here: + +#### **Behaviour** + +* A new management API has been introduced at `umbraco/workflow/management/api` + +#### Dependencies + +* Umbraco CMS dependency was updated to `14.1.0` + +#### **Code** + +Workflow 14 includes a non-trivial number of breaking code changes, primarily related to namespace changes. The majority of these related to removing the `Implement` namespace for services, and moving appropriate models to `Umbraco.Workflow.Core.ViewModels` or `Umbraco.Workflow.Core.Interfaces`. + +* The serialization library has been changed from `Newtonsoft.Json` to `System.Text.Json`. +* Approval group identifiers changes from int to Guid. +* Workflow instance author identifier changes from int to Guid. +* Workflow task indentifiers for approving user, assigned user and actioning user change from int to Guid. +* Services return `Attempt` or `Attempt`, in line with similar changes in the CMS. + +## Legacy version specific upgrade notes + +You can find the version specific upgrade notes for versions out of support in the [Legacy documentation on GitHub](https://github.com/umbraco/UmbracoDocs/tree/umbraco-eol-versions). diff --git a/16/umbraco-workflow/workflow-section/active-workflows.md b/16/umbraco-workflow/workflow-section/active-workflows.md new file mode 100644 index 00000000000..ebecbdf4854 --- /dev/null +++ b/16/umbraco-workflow/workflow-section/active-workflows.md @@ -0,0 +1,22 @@ +# Active Workflows + +The Active Workflows view in the **Workflow** section provides an administrator view of the active Workflows. It displays a table containing the following details: + +* Page name/Node with the Language variant. +* Type of Publish. +* Date the workflow was requested on. +* Comment describing the changes. + +![Active Workflows](../../../10/umbraco-workflow/images/active-workflows-section.png) + +You can also **Filter** the records based on the Node, Requested by, Created date, Completed date, Page Language, Workflow Type, and Workflow Status. + +![Workflow history Filters](../images/history-filter-v14.png) + +Additionally, you can adjust the total number of records displayed on a page. + +![Workflow history PageSize](../images/content-reviews-pagesize-v14.png) + +The **Detail** button at the end of the record displays an overlay with content similar to the [Active workflow](../getting-started/workflow-content-app.md#active-workflow) sub-section. + +![Details overlay](../getting-started/images/Active-Workflow-detailed-info-v14.png) diff --git a/16/umbraco-workflow/workflow-section/approval-groups.md b/16/umbraco-workflow/workflow-section/approval-groups.md new file mode 100644 index 00000000000..3edb18124ce --- /dev/null +++ b/16/umbraco-workflow/workflow-section/approval-groups.md @@ -0,0 +1,98 @@ +# Approval Groups + +The **Approval groups** view in the **Workflow** section lists the active groups name, group members, their permissions, and a quick link to email the group. + +![Approval groups](../getting-started/images/approval-groups-roles-v14.png) + +To add an approval group, follow these steps: + +1. Go to the **Workflow** section. +2. Click on **Approval groups**. +3. Click **Create**. +4. Enter a **Name** for the Approval Group. For example: Danish Editors. +5. Enter the **Group Email** address in the **Settings** section to which the notifications will be sent. +6. Select the **Group Language** from the drop-down list in the **Settings** section. +7. Click **Save**. + + ![Create Approval Group](../images/Create-approval-group-v14.png) + +{% hint style="info" %} +You can create a total of 5 groups on unlicensed installations. The paid license removes this restriction. +{% endhint %} + +You can search for a specific group using the Search bar. Select a group from the list to edit its Settings, Roles, Members, and view the group's History. + +## Approval Groups Settings + +The **Settings** tab consists of the following fields: + +* **Group Email:** Workflow notifications are sent to a generic inbox (a group's email address) rather than the individual group members. +* **Group Language:** Select a language variant for the email. +* **Workflow Activity:** Provides a chart displaying an overview of the workflow activity such as approved, cancelled, rejected, or pending approvals for the current group. + +![Approval group Settings](../images/Approval-group-settings-v14.png) + +## Members + +The **Members** tab manages the membership for the given user group. Add members to approval groups to determine which member will be responsible for approving content changes. Group Members can be explicitly added to the group or can inherit group membership from an existing Umbraco group. Ideally, group members are set explicitly to ensure changes made to Umbraco groups do not cause unexpected changes to workflow permissions. + +![Approval group Members](../images/approval-group-members-v14.png) + +To add a Group member, follow these steps: + +1. Go to the **Workflow** section. +2. Click on **Approval groups**. +3. Select a group from the list to edit its Members. +4. Go to the **Members** tab. +5. Click **Choose** in the **Group members** section. +6. Select the **Users** you want to add to the approval group. + + ![Add group Members](../images/add-group-member-v14.png) +7. Click **Submit**. +8. Click **Save**. + +To remove a Group member, click **Remove**. + +To inherit an existing Umbraco group membership, follow these steps: + +1. Go to the **Workflow** section. +2. Click on **Approval groups**. +3. Select a group from the list to edit its Members. +4. Go to the **Members** tab. +5. Click **Choose** in the **Inherited group membership** section. +6. Select the **User groups** you want to add to the approval group. + + ![Inherited group membership](../images/Inherited-group-membership-v14.png) +7. Click **Submit**. +8. Click **Save**. + +To remove a Group membership, click **Remove**. + +## Roles + +The **Roles** tab provides an overview of the current workflow roles for the Group: + +* **Node-based approvals**: This workflow applies only to the specified node. +* **Document-type approvals**: This workflow applies to all the nodes of a given Document Type. + +You can set these **Roles** in the Workflow **Settings** section. For more information, see the [Workflow Settings](workflow-settings.md) article. + +![Approval group Roles](../images/approval-groups-role-v14.png) + +## History + +The History tab provides an overview of the workflow activity for the current group. It displays a table containing the following details: + +* Page name with the Language variant +* Type of Publish +* Workflow requested by +* Date the workflow was requested on +* Comment describing the changes + +![Approval group history](../images/approval-group-history-v14.png) + +You can also **Filter** the records based on the Document Type, Requested by, Created date, Completed date, Page Language, Workflow Type, and Workflow Status. Additionally, you can adjust the total number of records displayed on a page. + +The **Detail** button at the end of the record displays an overlay with content similar to the [Active workflow](../getting-started/workflow-content-app.md#active-workflow) sub-section. + +![Details overlay](../getting-started/images/Workflow-Content-app-Details-overlay-v14.png) diff --git a/16/umbraco-workflow/workflow-section/content-reviews.md b/16/umbraco-workflow/workflow-section/content-reviews.md new file mode 100644 index 00000000000..493bc59c6f7 --- /dev/null +++ b/16/umbraco-workflow/workflow-section/content-reviews.md @@ -0,0 +1,158 @@ +# Content Reviews + +Content reviews is a tool that allows content editors to keep their content up-to-date. **Content reviews** adds a new dashboard to the **Workflow** section. By default, Content reviews are disabled and can be enabled from **Content reviews Settings** in the **Workflow** section. + +![Enable Content Reviews](../images/Enable-content-reviews-v14.png) + +## Video overview + +{% embed url="https://youtu.be/mnSL7nrn10o" %} +Watch this video to learn how to use the Content Review feature in Umbraco Workflow +{% endembed %} + +## Content Reviews Dashboard + +The Content reviews Dashboard provides an overview of the expired content. The dashboard displays a table containing the following details: + +* Page name/Node with the Language variant +* Next review due date +* Last reviewed date +* Review period in days +* Review group + +![Content Reviews Dashboard](../images/Content-review-dashboard-v14.png) + +Selecting a content node takes you to the content node in the **Content** section where you can see the Content review banner. The Content review banner is displayed only when the node has passed its review date. Also, the review banner is displayed only to users assigned as reviewers for the node. For more information, see the [Content Reviews Permissions](content-reviews.md#content-review-permissions) section + +![Content Review Message Banner](../images/content-review-message-banner-v14.png) + +Clicking on **Mark as reviewed** allows the review group member to mark the content as reviewed. Optionally, the review group member can also set the next review date on the content node. The next review date must fall inside the review period set in the **Content Reviews Settings**. + +![Content Review Date](../images/content-review-date-v14.png) + +You can also **Filter** the records based on the Document Type, Review Group, Next review due date, Last reviewed date, and Expired review Status. + +![Content Reviews Filters](../images/content-reviews-filter-v14.png) + +Additionally, you can adjust the total number of records displayed on a page. + +![Content Reviews PageSize](../images/content-reviews-pagesize-v14.png) + +## Content Reviews Settings + +The Content reviews Settings tab provides a range of settings for configuring email notifications, review period days, reminder days, and so on. Using Content reviews, all content has a default review period. + +### General Settings + +You can configure the **General** Settings from the **Content reviews** tab in the **Workflow** section. The following settings are available: + +![General settings](../images/content-reviews-general-settings-v14.png) + +* **Enable content reviews** - Enable this setting if you wish to remind users to review their content. By default, this option is disabled. +* **Send notifications** - Enable this setting to send email notification to approval groups when content requires review. +* **Treat saving as a review?** - Enable this setting to reset the review date when content is saved. Saving a content node recalculates the review date, using the review period assigned to the content node, its Document Type, or the default Review period value. If disabled, content must be explicitly reviewed via the review banner displayed on the content item. +* **Review period (days)** - The default number of days between content reviews. +* **Reminder threshold (days)** - Determines how many days prior to the review date the Workflow should notify editors of required reviews. By default, the number of days is set to 1. + +### Content Review Permissions + +You can configure specific review groups to review designated content nodes or Document Types. The review group responsible for reviewing content is determined by the workflow configuration. This means a site with workflow already configured can leverage the existing permissions model for assigning content review responsibilities. By default, content reviews are assigned to the approval group defined in the first stage of the workflow. + +Content review permissions can be set at the node or Document Type level, both of which take precedence over any existing Workflow permissions. Permissions are assigned to user roles or groups within each workflow stage. For example: + +* Internal Reviewers: Users assigned to roles like *Editors* or *Content Managers* may have permissions to review content during the Internal Review stage. They ensure content quality, compliance with standards, and provide feedback for improvements before the content is published. +* External Reviewers: External reviewers are users who are invited to participate in the content review process but do not have Backoffice access. Their main role is to provide feedback or suggest changes based on their expertise or stake in the content being published. This feedback is not managed by Workflow. + +![Content review permissions](../images/Content-review-permissions-v13.png) + +The current permissions for a content node are displayed in the **Workflow** content app on the **Configuration** tab. + +![Workflow Content App - Configuration tab](../getting-started/images/content-approval-flow-v14.png) + +### Content Item and Document Type Reviews + +You can configure content reviews for individual content nodes or for all nodes of a given Document Type. For both Content Item and Document Type Reviews, the following settings are available: + +* **Language** - Allows you to specify which language version of the content is being reviewed. +* **Exclude from review** - Enable this setting to ignore the specific content node (or all content nodes of this Document Type) when determining nodes to review. +* **Review period (days)** - The review period in days between required reviews. +* **Review group** - The group responsible for reviewing the content node. Can contain more than one group. +* **External reviewers** - Assign email addresses for reviewers without CMS access. Feedback from external reviewers is not managed by Workflow. + +{% hint style="info" %} +When reviews are enabled or any changes to content review settings are saved, Workflow determines the review status. It assesses all the content needing review and provides this data in the Content reviews Dashboard. For large sites, or on the first run, this may take a few seconds to complete. +{% endhint %} + +#### Content Item Reviews + +To add a content item review, follow these steps: + +1. Go to the **Workflow** section. +2. Go to the **Settings** tab in the **Content reviews** menu. +3. Click **Add** in the **Content item reviews** section. + + ![Content Item Reviews](../images/content-item-reviews-v14.png) +4. Select **Content node** to add to the Content item reviews section. + + ![Select Content Node](../images/content-item-reviews-select-content-v14.png) +5. Select **Choose**. +6. Select the **Language** from the drop-down. +7. *[Optional]* Enable **Exclude from Review** if you wish to exclude this content node from content review. If you enable this setting, skip to step 12. +8. Enter the **Review period** in days. +9. Click **Choose** to add the **Review Group**. +10. Select an **approval group**. +11. Select **Submit**. +12. *[Optional]* Enter a user in the **External reviewers** field. For example: `john.doe@workflow.com`. + + ![Edit Content Item Review Settings](../images/Content-review-permissions-v14.png) +13. Click Submit. +14. Click **Save**. + +To Edit a content item review, click on the Content item and update the settings as per your requirement. + +To remove a content item review, click **Remove**. + +#### Document Type Reviews + +To add a Document Type review, follow these steps: + +1. Go to the **Workflow** section. +2. Go to the **Settings** tab in **Content reviews**. +3. Click **Add** in the **Document-type reviews** section. + + ![Document Type reviews](../images/document-type-reviews-v14.png) +4. Select **Content type** to add to the Document-type reviews section. + + ![Select Content Type](../images/document-type-reviews-select-content-v14.png) + +5. Select **Choose** +6. Select the **Language** from the drop-down. +7. *[Optional*] Enable **Exclude from Review** if you wish to exclude this Document-type from content review. If you enable this setting, skip to step 12. +8. Enter the **Review period** in days. +9. Click **Choose** to add the **Review Group**. +10. Select an **approval group**. +11. Click Submit. +12. *[Optional]* Enter a user in the **External reviewers** field. For example: `john.doe@workflow.com`. + + ![Add Document Type Review Settings](../images/document-type-review-settings-v13.png) +13. Click Submit. +14. Click **Save Settings**. + +To Edit a Document-type review, click **Edit** and update the settings as per your requirement. + +To remove a Document-type review, click **Remove**. + +## Content Review Notifications + +Content review notifications use the email template available at `~/Views/Partials/WorkflowEmails/ContentReviews.cshtml`, which can be customized as required. For example to add a corporate branding or send customized messages. + +To add templates for other languages: + +1. Go to the `~/Views/Partials/WorkflowEmails/` folder. +2. Copy the required template and paste it into the same folder. +3. Append the culture code to the file name prefixed with an underscore. + +For example: + +* **Default approval request template:** `~/Views/Partials/WorkflowEmails/ContentReviews.cshtml` +* **Danish approval request template:** `~/Views/Partials/WorkflowEmails/ContentReviews_da-DK.cshtml` diff --git a/16/umbraco-workflow/workflow-section/workflow-history.md b/16/umbraco-workflow/workflow-section/workflow-history.md new file mode 100644 index 00000000000..a1cd299c79a --- /dev/null +++ b/16/umbraco-workflow/workflow-section/workflow-history.md @@ -0,0 +1,25 @@ +# Workflow History + +The Umbraco Workflow History provides a chronological audit trail of workflow activity for all the nodes. + +It displays a table containing the following details: + +* Page name/Node with the Language variant. +* Type of Publish. +* Editor/Original author requesting the workflow. +* Date the workflow was requested on. +* Comment describing the changes. + +![Workflow history](../images/workflow-history-v14.png) + +You can also **Filter** the records based on the Document Type, Requested by, Created date, Completed date, Page Language, Workflow Type, and Workflow Status. + +![Workflow history Filters](../images/history-filter-v14.png) + +Additionally, you can adjust the total number of records displayed on a page. + +![Workflow history PageSize](../images/content-reviews-pagesize-v14.png) + +The **Detail** button at the end of the record displays an overlay with content similar to the [Active workflow](active-workflows.md) sub-section. + +![Details overlay](../getting-started/images/Workflow-Content-app-Details-overlay-v14.png) diff --git a/16/umbraco-workflow/workflow-section/workflow-section-dashboard.md b/16/umbraco-workflow/workflow-section/workflow-section-dashboard.md new file mode 100644 index 00000000000..ab298d114a9 --- /dev/null +++ b/16/umbraco-workflow/workflow-section/workflow-section-dashboard.md @@ -0,0 +1,5 @@ +# Workflow Section + +The Workflow section provides an administrator view Workflow Dashboard. It displays a chart of recent workflow activity, chart of content review activity, licensing details, and any relevant upgrade-related messages. You can also view the workflow and content review activity chart for the specified range of days. + +![Workflow section](../images/Workflow-Admin-Dashboard-v14.png) diff --git a/16/umbraco-workflow/workflow-section/workflow-settings.md b/16/umbraco-workflow/workflow-section/workflow-settings.md new file mode 100644 index 00000000000..0d8660b8407 --- /dev/null +++ b/16/umbraco-workflow/workflow-section/workflow-settings.md @@ -0,0 +1,235 @@ +# Workflow Settings + +When working with Umbraco Workflow, you can handle the workflow settings directly in the Backoffice from the **Workflow** section. You can configure the following from the Workflow Settings section: + +* [General settings](workflow-settings.md#general-settings) +* [New node approval flow](workflow-settings.md#new-node-approval-flow) +* [Document Type approval flows](workflow-settings.md#document-type-approval-flows) +* [Exclude nodes](workflow-settings.md#exclude-nodes) +* [Notification Settings](workflow-settings.md#notifications-settings) +* [Email templates](workflow-settings.md#email-templates) + +![Workflow settings](../images/workflow-settings-v14.png) + +## General Settings + +You can configure the **General** Settings from the **Settings** menu in the **Workflow** section. The following settings are available: + +![General settings](../images/workflow-settings-v14.png) + +* **Flow type** - Determines the approval flow progress. These options manage how the Change Author is included in the workflow: + * **Explicit** - All steps of the workflow must be completed and all users will be notified of tasks (including the Change Author). + * **Implicit** - All steps where the original Change Author is _not_ a member of the group must be completed. Steps where the original Change Author is a member of the approving group will be completed automatically and noted in the workflow history as not required. + * **Exclude** - Similar to Explicit. All steps must be completed but the original Change Author is not included in the notifications or shown in the dashboard tasks. +* **Approval threshold** - Sets the global approval threshold to One, Most or All: + * **One** - Pending task requires approval from any member of the assigned approval group. This is the default behavior for all installations (trial and licensed). + * **Most** - Pending task requires an absolute majority of group members. For example, a group with three members requires two approvals and a group with four members requires three approvals. + * **All** - Pending task requires approval from all group members. +* **Rejection resets approvals** - When true, and the approval threshold is Most or All, rejecting a task resets the previous approvals for the workflow stage. +* **Allow configuring approval threshold** - Enables setting the approval threshold for any stage of a workflow (on a content node or Document Type). +* **Lock active content** - Determines how the content in a workflow should be managed. Set to `true` or `false` depending on whether the approval group responsible for the active workflow step should make modifications to the content. Content is locked after the first approval in the workflow - until then, the content can be edited as normal. +* **Administrators can edit** - Set to true to allow administrators to edit content at any stage of the workflow, ensuring flexibility and control over the content approval process. +* **Mandatory comments** - Set to true to require comments when approving workflows. Comments are always required when submitting changes for approval, and are always optional for admin users. +* **Allow attachments** - Provide an attachment (such as a supporting document or enable referencing a media item) when initiating a workflow. This feature is useful when a workflow requires supporting documentation. +* **Allow scheduling** - Provides an option to select a scheduled date when initiating a workflow. +* **Use workflow for unpublish** - Determines if unpublish actions require workflow approval. Set to true to display the **Action** option when submitting the content for approval. +* **Extend permissions** - Determines if Umbraco Workflow should extend or replace the users' save and publish permissions. The default behavior is to replace the users' permissions. + +### New node approval flow + +All new nodes use this workflow for initial publishing. You can add, edit, or remove an approval group to/from the workflow. + +To add an approval group to the workflow: + +1. Go to the **Workflow** section. +2. Go to the **General** tab in the **Settings** menu. +3. Click **Choose** in the **New node approval flow** section. + + ![New Node Approval Flow](../images/new-node-approval-flow-v14.png) + +4. Select an **approval group** to add to the workflow. + + ![Add Workflow Approval Groups](../images/add-approval-flow-v14.png) +5. Click **Submit**. +6. Click **Save**. + +When you click on the approval group, you are presented with different configuration options for that group. For more information on the approval group settings, see the [Settings](approval-groups.md#approval-groups-settings) section in the [Approval Groups](approval-groups.md) article. + +To remove an approval group, click **Remove**. + +### Document type approval flows + +Configure default workflows that should be applied to all content nodes of the selected Document Type. This feature requires a license. + +To add a Document type approval flow: + +1. Go to the **Workflow** section. +2. Go to the **General** tab in the **Settings** menu. +3. Click **Add document type** in the **Document type approval flows** section. + + ![Document Type Approval Flows](../images/doc-type-approval-flows-v14.png) +4. Select a **Document Type** from the drop-down list. +5. Select a **Language** from the drop-down list. +6. Click **Choose** in the **Approval groups**. +7. Click **Submit**. +8. Click **Add condition** to add a condition to the workflow process. + + ![Configure Document Type Approval Flow Settings](../images/add-doc-type-approval-flows-settings-v14.png) +9. Click **Submit**. +10. Click **Save**. + +To edit a Document type approval flow: + +1. Go to the **Workflow** section. +2. Go to the **General** tab in the **Settings** menu. +3. Click the content node in the **Document type approval flows** section. + + ![Edit Document Type Approval Flow](../images/edit-doc-type-approval-flows-v14.png) +4. **Add**, **Edit**, or **Remove** approval groups from the current workflow. +5. Click **Add condition** to add or edit a condition to the workflow process. + + ![Configure Document Type Approval Flow](../images/edit-doc-type-approval-flows-settings-v14.png) +6. Click **Submit**. +7. Click **Save**. + +### Exclude nodes + +Nodes and their descendants selected here are excluded from the workflow process and will be published as per the configured Umbraco user permissions. This feature requires a license. + +To exclude a node from the workflow process: + +1. Go to the **Workflow** section. +2. Go to the **General** tab in the **Settings** menu. +3. Click **Choose** in the **Exclude nodes** section. + + ![Exclude Nodes](../images/exclude-nodes-v14.png) +4. Select the **Content node** from the Content tree. + + ![Select Content Node](../images/select-content-from-tree-v14.png) +5. Click **Choose**. +6. Click **Save**. + +## Notifications Settings + +Umbraco Workflow uses Notifications to allow you to configure email notifications for all workflow activities for the backoffice. + +From the **Settings** view in the **Workflow** section, the **Notifications** tab provides access to the following: + +* **Send notifications:** If you wish to send email notifications to approval groups, you can enable it here. If your users are active in the backoffice, email notifications might not be required. +* **Workflow email:** Provide a sender address for email notifications. This is a mandatory field. +* **Reminder delay (days):** Set a delay in days for sending reminder emails for outstanding workflow processes. Set to 0 to disable reminder emails. +* **Edit site URL:** The URL for the editing environment (including schema - http[s]). This is a mandatory field. +* **Site URL:** The URL for the public website (including schema - http[s]). This is a mandatory field. +* [**Email templates**](workflow-settings.md#email-templates)**:** Configure which users receive emails for which workflow actions and modify the templates for those emails. + + ![Notifications tab in the Workflow Section](../images/Notifications-tab-v14.png) + +## Notifications Overview + +Notification emails use HTML templates which render information from the `HtmlEmailModel` type which lives in the `Umbraco.Workflow.Core.Models.Email` namespace. While it is possible to modify the email templates from the backoffice, we recommend making changes via an Integrated Development Environment (IDE) of your choice. + +The `HtmlEmailModel` contains the following fields: + +| Fields | Data Type | Description | +| ------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| WorkflowType | WorkflowType | An `enum` value containing either 1 or 2 for Publish and Unpublish respectively. | +| ScheduledDate | DateTime | If a scheduled date exists for the workflow, it is found here. | +| Summary | IHtmlString | A pre-generated representation of the current workflow state. | +| CurrentTask | WorkflowTaskViewModel | The view model data for the current workflow task. Contains a lot of useful data, best explored via Intellisense. | +| Instance | WorkflowInstanceViewModel | The view model data for the current workflow. Best explored via Intellisense. | + +The `HtmlEmailBase` contains the following fields: + +| Fields | Data Type | Description | +| ------------ | -------------- | ---------------------------------------------------------------------------------------------------- | +| SiteUrl | string | The public URL of your site. | +| NodeName | string | The name of the node from the current workflow. | +| Type | string | The workflow type including the scheduled date (if exists). | +| EmailType | EmailType | An `enum` value representing the current email type that relates directly to the workflow task type. | +| To | EmailUserModel | The model defining the receiver of the email. | +| Email | string | The user's email address or a group address (if a group email is being sent). | +| Name | Name | The user's name. | +| Language | string | The user's language. | +| Id | int | The user's ID or group ID (when sending to a group email address). | +| IsGroupEmail | bool | Is the email being sent to a generic group email address? | + +Umbraco Workflow provides **Settings** for determining who receives emails at which stages of a workflow. While these are set to default values during installation, it is recommended to update your Notifications Settings to better suit your installation needs. Emails can be sent to: + +* **All**: All the participants in all workflow stages (previous and current). +* **Admin**: The admin user. +* **Author**: The user who initiated the workflow. +* **Group**: All members of the group assigned to the current task. + +{% hint style="info" %} +Duplicate users are removed from email notifications. +{% endhint %} + +By default, all emails are sent to the **Group**. This might not always be an ideal situation. For example: cancelled workflows would be best sent to the **Author** only, likewise with rejected. + +It might be useful to notify **All** the participants of completed workflows but even this may be excessive. Depending on your website, you can adjust the best configuration. + +## Reminders Overview + +Umbraco Workflow uses a reminder email system to prompt editors to complete the pending workflows. Reminders are sent using Umbraco's internal task scheduler, every 24 hours after an initial delay. For example, setting the **Reminder delay (days)** value to 2 in the Workflow **Settings** section will allow pending workflows to sit for 2 days. After that reminder emails will be sent every 24 hours to all members of the group assigned to the pending workflow task. + +The emails use a similar model to the notification emails, also inheriting from `HtmlEmailBase`. In addition to the inherited fields, `HtmlReminderEmailModel` includes: + +| Fields | Data Type | Description | +| ------------ | --------- | --------------------------------------------------------------------- | +| OverdueTasks | IList | A list containing all the overdue tasks assigned to the current user. | +| TaskCount | int | The count of overdue tasks assigned to the current user. | + +## Email Templates + +All email templates are fully localized where translations exist. You can edit the email templates in the Backoffice or in your IDE. By default, Umbraco Workflow's email templates are available in the default language. + +## Creating an Email Template + +If you wish to have one or more email templates for different languages, you will need to place all the email templates into the `~/Views/Partials/workflow/email/` folder. + +To add templates for other languages: + +1. Go to the `~/Views/Partials/workflow/email` folder. +2. Copy the required template and paste it into the same folder. +3. Append the culture code to the file name prefixed with an underscore. + +For example: + +* **Default approval request template:** `~/Views/Partials/workflow/email/ApprovalRequest.cshtml` +* **Danish approval request template:** `~/Views/Partials/workflow/email/ApprovalRequest_da-DK.cshtml` + +## Sample Email Template + +Below is an example of the `ApprovalRequest.cshtml` email template from the `~/Views/Partials/workflow/email/` folder: + +```csharp +@model Umbraco.Workflow.Core.Models.Email.HtmlEmailModel + +@* + Refer to the documentation for Email templates for a full rundown on the available fields + or (better option), edit the template in Visual Studio where Intellisense will save you +*@ + + + + + + + Workflow: Approval request + + + + + +
+

Hello @Model.To.Name,

+

Please review the following page for @Model.Type.ToLower() approval:

+ +
+ + +```