diff --git a/14/umbraco-deploy/.gitbook.yaml b/14/umbraco-deploy/.gitbook.yaml new file mode 100644 index 00000000000..49dec298ba5 --- /dev/null +++ b/14/umbraco-deploy/.gitbook.yaml @@ -0,0 +1,10 @@ +root: ./ + +​structure: + readme: README.md + summary: SUMMARY.md + +redirects: + deploy-settings: getting-started/deploy-settings.md + extending: extending/extending.md + handling-cache-refresher-notifications: extending/handling-cache-refresher-notifications.md diff --git a/14/umbraco-deploy/.gitbook/assets/code_cursor copy.png b/14/umbraco-deploy/.gitbook/assets/code_cursor copy.png new file mode 100644 index 00000000000..652baf5ff5f Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/code_cursor copy.png differ diff --git a/14/umbraco-deploy/.gitbook/assets/code_cursor.png b/14/umbraco-deploy/.gitbook/assets/code_cursor.png new file mode 100644 index 00000000000..652baf5ff5f Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/code_cursor.png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (1).png b/14/umbraco-deploy/.gitbook/assets/image (1).png new file mode 100644 index 00000000000..39e8a3bba96 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (1).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (10).png b/14/umbraco-deploy/.gitbook/assets/image (10).png new file mode 100644 index 00000000000..0559a8b337d Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (10).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (11).png b/14/umbraco-deploy/.gitbook/assets/image (11).png new file mode 100644 index 00000000000..10c425d06e0 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (11).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (12).png b/14/umbraco-deploy/.gitbook/assets/image (12).png new file mode 100644 index 00000000000..2ab8bdfeca1 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (12).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (13).png b/14/umbraco-deploy/.gitbook/assets/image (13).png new file mode 100644 index 00000000000..a310a023860 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (13).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (14).png b/14/umbraco-deploy/.gitbook/assets/image (14).png new file mode 100644 index 00000000000..dd18b71076d Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (14).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (15).png b/14/umbraco-deploy/.gitbook/assets/image (15).png new file mode 100644 index 00000000000..24eb0be1403 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (15).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (16).png b/14/umbraco-deploy/.gitbook/assets/image (16).png new file mode 100644 index 00000000000..24eb0be1403 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (16).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (17).png b/14/umbraco-deploy/.gitbook/assets/image (17).png new file mode 100644 index 00000000000..24eb0be1403 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (17).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (2) (1).png b/14/umbraco-deploy/.gitbook/assets/image (2) (1).png new file mode 100644 index 00000000000..e2e61fef550 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (2) (1).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (2).png b/14/umbraco-deploy/.gitbook/assets/image (2).png new file mode 100644 index 00000000000..0bc92ab5012 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (2).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (3) (1).png b/14/umbraco-deploy/.gitbook/assets/image (3) (1).png new file mode 100644 index 00000000000..99c55b6c5db Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (3) (1).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (3).png b/14/umbraco-deploy/.gitbook/assets/image (3).png new file mode 100644 index 00000000000..e7b113727c6 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (3).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (4).png b/14/umbraco-deploy/.gitbook/assets/image (4).png new file mode 100644 index 00000000000..bfc79bbd110 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (4).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (5) (1).png b/14/umbraco-deploy/.gitbook/assets/image (5) (1).png new file mode 100644 index 00000000000..8e8df467a42 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (5) (1).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (5).png b/14/umbraco-deploy/.gitbook/assets/image (5).png new file mode 100644 index 00000000000..0a3ea1bed36 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (5).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (6).png b/14/umbraco-deploy/.gitbook/assets/image (6).png new file mode 100644 index 00000000000..77595f7bdfe Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (6).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (7) (1).png b/14/umbraco-deploy/.gitbook/assets/image (7) (1).png new file mode 100644 index 00000000000..e9c3169ab1b Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (7) (1).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (7).png b/14/umbraco-deploy/.gitbook/assets/image (7).png new file mode 100644 index 00000000000..b787838c11e Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (7).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (8) (1).png b/14/umbraco-deploy/.gitbook/assets/image (8) (1).png new file mode 100644 index 00000000000..ddf5beadede Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (8) (1).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (8).png b/14/umbraco-deploy/.gitbook/assets/image (8).png new file mode 100644 index 00000000000..e4a69d61a09 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (8).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (9) (1).png b/14/umbraco-deploy/.gitbook/assets/image (9) (1).png new file mode 100644 index 00000000000..2aec97a8175 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (9) (1).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image (9).png b/14/umbraco-deploy/.gitbook/assets/image (9).png new file mode 100644 index 00000000000..af4dd7e446b Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image (9).png differ diff --git a/14/umbraco-deploy/.gitbook/assets/image.png b/14/umbraco-deploy/.gitbook/assets/image.png new file mode 100644 index 00000000000..7aa0b73eb56 Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/image.png differ diff --git a/14/umbraco-deploy/.gitbook/assets/lightbulb.png b/14/umbraco-deploy/.gitbook/assets/lightbulb.png new file mode 100644 index 00000000000..ea184f80f6d Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/lightbulb.png differ diff --git a/14/umbraco-deploy/.gitbook/assets/update.png b/14/umbraco-deploy/.gitbook/assets/update.png new file mode 100644 index 00000000000..7c182d2364b Binary files /dev/null and b/14/umbraco-deploy/.gitbook/assets/update.png differ diff --git a/14/umbraco-deploy/README.md b/14/umbraco-deploy/README.md new file mode 100644 index 00000000000..ee929bccdfd --- /dev/null +++ b/14/umbraco-deploy/README.md @@ -0,0 +1,29 @@ +--- +description: Documentation on how to work with Umbraco Deploy. +--- + +# Umbraco Deploy Documentation + +Umbraco Deploy is a deployment tool that helps you with the process of transferring code and data between multiple environments. Deploy can be configured for many different setups and is great for both small setups as well as large and more complex infrastructures. + +
Set up Umbraco DeployLearn how you can set up Umbraco Deploy on new and existing Umbraco projects.update.pnginstall-configure.md
Deployment workflow inLearn about how the Deployment workflow in Umbraco Deploy work.lightbulb.pngdeployment-workflow
UpgradingLearn how you can upgrade Umbraco Deploy.code_cursor.pngupgrades
+ +{% content-ref url="getting-started/deploy-settings.md" %} +[deploy-settings.md](getting-started/deploy-settings.md) +{% endcontent-ref %} + +{% content-ref url="extending/extending.md" %} +[extending.md](extending/extending.md) +{% endcontent-ref %} + +{% content-ref url="troubleshooting.md" %} +[troubleshooting.md](troubleshooting.md) +{% endcontent-ref %} + +Umbraco Deploy is also the engine that runs behind the scenes on [Umbraco Cloud](https://docs.umbraco.com/umbraco-cloud/). Here it takes care of all the deployment processes of both code, schema and content on projects. + +With Umbraco Deploy you get to use the Umbraco Cloud Deployment technology outside of Umbraco Cloud to ease deployment between multiple Umbraco environments. This is done by connecting external hosted Umbraco projects with a local instance of your Umbraco website. + +In the Umbraco Deploy documentation can read all about how to set up and work with Umbraco Deploy. + +You can find articles about how to set up Umbraco Deploy on a new or an existing website, and articles about the deployment workflow. diff --git a/14/umbraco-deploy/SUMMARY.md b/14/umbraco-deploy/SUMMARY.md new file mode 100644 index 00000000000..b3fdf572860 --- /dev/null +++ b/14/umbraco-deploy/SUMMARY.md @@ -0,0 +1,44 @@ +# Table of contents + +* [Umbraco Deploy Documentation](README.md) +* [Legacy Documentation](legacy-documentation.md) +* [Release notes](release-notes.md) +* [Troubleshooting](troubleshooting.md) + +## Installation + +* [Installing Umbraco Deploy](installation/install-configure.md) +* [Licensing](installation/the-licensing-model.md) + +## Upgrading + +* [Upgrading Umbraco Deploy](upgrades/README.md) +* [Version Specific Upgrade Details](upgrades/version-specific.md) + +## Getting Started + +* [Getting started](getting-started/get-started-with-deploy.md) +* [CI/CD Build and Deployment Pipeline](getting-started/cicd-pipeline/README.md) + * [Azure DevOps](getting-started/cicd-pipeline/ci-cd-azure-dev-ops.md) + * [GitHub Actions](getting-started/cicd-pipeline/ci-cd-github-actions.md) +* [Streamlining Local Development](getting-started/streamlining-local-development.md) +* [Configuration](getting-started/deploy-settings.md) + +## Deployment Workflow + +* [Deployment](deployment-workflow/README.md) +* [Transferring Content, Media and Forms](deployment-workflow/content-transfer.md) +* [Import and Export](deployment-workflow/import-export.md) + * [Import and Export with Migrations](deployment-workflow/import-with-migrations.md) + * [Import and Export from version 7](deployment-workflow/import-export-v7.md) + * [Import on startup](deployment-workflow/import-on-startup.md) +* [Deploying Changes](deployment-workflow/deploying-changes.md) +* [Deploying deletions](deployment-workflow/deploying-deletions.md) +* [Restoring content](deployment-workflow/restoring-content/README.md) + * [Partial Restores](deployment-workflow/restoring-content/partial-restore.md) +* [Deploy Dashboard](deployment-workflow/deploy-dashboard.md) + +## Extending + +* [Extend Deploy](extending/extending.md) +* [Handling Cache Refresher Notifications](extending/handling-cache-refresher-notifications.md) diff --git a/14/umbraco-deploy/deployment-workflow/README.md b/14/umbraco-deploy/deployment-workflow/README.md new file mode 100644 index 00000000000..ad396987b7d --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/README.md @@ -0,0 +1,76 @@ +--- +description: A description of the proper workflow when working with Umbraco Deploy +--- + +# Deployment + +Umbraco Deploy uses a deployment model that relies on Git and Umbraco Deploy core technology to move your changes from one environment to another. Umbraco Deploy uses a classic "left to right" deployment model, meaning that changes are first made in the Development or local environment and then deployed to the production environment. + +{% hint style="info" %} +If your project contains a Staging environment, deployments will be made from Development to Staging and then from Staging to Live. +{% endhint %} + +![Left to right model](images/left-to-right.png) + +## Deployment Approach + +Umbraco Deploy uses a two-part deployment approach where we keep meta data (Document types, templates, etc) and content (Content nodes and Media) as separate parts of a deployment. In order to be able to distinguish between the two types of deployments we use the term _transfer_ for content and media deployments and the term _deploy_ for meta data deployments. + +In summary: + +1. Meta data such as Document Types, Templates, Forms, Views and config files are stored in a repository and are **deployed** between environments. This can be achieved using a CI/CD deployment pipeline with something like GitHub Actions or Azure DevOps. +2. Content and Media items are **not** stored in the repository. These need to be **transferred** directly from the Umbraco backoffice using the _"Queue for Transfer"_ option. Once a content editor has all the items needed for a transfer they will use the Deployment Dashboard in the Content section to transfer the items in the queue. + +### Deploying meta data + +In order to be able to transfer content and media, the source environment and the target environment needs to have the same setup - meaning they need to be completely in sync and have the same file structure. To achieve this you need to deploy your meta data changes to the target environment. + +* [Deploying from your local machine to your environments](deploying-changes.md) + +### Transfer Content and Media + +Moving your content and media between your environments is done through the Umbraco backoffice. You can transfer content from one environment to another, e.g. from local to your development environment. You also have the option to restore content and media to your local or development environment from your production or staging environment. + +* [Transfer Content and Media](content-transfer.md) +* [Restore Content and / or Media](restoring-content/) + +{% hint style="info" %} +Transferring and restoring content and media is the same whether you are working locally and transferring between two environments. +{% endhint %} + +{% embed url="https://www.youtube.com/embed/poRzuBB11pc?rel=0" %} +Umbraco Deploy - Content transfer and deploy +{% endembed %} + +### Import and Export + +Another approach for transferring content and schema between environments is to use import and export. In one environment, you can export selected content, a tree, or the whole workspace to a .zip file. There are options to include related media files, schema and code files such as templates and stylesheets. + +That .zip file can then be uploaded into a new environment, where it will be validated and then processed to update Umbraco. + +As part of the import process, we provide hooks to allow for migrations of the imported artifacts (like data types) and property data. This should allow you to migrate your Umbraco data from one Umbraco major version to a newer one. + +We recommend using the content and media backoffice transfer options for day-to-day editorial activities. Import and export is intended more for larger transfer options, project upgrades, or one-off tasks when setting up new environments. + +Read more about the [import and export feature](import-export.md). + +## Deploy Dashboard + +In Umbraco Deploy we have included a Deploy Dashboard in the Settings section of the Umbraco backoffice to make it easier to run operations like schema deployment from data files and extract schema to data files. + +When running the `extract schema to data files` operation, Umbraco Deploy will run an `echo > deploy-export` in the data folder of your project which is used to generate UDA files based on the schema in your database. + +Running the `schema deployment from data files` operation will initiate an extraction on the environment + +The extraction will end in one of two possible outcomes: + +1. `deploy-complete`: The extraction succeeded and your environment is in good shape! +2. `deploy-failed`: The extraction failed - open the deploy-failed file, to see the error message. + +It is also possible to see which version of Umbraco Deploy you are running, when the last operation was started and the status of the deployment operation. + +
Deploy Dashboard

Deploy Dashboard

+ +{% embed url="https://www.youtube.com/embed/l5qdTsIddKM?rel=0" %} +Umbraco Deploy - Content transfer and deploy +{% endembed %} diff --git a/14/umbraco-deploy/deployment-workflow/content-transfer.md b/14/umbraco-deploy/deployment-workflow/content-transfer.md new file mode 100644 index 00000000000..d3bea4c38fc --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/content-transfer.md @@ -0,0 +1,73 @@ +--- +description: How to restore content in Umbraco Deploy using the deployment dashboard +--- + +# Transferring Content, Media and Forms + +Once all code and meta data is in sync between your environments, it's time to transfer your content and media. This is done from the Umbraco Backoffice. + +Content and media transfers are flexible which means you have complete control over which content nodes and/or media items you want to transfer. You can transfer it all in one go, a few at a time or transfer only a single node. + +Transferring content will overwrite any existing nodes on the target environment - content transfers will transfer the items that you select in the "source" environment to the "target" environment exactly the same as it was in the "source". This means that if you have some content on the target environment already, this will be replaced by the new content from the source environment. + +**Important**: Content and Media transfers will only work if you've deployed all changes to your meta data before hand. Please refer to our documentation on how to deploy meta data from [Deploying Content](deploying-changes.md). + +## Step-by-step + +Let’s go through a content transfer step by step. Imagine you’ve finished working on new content for your project locally and you are ready to transfer the changes to your development site. + +You want to transfer the whole site. You start from the `Home` node and choose to transfer everything under it: + +1. Click on the ellipsis next to the `Home` node in the Content tree. +2. Choose "Do something else". +3. There you get the choice of **Queue for transfer**. + * If you’re currently editing the Home page you could also use the Actions dropdown to find **Queue for transfer**. +4. Choose if you want to include all pages under the chosen page or only transfer the chosen node. + * If you wish to transfer all your content at once, click **...** next to the Content tree where you will also find **Queue for transfer** - this will queue all your content for transfer. +5. Select the language versions that you want to queue for transfer. Only languages for which you have permission to access will be selectable. +6. Set the publish date and time if you want to change when the transferred content should be published. + + {% hint style="info" %} + By default, the content will be transferred in its current published state. So if the content is published in the current environment, the changes will be deployed and the item immediately be published in the destination. If you prefer to schedule the publishing of the changes, you can do so by selecting a publish date. + {% endhint %} +7. Click **Queue** to add the content item to the transfer queue. + +
Queue for transfer window

Queue for transfer window

+ +1. Go to the Deployment dashboard by clicking on the Content section header. + * You will be able to see which items are currently ready to be transferred - this will include both content and media that you've _queued for transfer_. +2. Confirm by clicking **Transfer toDevelopment** and monitor the progress of the transfer. + +
Transfer queue

Transfer queue

+ +If everything went well, you will see the confirmation screen saying that the transfer has succeeded. + +### Media items + +Media items are transferred the same way as content: + +1. In the Media section, Click **...** next to the items you want to transfer and choose **Queue for transfer**. + * Or click **...** next to the Media section to transfer all you media at once. +2. Go to the Deployment dashboard in the Content section to see the items you've queued for transfer and to transfer your items. + +### Umbraco Forms + +In order for Deploy to handle Forms data as content, you will need to ensure that the `transferFormsAsContent` setting in configuration is set to `true`. See details in the [Deploy Settings for Umbraco 9+](../getting-started/deploy-settings.md) article. + +Once the setting have been added to the source and target environment forms can be transferred the same way as content and media: + +1. In the Forms section, click **...** next to the items you want to transfer and choose **Queue for transfer**. + * Or click **...** next to the Forms section to transfer all your Forms at once. +2. Go to the Deployment dashboard in the Content section to see the items you've queued for transfer and to transfer your items. + +{% hint style="info" %} +This does not include entries submitted via the forms. +{% endhint %} + +## Schema Mismatches + +Sometimes a content transfer might not be possible. For example if you add a new property to the HomePage Document type and you don’t have that property in both environments, you’ll get an error with a hint on how to fix this. + +![Schema mismatch](../deployment-workflow/images/schema-mismatch.png) + +If you are seeing this type of issue when trying to transfer content, head over to our article about [Schema Mismatch errors](../troubleshooting.md), where you can read about how to resolve the issues. diff --git a/14/umbraco-deploy/deployment-workflow/deploy-dashboard.md b/14/umbraco-deploy/deployment-workflow/deploy-dashboard.md new file mode 100644 index 00000000000..2562e32c6bb --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/deploy-dashboard.md @@ -0,0 +1,83 @@ +--- +description: >- + With the Deploy Dashboard, we have made it possible to get an overview of your + Umbraco Deploy installation and perform Deploy operations. +--- + +# Deploy Dashboard + +In this article, we will show the different sections on the Deploy dashboard and how they can be used. + +## Deploy Status + +Here you can see whether the latest deployment has been completed or failed. You can see the version of Umbraco Deploy you are running, and the last time an operation was run. + +
Umbraco Deploy status

Umbraco Deploy status

+ +## Deploy Operations + +With the Deploy operations, you can run different operations in Umbraco Deploy. + +
+ +
The different Deploy operations.

The different Deploy operations.

+ +
+ +Below you can read what each operation will do when run through the dashboard. + +### Update Umbraco Schema From Data Files + +Running this operation will update the Umbraco Schema based on the information in the `.uda` files on disk. + +### Export Schema To Data Files + +Running this operation will extract the schema from Umbraco and output it to the `.uda` files on disk. + +### Clear Cached Signatures + +Running this operation will clear the cached artifact signatures from the Umbraco environment. This should not be necessary, however, it may resolve reports of schema mismatches when transferring content that has been aligned. + +### Set Cached Signatures + +This operation will set the cached artifact signatures for all entities within the Umbraco environment. Use this when signatures have been cleared and you want to ensure they are pre-generated before attempting a potentially longer restore or transfer operation. + +## Download Deploy Artifacts + +Running this operation will download a zip file with all the Deploy artifacts representing the Umbraco schema in the form of `.uda` files. + +This operation is useful if you want to move to another Umbraco instance and migrate the data with you. + +
+ +
Donwload the Deploy artifacts

Donwload the Deploy artifacts

+ +
+ +## Configuration Details + +In the Configuration details, you can see how Umbraco Deploy has been [configured](../getting-started/deploy-settings.md) on your environment. You get an overview of the Setting options, the current value(s), and notes help you understand each of the settings. Updates to the need to be applied in the `appsettings.json` file. + +

Example of Umbraco Deploy configuration.

+ +## Schema Comparison + +The Schema Comparison table shows the schema information managed by Umbraco Deploy. + +You can see a comparison between the information that is held in Umbraco and the information in the `.uda` files on disk. + +The table shows: + +* The name of the schema +* The file name +* Whether the file exists in Umbraco +* Whether the file exists +* Whether the file is up-to-date + +

Document type schema comparison

+ +You can also view details about a certain element by selecting "View Details". + +This will show the difference between entities stored in Umbraco and the `.uda` file stored on disk. + +

Showing how you can compare schema in the deploy dashboard

diff --git a/14/umbraco-deploy/deployment-workflow/deploying-changes.md b/14/umbraco-deploy/deployment-workflow/deploying-changes.md new file mode 100644 index 00000000000..ca866bae723 --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/deploying-changes.md @@ -0,0 +1,50 @@ +--- +description: "How to Deploy changes between a local machine and an environment in Umbraco Deploy using either a Git Gui or without." +--- + +# Deploying Changes + +In this article you can learn more about how to deploy your code changes and meta data from a local instance to a remote environment. + +## Deploying from local to your environments + +When you are working with your Umbraco project locally all changes you make will automatically be identified and picked up by your local Git client. + +Here's a quick step-by-step on how you deploy these changes to your environment: + +* You've cloned a site to your local machine to work on. +* You've made some changes to a Document Type. +* The corresponding `.uda` file for this Document Type is now updated with the changes - the file is located in the `/umbraco/Deploy/Revision` folder. +* You've also created a new Data Type that's used on the Document Type. This Data Type is stored as a new file in the `/umbraco/Deploy/Revision` folder as well. +* Using Git, commit those two changed files to your local repository and push them to your repository. +* A deployment kicks in and the Document Type is updated and the new Data Type you created locally is now automatically created in the remote environment as well. + +## Deploying without using a Git client + +If you don't have a Git client installed on your local machine, you can use Git or Git Bash for command-line Git operations. Run the following commands: + +``` +# Navigate to the repository folder +cd mySite +# Check status of the repository for pending changes +git status +# Add pending changes +git add -A +# Commit staged files +git commit -m "Adding updated schema changed" +# Push to the environment +git push + +# If the push is rejected you will need to pull first +git pull +# Try to push again if there were no conflicts +git push +``` + +When pulling new commits, it is a good idea to see if any of these commits contained changes to the schema (anything in `umbraco/Deploy/Revision/`). To ensure your local schema is up-to-date, you can navigate to the `umbraco/Deploy/` folder and create a deploy marker if it doesn't exist. From a command line type the following command: + +`/…mysite/umbraco/Deploy> echo > deploy` + +The local site should be running when you do this. The deploy marker will change to `deploy-progress` while updating the site and to `deploy-complete` when done. If there are any conflicts/errors you will see a `deploy-failed` marker instead, which contains an error message with a description of what went wrong. + +Another way is to use the Deploy Dashboard in the Settings section of the Umbraco backoffice. Here you can see the status of ongoing or completed deployment processes. The status will show whether an operation has been triggered and whether it is in progress, has completed or has failed. The dashboard will show the status based on the marker files on the disk, eg. `deploy-progress`. From the Deploy Dashboard it is also possible to trigger processes. Learn more about this dashboard in the [Deployment ](README.md#deploy-dashboard)article. diff --git a/14/umbraco-deploy/deployment-workflow/deploying-deletions.md b/14/umbraco-deploy/deployment-workflow/deploying-deletions.md new file mode 100644 index 00000000000..2be7c2e8cc4 --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/deploying-deletions.md @@ -0,0 +1,87 @@ +--- +description: How deleting meta data and files work in Umbraco Deploy +--- + +# Deploying deletions + +With Umbraco Deploy deletions are environment specific. This means that in order to delete something entirely from your project, you need to delete it on all environments. + +In this article you can read about the correct way of deleting files, schema and content when using Umbraco Deploy. + +When you are using Umbraco Deploy, you might have more than one environment - including a local clone of the project. These environments each have their own database. The databases will contain references to all of your content and media, as well as to all of your schema files (e.g. Document Types, Templates etc). + +The databases are environment specific. When you deploy from one environment to another, Umbraco Deploy will compare incoming schema files with references to these in the databases using both _alias_ and _GUID_. If something doesn't add up - e.g. there is a mismatch between the database references and the files deployed - you will see an error. Learn more about this in the [Troubleshooting section](../troubleshooting.md). + +The workflow described above does not pick up deletions of content and schema from the database, which is why you'll need to delete the content and/or schema on all your environments, in order to fully complete the deletion. + +The main reason Umbraco Deploy does not delete schema and content on deployments, is because it could lead to unrecoverable loss of data. Imagine that you delete a Document Type on your Development environment, and push this deletion to your production environment where you have a lot of content nodes based on the deleted Document Type. When the deployments goes through, all of those content nodes would be instantly removed with no option to roll back as the Document Type they are based on no longer exists. To avoid anyone ending up in this unfortunate situation, deletes are not automatically handled and will require an active decision from you on each environment in order to take place. + +## Example scenario + +Let's say you've deleted a Document Type on your Development environment, and now you want to deploy this deletion to the production environment. + +Before you deploy the changes, in Git it will show that the following changes are ready to be committed and deployed: + +![Changes ready for deployment](./images/deletions-of-doctype2.png) + +Commit the changes and push them to your repository and trigger a deployment to your environment. + +Once the deployment is complete, you will notice the following: + +* The Document Type you deleted on Development is still present in the backoffice on the production environment. + +You might wonder why the Document Type that you have deleted, is still there. The reason is, that deploy only deletes the associated UDA file, and not the actual Document Type in the database. + +In order to completely delete the Document Type from your entire project, you need to delete it from the backoffice of any of the other environments you have as well. When the Document Type has been deleted from the backoffice of all environments and no UDA file exists, you can consider it completely gone. + +You should however keep in mind that if you at any point during the process, save your Document Type again, a UDA file will be regenerated and when you start deploying changes between environments, this will likely end up recreating your deleted Document Type. + +## Which deletions are deployed? + +Every **file** that's deleted, will also be deleted on the next environment when you deploy. However, there are some differences depending on what you have deleted. + +Here's an overview of what happens when you deploy various deletions to the next environment. + +### Deleting Schema (Document Types, Datatypes etc.) + +Deleted: + +* The associated `.uda` file. + +Not deleted: + +* The entry in the database. +* The item will still be visible in the backoffice. + +### Deleting a Template + +Deleted: + +* The associated `.uda` file. +* The associated `.cshtml` file (the view file). + +Not deleted: + +* The entry in the database. +* The template file will be empty, but still be visible in the backoffice. + +### Deleting files (css files, config files etc.) + +As these are **only** files, everything will be deleted on the next environment upon deployment. + +### Deleting content and / or media + +Content and media deletions will not be picked up by deployments and will have to be deleted on each environment you wish to delete the content or media on. + +### Deleting backoffice languages + +Deleted: + +* The associated `.uda` file + +Not deleted: + +* The entry in the database +* The language will still be visible in the backoffice/content dashboard (for multilingual content) + +Deleting the language in the backoffice on the target environment will ensure the environments are in sync. diff --git a/14/umbraco-deploy/deployment-workflow/images/delete-exports.png b/14/umbraco-deploy/deployment-workflow/images/delete-exports.png new file mode 100644 index 00000000000..7c6bc8c53a7 Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/delete-exports.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/deletions-of-doctype2.png b/14/umbraco-deploy/deployment-workflow/images/deletions-of-doctype2.png new file mode 100644 index 00000000000..222348d67d2 Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/deletions-of-doctype2.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/deploy-dashboard.png b/14/umbraco-deploy/deployment-workflow/images/deploy-dashboard.png new file mode 100644 index 00000000000..f364aeac6dc Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/deploy-dashboard.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/environment-export-modal.png b/14/umbraco-deploy/deployment-workflow/images/environment-export-modal.png new file mode 100644 index 00000000000..de6e7a3eeea Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/environment-export-modal.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/export-complete.png b/14/umbraco-deploy/deployment-workflow/images/export-complete.png new file mode 100644 index 00000000000..3cff8d54d81 Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/export-complete.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/import-complete.png b/14/umbraco-deploy/deployment-workflow/images/import-complete.png new file mode 100644 index 00000000000..ab4b033482c Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/import-complete.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/import-modal-2.png b/14/umbraco-deploy/deployment-workflow/images/import-modal-2.png new file mode 100644 index 00000000000..f89f6d322cf Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/import-modal-2.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/import-modal.png b/14/umbraco-deploy/deployment-workflow/images/import-modal.png new file mode 100644 index 00000000000..3c746aeb94c Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/import-modal.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/left-to-right.png b/14/umbraco-deploy/deployment-workflow/images/left-to-right.png new file mode 100644 index 00000000000..ffe8d03dd6c Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/left-to-right.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/schema-mismatch.png b/14/umbraco-deploy/deployment-workflow/images/schema-mismatch.png new file mode 100644 index 00000000000..a2292cd1e98 Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/schema-mismatch.png differ diff --git a/14/umbraco-deploy/deployment-workflow/images/tree-export-modal.png b/14/umbraco-deploy/deployment-workflow/images/tree-export-modal.png new file mode 100644 index 00000000000..b286d8372b4 Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/images/tree-export-modal.png differ diff --git a/14/umbraco-deploy/deployment-workflow/import-export-v7.md b/14/umbraco-deploy/deployment-workflow/import-export-v7.md new file mode 100644 index 00000000000..9c13c139f3d --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/import-export-v7.md @@ -0,0 +1,232 @@ +--- +meta.Title: Migrating from Umbraco 7 +description: How to export content and schema from Umbraco 7 and import into a newer version +--- + +### Migrating from Umbraco 7 + +The import and export features are available for Umbraco Deploy supporting Umbraco 8 and above. It's not been ported back to Umbraco 7, hence you cannot trigger an export from the backoffice or use the service. + +However, you can still use this feature to help migrate from Umbraco 7 to a supported major version. This requires adding additional logic to your Umbraco 7 project to create an export ZIP archive similar to newer versions. + +#### Exporting Umbraco 7 content and schema + +You can generate an export archive in the same format as the import/export feature. This is done by adding the [`Umbraco.Deploy.Contrib.Export` assembly](https://github.com/umbraco/Umbraco.Deploy.Contrib/releases/tag/release-2.0.0-export) to your Umbraco 7 project (that already has Deploy and Deploy Contrib installed, see below). This archive can be imported into a newer Umbraco version by configuring the legacy import migrators. You can also apply additional migrators to update obsolete data types and property data into newer equivalents. + +This is possible via code, by temporarily applying a composer to an Umbraco 7 project to generate the export archive on start-up: + + +
+DeployExportApplicationHandler.cs (export Umbraco 7 content and schema to ZIP archive) + +```csharp +using System; +using System.Linq; +using System.Web.Hosting; +using Umbraco.Core; +using Umbraco.Deploy; +using UmbracoDeploy.Contrib.Export; + +public class DeployExportApplicationHandler : ApplicationEventHandler +{ + protected override void ApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) + { + // Set a default value connector that doesn't use object type prefixes + DefaultValueConnector.SetDefault(); + + // Run export after Deploy has started + DeployComponent.Started += (sender, e) => DeployStarted(); + } + + protected void DeployStarted() + { + var udis = new[] + { + // Export all content + Constants.UdiEntityType.Document, + Constants.UdiEntityType.DocumentBlueprint, + Constants.UdiEntityType.Media, + // Export all forms data + Constants.UdiEntityType.FormsForm, + Constants.UdiEntityType.FormsDataSource, + Constants.UdiEntityType.FormsPreValue + }.Select(Udi.Create); + + var dependencyEntityTypes = new[] + { + // Include all related schema + Constants.UdiEntityType.DataType, + Constants.UdiEntityType.DataTypeContainer, + Constants.UdiEntityType.DocumentType, + Constants.UdiEntityType.DocumentTypeContainer, + Constants.UdiEntityType.MediaType, + Constants.UdiEntityType.MediaTypeContainer, + Constants.UdiEntityType.MemberType, + Constants.UdiEntityType.MemberGroup, + Constants.UdiEntityType.Macro, + Constants.UdiEntityType.DictionaryItem, + Constants.UdiEntityType.Template, + Constants.UdiEntityType.Language, + // Include all related files + Constants.UdiEntityType.MediaFile, + Constants.UdiEntityType.MacroScript, + Constants.UdiEntityType.PartialView, + Constants.UdiEntityType.PartialViewMacro, + Constants.UdiEntityType.Script, + Constants.UdiEntityType.Stylesheet, + Constants.UdiEntityType.UserControl, + Constants.UdiEntityType.TemplateFile, + Constants.UdiEntityType.Xslt + }; + + // Create export + var zipArchiveFilePath = HostingEnvironment.MapPath("~/data/" + "export-" + Guid.NewGuid() + ".zip"); + ArtifactExportService.ExportArtifacts(udis, Constants.DeploySelector.ThisAndDescendants, zipArchiveFilePath, dependencyEntityTypes); + } +} +``` + +
+ +#### Importing Umbraco 7 content and schema + +To import this archive into a newer Umbraco project, you need to install either of these packages: + +- `UmbracoDeploy.Contrib` 4.3 for Umbraco 8 +- `Umbraco.Deploy.Contrib` for Umbraco 10.2, 12.1, 13.1 or later + +Then you need to configure the legacy artifact type resolver and migratory. + +Artifact type resolvers allow resolving changes in the type that's stored in the `__type` JSON property of the artifact. This is in case it moved to a different assembly or namespace (or got renamed) in a newer version. The legacy migrators handle the following changes: + +- Moving the pre-values of data types to the configuration property; +- Moving the invariant release and expiration dates of content to the (culture variant) schedule property; +- Moving the 'allowed at root' and 'allowed child content types' of content/media/member types to the permissions property; +- Migrating the Data Type configuration from pre-values to the correct configuration objects and new editor aliases for: + - `Umbraco.CheckBoxList` (pre-values to value list) + - `Umbraco.ColorPickerAlias` to `Umbraco.ColorPicker` (pre-values to value list) + - `Umbraco.ContentPicker2` to `Umbraco.ContentPicker` (removes invalid start node ID) + - `Umbraco.ContentPickerAlias` to `Umbraco.ContentPicker` (removes invalid start node ID) + - `Umbraco.Date` to `Umbraco.DateTime` + - `Umbraco.DropDown` to `Umbraco.DropDownListFlexible` (pre-values to value list, single item select) + - `Umbraco.DropDownListFlexible` (pre-values to value list, defaults to multiple item select) + - `Umbraco.DropdownlistMultiplePublishKeys` to `Umbraco.DropDownListFlexible` (pre-values to value list, defaults to multiple item select) + - `Umbraco.DropdownlistPublishingKeys` to `Umbraco.DropDownListFlexible` (pre-values to value list, defaults to single item select) + - `Umbraco.DropDownMultiple` to `Umbraco.DropDownListFlexible` (pre-values to value list, defaults to multiple item select) + - `Umbraco.MediaPicker2` to `Umbraco.MediaPicker` (removes invalid start node ID, defaults to single item select) + - `Umbraco.MediaPicker` (removes invalid start node ID) + - `Umbraco.MemberPicker2` to `Umbraco.MemberPicker` + - `Umbraco.MultiNodeTreePicker2` to `Umbraco.MultiNodeTreePicker` (removes invalid start node ID) + - `Umbraco.MultiNodeTreePicker` (removes invalid start node ID) + - `Umbraco.MultipleMediaPicker` to `Umbraco.MediaPicker` (removes invalid start node ID, defaults to multiple item select) + - `Umbraco.NoEdit` to `Umbraco.Label` + - `Umbraco.RadioButtonList` (pre-values to value list, change database type from integer to nvarchar) + - `Umbraco.RelatedLinks2` to `Umbraco.MultiUrlPicker` + - `Umbraco.RelatedLinks` to `Umbraco.MultiUrlPicker` + - `Umbraco.Textbox` to `Umbraco.TextBox` + - `Umbraco.TextboxMultiple` to `Umbraco.TextArea` + - `Umbraco.TinyMCEv3` to `Umbraco.TinyMCE` +- Migrating pre-value property values for: + - `Umbraco.CheckBoxList` + - `Umbraco.DropDown.Flexible` + - `Umbraco.RadioButtonList` + +The following composer adds the required legacy artifact type resolver and migrators. It also adds a custom resolver that marks the specified Document Type alias `testElement` as the element type. Element types are a concept added in Umbraco 8 and are required for Document Types that are used in Nested Content. + +
+LegacyImportComposer.cs (configure artifact type resolver and artifact migrators) + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Deploy.Contrib.Migrators.Legacy; + +internal class LegacyImportComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.DeployArtifactTypeResolvers() + .AddLegacyTypeResolver(); + + builder.DeployArtifactMigrators() + .AddLegacyMigrators() + .Append(); + + builder.DeployPropertyTypeMigrators() + .AddLegacyMigrators(); // Available from Deploy Contrib 13.3.0 and 14.2.0+ + } + + private class ElementTypeArtifactMigrator : ElementTypeArtifactMigratorBase + { + public ElementTypeArtifactMigrator() + : base("testElement") + { } + } +} +``` + +
+ +{% hint style="info" %} +It is recommended to start by importing only the schema and schema files (by deselecting 'Content' and 'Content files' in the dialog). Then, you can proceed with importing all content and schema together. The order in which the artifacts are imported depends on their dependencies. By importing the schema first, we ensure that the schema is updated before any content is processed. +{% endhint %} + +#### Obtaining Umbraco Deploy for Umbraco 7 + +Umbraco Deploy for Umbraco 7 is no longer supported and was only available on Umbraco Cloud. It was not released for use on-premise. + +As such if you are looking to migrate from an Umbraco Cloud project running on Umbraco 7, you already have Umbraco Deploy installed. + +If you have an Umbraco 7 on-premises website, you can use this guide to migrate from on-premises to Umbraco Cloud. Or to upgrade to a newer Deploy On-premises version. You need to obtain and install Umbraco Deploy for Umbraco 7 into your project, solely to use the export feature. + +The export feature can be used without a license. + +{% hint style="info" %} + +A license is required for the Umbraco project you are importing into. This can be a license that comes as part of an Umbraco Cloud subscription, or a Deploy On-premises one. + +{% endhint %} + +Use this guide to migrate from on-premises to Umbraco Cloud or to upgrade to a newer Deploy On-premises version. + +1. Download the required `dll` files for Umbraco Deploy for Umbraco 7 from the following links: + +- [Umbraco Deploy v2.1.6](https://umbraconightlies.blob.core.windows.net/umbraco-deploy-release/UmbracoDeploy.v2.1.6.zip): Latest Deploy Version 2 release for Umbraco CMS Version 7 (officially for use on Cloud) +- [Umbraco Deploy Contrib v2.0.0](https://umbraconightlies.blob.core.windows.net/umbraco-deploy-contrib-release/UmbracoDeploy.Contrib.2.0.0.zip): Latest/only Deploy Contrib Version 2 +- [Umbraco Deploy Export v2.0.0](https://github.com/umbraco/Umbraco.Deploy.Contrib/releases/tag/release-2.0.0-export): For exporting all content/schema in Version 7 + +2. Install Umbraco Deploy with the Contrib and Export extensions. + +- Install `Umbraco Deploy`, `Deploy.Contrib`, and `Deploy.Export` by copying the downloaded `.dll` files into your Umbraco 7 site. +- When copying the files over from `Umbraco Deploy` you should not overwrite the following files (if you already had Umbraco Deploy installed): + +```csharp + Config/UmbracoDeploy.config + Config/UmbracoDeploy.Settings.config +``` + +- Run the project to make sure it runs without any errors + +3. Update the `web.config` file with the required references for Umbraco Deploy: + +{% code title="web.config" lineNumbers="true" %} + +```xml + + + +
+
+ + + + + + + +``` + +{% endcode %} + +4. Export Content. + +- **Export** your content, schema, and files to zip. diff --git a/14/umbraco-deploy/deployment-workflow/import-export.md b/14/umbraco-deploy/deployment-workflow/import-export.md new file mode 100644 index 00000000000..e466883aead --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/import-export.md @@ -0,0 +1,181 @@ +--- +meta.Title: Import and export with Umbraco Deploy +description: How to import and export content and schema between Umbraco environments and projects +--- + +# Import and Export + +## What is import and export? + +The import and export feature of Umbraco Deploy allows you to transfer content and schema between Umbraco environments. Exports are made from one environment to a `.zip` file. And this file is imported into another environment to update the Umbraco data there. + +## When to use import and export + +Umbraco Deploy provides two primary workflows for managing different types of Umbraco data: + +- Umbraco schema (such as document types and data types) are transferred [as `.uda` files serialized to disk](./deploying-changes.md). They are deployed to refresh the schema information in a destination environment along with code and template updates. +- Umbraco content (such as content and media) are [transferred by editors using backoffice operations](./content-transfer.md). + +We recommend using these approaches for day-to-day editorial and developer activities. + +Import and export is intended more for larger transfer options, project upgrades, or one-off tasks when setting up new environments. + +As import and export is a two-step process, it doesn't require inter-environment communication. This allows us to process much larger batches of information without running into hard limits imposed by Cloud hosting platforms. + +We are also able provide hooks to allow for migrations of artifacts (such as data types) and property data when importing. This should allow you to migrate your Umbraco data from one Umbraco major version to a newer one. + +## Exporting content and schema + +To export content and schema, you can select either a specific item of content, or a whole tree or environment. + +When exporting, you can choose to include associated media files. Bear in mind that including media files for a large site can lead to a big zip file. So even with this option, you might want to consider a different method for transferring large amounts of media. For example using direct transfer between Cloud storage accounts or File Transfer Protocol (FTP). + +If your account has access to the Settings section, you can also choose to include the schema information and related files as well. + +![Tree export](images/tree-export-modal.png) + +When doing an environment export, you also have the option to include *all* schema in the export (introduced in Deploy 14.2), regardless of whether it is in use by any content. + +![Environment export](images/environment-export-modal.png) + +Umbraco Deploy will then serialize all the selected items to individual files, archive them into a zip file and make that available for download. You can download the file using the _Download_ button. + +After the download, you should also delete the archive file from the server. You can do this immediately via the _Delete_ button available in the dialog. + +![Export complete](images/export-complete.png) + +If you miss doing this, you can also clean up archive files from the Umbraco Deploy dashboard in the _Settings_ section. + +![Delete exports](images/delete-exports.png) + +{% hint style="info" %} +The exported archive files are saved to the Umbraco temp folder in the `Deploy\Export` sub-directory. This is a temporary (non-persistent) location, local to the backoffice server and therefore shouldn't be used for long-term storage of exports. You can also only download the file from the export dialog in the backoffice. +{% endhint %} + +## Importing content and schema + +Having previously exported content and schema to a zip file, you can import this into a new environment. + +![Import (step 1)](images/import-modal.png) + +You can upload the file via the browser. + +Similar to when exporting, you can choose to import everything from the archive file, or only content, schema or files. + +{% hint style="info" %} +Deploy does not touch the default maximum upload size, but you can [configure this yourself by following the CMS documentation](https://docs.umbraco.com/umbraco-cms/reference/configuration/maximumuploadsizesettings). + On Umbraco Cloud, the upload size limit is 500 MB. +{% endhint %} + +![Import (step 2)](images/import-modal-2.png) + +We validate the file before importing. Schema items that content depends on must either be in the upload itself or already exist on the target environment with the same details. If there are any issues that mean the import cannot proceed, it will be reported. You may also be given warnings for review. You can choose to ignore these and proceed if they aren't relevant to the action you are carrying out. + +The import then proceeds, processing all the items provided in the zip file. + +![Import complete](images/import-complete.png) + +Once complete or on close of the dialog, the imported file will be deleted from the server. If this is missed, perhaps via a closed browser, you can also delete archive files from the Umbraco Deploy dashboard in the _Settings_ section. + +## Migrating whilst importing + +It is possible to migrate schema and content whilst importing. For example, to change Data Type using Nested Content to Block List and ensure content data is imported to the correct Block Editor format. + +Deploy contains base classes and implementations to handle common migrations that need to be registered in code, as explained in [Import with migrations](./import-with-migrations.md). + +### Migrating from Umbraco 7 + +The import and export feature is not available in Deploy 2 for Umbraco 7. We have though released a package to allow creating an export. This needs to be done in code and requires additional legacy migrators to be able to import into a newer version. This is explained in [Migrating from Umbraco 7](./import-export-v7.md). + +## Service details (programmatically importing and exporting) + +Underlying the functionality of import/export with Deploy is the import/export service, defined by the `IArtifactImportExportService`. + +You may have need to make use of this service directly if building something custom with the feature. For example you might want to import from or export to some custom storage. + +The service interface defines two methods: + +- `ExportArtifactsAsync` - takes a collection of artifacts and a storage provider defined by the `IArtifactExportProvider` interface. The artifacts are serialized and exported to storage. + - `IArtifactExportProvider` defines methods for creating streams for writing serialized artifacts or files handled by Deploy (media, templates, stylesheets etc.). +- `ImportArtifactsAsync` - takes storage provider containing an import defined by the `IArtifactImportProvider` interface. The artifacts from storage are imported into Umbraco. + - `IArtifactImportProvider` defines methods for creating streams for reading serialized artifacts or files handled by Deploy (media, templates, stylesheets etc.). + +Implementations for `IArtifactExportProvider` and `IArtifactImportProvider` are provided for: + +- A physical directory. +- An Umbraco file system. +- A zip file. + +These are all accessible for use via extension methods available on `IArtifactImportExportService` found in the `Umbraco.Deploy.Infrastructure.Extensions` namespace. + +The following example shows this service in use, importing and exporting from a zip file on startup: + +
+ArtifactImportExportComposer.cs (import and export on startup) + +```csharp +using System.IO.Compression; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Deploy; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Extensions; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Deploy.Core; +using Umbraco.Deploy.Core.Connectors.ServiceConnectors; +using Umbraco.Deploy.Infrastructure; +using Umbraco.Deploy.Infrastructure.Extensions; +​ +internal class ArtifactImportExportComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.AddNotificationAsyncHandler(); +​ + private sealed class ArtifactImportExportStartedAsyncHandler : INotificationAsyncHandler + { + private readonly IHostEnvironment _hostEnvironment; + private readonly IArtifactImportExportService _diskImportExportService; + private readonly IServiceConnectorFactory _serviceConnectorFactory; + private readonly IFileTypeCollection _fileTypeCollection; +​ + public ArtifactImportExportStartedAsyncHandler(IHostEnvironment hostEnvironment, IArtifactImportExportService diskImportExportService, IServiceConnectorFactory serviceConnectorFactory, IFileTypeCollection fileTypeCollection) + { + _hostEnvironment = hostEnvironment; + _diskImportExportService = diskImportExportService; + _serviceConnectorFactory = serviceConnectorFactory; + _fileTypeCollection = fileTypeCollection; + } +​ + public async Task HandleAsync(UmbracoApplicationStartedNotification notification, CancellationToken cancellationToken) + { + var deployPath = _hostEnvironment.MapPathContentRoot(Constants.SystemDirectories.Data + "/Deploy"); + await ImportAsync(Path.Combine(deployPath, "import.zip")); +​ + Directory.CreateDirectory(deployPath); + await ExportAsync(Path.Combine(deployPath, $"export-{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}.zip")); + } +​ + private async Task ImportAsync(string zipFilePath) + { + if (File.Exists(zipFilePath)) + { + using ZipArchive zipArchive = ZipFile.OpenRead(zipFilePath); + await _diskImportExportService.ImportArtifactsAsync(zipArchive); + } + } +​ + private async Task ExportAsync(string zipFilePath) + { + using ZipArchive zipArchive = ZipFile.Open(zipFilePath, ZipArchiveMode.Create); +​ + IEnumerable udis = DeployEntityTypes.GetEntityTypes(_fileTypeCollection, DeployEntityTypeCategories.ContentAndSchema).Select(Udi.Create); + var contextCache = new DictionaryCache(); + string[] dependencyEntityTypes = DeployEntityTypes.GetEntityTypes(_fileTypeCollection, DeployEntityTypeCategories.All); +​ + await _diskImportExportService.ExportArtifactsAsync(_serviceConnectorFactory, udis, Constants.DeploySelector.ThisAndDescendants, contextCache, zipArchive, dependencyEntityTypes: dependencyEntityTypes); + } + } +} +``` + +
diff --git a/14/umbraco-deploy/deployment-workflow/import-on-startup.md b/14/umbraco-deploy/deployment-workflow/import-on-startup.md new file mode 100644 index 00000000000..53ee2e818d4 --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/import-on-startup.md @@ -0,0 +1,69 @@ +--- +meta.Title: Import on startup +description: How to import content and schema on startup and implement your own `IArtifactImportOnStartupProvider` +--- + +# Import on startup + +Deploy can import content and/or schema previously exported from another Umbraco installation on start-up. This allows for a quick setup of a baseline/starter kit or serves as a workaround for large ZIP archives that cannot be uploaded via the backoffice. + +## Default configuration + +The default configuration will look for the ZIP archive `umbraco\Deploy\import-on-startup.zip` on start-up and if it exists, run an import and delete the file on successful completion. If you want to customize the default behavior, do so via [settings](../getting-started/deploy-settings.md#import-on-startup). + +This feature is extensible via a provider-based model by implementing `IArtifactImportOnStartupProvider` and registering it using `builder.DeployArtifactImportOnStartupProviders()`. The default `Umbraco.Deploy.Infrastructure.SettingsArtifactImportOnStartupProvider` implementation uses the above settings and inherits from `Umbraco.Deploy.Infrastructure.ArtifactImportOnStartupProviderZipArchiveBase` (which can be used for your own custom implementation). + +## Implementing your own `IArtifactImportOnStartupProvider` + +An example of an import on a start-up provider that imports from a physical directory (instead of ZIP archive) is shown below: + +```csharp +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Extensions; +using Umbraco.Deploy.Core; +using Umbraco.Deploy.Core.OperationStatus; +using Umbraco.Deploy.Infrastructure.Extensions; + +internal sealed class DeployImportOnStartupComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.DeployArtifactImportOnStartupProviders() + .Append(); + + private sealed class PhysicalDirectoryArtifactImportOnStartupProvider : IArtifactImportOnStartupProvider + { + private readonly IArtifactImportExportService _artifactImportExportService; + private readonly ILogger _logger; + private readonly string _artifactsPath; + + public PhysicalDirectoryArtifactImportOnStartupProvider(IArtifactImportExportService artifactImportExportService, ILogger logger, IHostEnvironment hostEnvironment) + { + _artifactImportExportService = artifactImportExportService; + _logger = logger; + _artifactsPath = hostEnvironment.MapPathContentRoot("~/umbraco/Deploy/ImportOnStartup"); + } + + public Task CanImportAsync(CancellationToken cancellationToken = default) + => Task.FromResult(Directory.Exists(_artifactsPath)); + + public async Task> ImportAsync(CancellationToken cancellationToken = default) + { + _logger.LogInformation("Importing Umbraco content and/or schema import at startup from directory {FilePath}.", _artifactsPath); + + Attempt attempt = await _artifactImportExportService.ImportArtifactsAsync(_artifactsPath, default, null, cancellationToken); + + _logger.LogInformation("Imported Umbraco content and/or schema import at startup from directory {FilePath} with status: {OperationStatus}.", _artifactsPath, attempt.Result); + + if (attempt.Success) + { + Directory.Delete(_artifactsPath, true); + + _logger.LogInformation("Deleted physical directory after successful import on startup {FilePath}.", _artifactsPath); + } + + return attempt; + } + } +} +``` \ No newline at end of file diff --git a/14/umbraco-deploy/deployment-workflow/import-with-migrations.md b/14/umbraco-deploy/deployment-workflow/import-with-migrations.md new file mode 100644 index 00000000000..22fe930caaa --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/import-with-migrations.md @@ -0,0 +1,464 @@ +--- +meta.Title: Import with migrations in Umbraco Deploy +description: How to import content and schema while migrating them into newer alternatives +--- + +# Import with migrations + +As well as importing the content and schema directly, we also provide support for modifying the items as part of the process. + +For example, you may have taken an export from an Umbraco 8 site, and are looking to import it into a newer major version. In this situation, most content and schema will carry over without issue. However, you may have some items that are no longer compatible. Usually this is due to a property editor - either a built-in Umbraco one or one provided by a package. These may no longer be available in the new version. + +Often though there is a similar replacement. Using Deploy's import feature we can transform the exported content for the obsolete property into that used by the new one during the import. The migration to a content set compatible with the new versions can then be completed. + +For example, we can migrate from a Nested Content property in Umbraco 8 to a Block List in Umbraco 13. + +We provide the necessary migration hooks for this to happen, divided into two types - **artifact migrators** and **property migrators**. + +### Artifact migrators + +Artifact migrators work by transforming the serialized artifact of any imported artifact, via two interfaces: + +- `IArtifactMigrator` - where the migration occurs at the artifact property level +- `IArtifactJsonMigrator` - where the migration occurs at the lower level of transforming the serialized JSON itself. + +Implementations to handle common migrations of Data Types from obsoleted property editors are available: + +- `ReplaceMediaPickerDataTypeArtifactMigrator` - migrates a Data Type from using the legacy Media Picker to the current version of this property editor +- `ReplaceNestedContentDataTypeArtifactMigrator` - migrates a Data Type based on the obsolete Nested Content property editor to the Block List +- `ReplaceGridDataTypeArtifactMigrator` - migrates a Data Type based on the legacy Grid layout into the Block Grid +- `ReplaceUnknownEditorDataTypeArtifactMigrator` - replaces any unknown editor alias with a label + +We've also made available base implementations that you can use to build your own migrations. You may need to handle the transfer of information between other obsolete and replacement property editors that you have in your Umbraco application. + +- `ArtifactMigratorBase` - migrates the artifact of the specified type +- `DataTypeArtifactMigratorBase` - migrates Data Type artifacts +- `ReplaceDataTypeArtifactMigratorBase` - migrates a Data Type from one property editor to another +- `ArtifactJsonMigratorBase` - migrates the JSON of the specified artifact type +- `ReplaceGridDataTypeArtifactMigratorBase` - migrates a Data Type based on the legacy Grid layout into the Block Grid + +### Property migrators + +Property migrators work to transform the content property data itself. They are used in the Deploy content connectors (documents, media and members) when the property editor is changed during an import: + +Again we have an interface: + +- `IPropertyTypeMigrator` + +Implementations for common migrations: + +- `MediaPickerPropertyTypeMigrator` +- `NestedContentPropertyTypeMigrator` +- `GridPropertyTypeMigrator` + +And a base type to help you build your own migrations: + +- `PropertyTypeMigratorBase` +- `GridPropertyTypeMigratorBase` + +{% hint style="info" %} +Property editor changes are determined by comparing the `PropertyEditorAliases` dictionary stored in the content artifact to the current Content Type/Data Type configuration. The dictionary contains editor aliases for each content property. +{% endhint %} + +### Registering migrators + +Migrators will run if you have registered them, so you can enable only the ones needed for your solution. + +You can do this via a composer, as in the following example. Here we register two of the migrators shipped with Umbraco Deploy: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Deploy.Core.Migrators; +using Umbraco.Deploy.Infrastructure.Migrators; + +internal class ArtifactMigratorsComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.DeployArtifactMigrators() + .Append() + .Append(); + + builder.DeployPropertyTypeMigrators() + .Append() + .Append(); + } +} + ``` + +### Import and migration flow + +When an import is started, the following happens: +1. Artifact signatures are read from the import provider (using `IArtifactImportProvider.GetArtifactSignatures()`). +2. The artifact signatures are sorted based on dependencies with `Ordering` enabled (ensuring dependent items are processed in the correct order, like parent items before children and data types before document types). +3. For each artifact signature: + 1. Check whether the entity type is allowed to be imported. + 2. Publish an `ArtifactImportingNotification` (cancelling will skip importing the artifact). +4. Publish a `ValidateArtifactImportNotification`: + - Deploy adds a default handler (`ValidateArtifactImportDependenciesNotificationHandler`) to validate whether all dependencies are either in the import or already present in the current environment. It emits warnings for missing content artifacts, missing or different artifact checksums and errors for missing schema artifacts. + - The import fails on validation errors or 'soft' fails on warnings if the `WarningsAsErrors` import option is set. +5. Create a Deploy scope and context (containing the 'owner' user for auditing purposes and cultures to import, in case the user doesn't have edit permissions for all languages). +6. For each artifact signature: + 1. Create a (readonly) `Stream` for the artifact (using `IArtifactImportProvider.CreateArtifactReadStream(Udi)`). + 2. Deserialize the artifact into a generic JSON object (`JsonNode`). + 3. Parse the `__version` and `__type` properties and resolve the artifact type (using `IArtifactTypeResolver`). + 4. Migrate the JSON object (using `IArtifactJsonMigrator`). + 5. Deserialize the JSON object into the artifact type. + 6. Migrate the artifact (using `IArtifactMigrator`). + 7. Initialize artifact processing (using `IServiceConnector.ProcessInit(...)`) and track deploy state with next passes. +7. For each next process pass (starting at the lowest initial next pass): + 1. Process artifact (using `IServiceConnector.Process(...)`). + 2. During processing: service connectors for content, media and members migrate property type values if a property editor alias has changed (using `IPropertyTypeMigrator`). + 3. When no next pass is required (the deploy state returns -1 as next pass): + 1. Publish an `ArtifactImportedNotification`. + 2. Report the import process (using `IProgress.Report(...)`). +8. The Deploy scope is completed, causing all scoped notifications to be published to handlers implementing `IDistributedCacheNotificationHandler`) and completing the import. + +### Details of Specific Migrations + +Umbraco Deploy ships with migrators to handle the conversion of core property editors as they have changed, been removed or replaced between versions. + +Open source migrators may be built by HQ or the community for property editors found in community packages. They will be made available for [use](https://www.nuget.org/packages/Umbraco.Deploy.Contrib) and [review](https://github.com/umbraco/Umbraco.Deploy.Contrib/tree/v14/dev/src/Umbraco.Deploy.Contrib/Migrators) via the `Umbraco.Deploy.Contrib` package. + +#### Grid to Block Grid + +The Grid editor introduced in Umbraco 7 has been removed from Umbraco 14. Its functionality is replaced with the Block Grid. + +With Deploy migrators we have support for migrating Data Type configuration and property data between these property editors. + +Deploy adds the `ReplaceGridDataTypeArtifactMigrator` and `GridPropertyTypeMigrator` migrators by default, so using a custom migrator requires replacing the default ones: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Deploy.Infrastructure.Migrators; + +internal sealed class DeployMigratorsComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.DeployArtifactMigrators() + .Replace(); + + builder.DeployPropertyTypeMigrators() + .Replace(); + } +} +``` + +{% hint style="info" %} +The project you are importing into needs to know about any custom legacy Grid editor configurations to migrate to the Block Grid editor correctly. Make sure to either copy the `grid.editors.config.js` and `package.manifest` (containing grid editors) files or override the `GetGridEditors()` method of the artifact migrator to provide this. +{% endhint %} + +These implementations make use of the following conventions to migrate the data: + +- `ReplaceGridDataTypeArtifactMigrator`: + - Grid layouts are migrated to an existing or new element type with an alias based on the layout name, prefixed with `gridLayout_` (this can be customized by overriding `MigrateGridTemplate()`); + - Row configurations are migrated to an existing or new element type with an alias based on the row name, prefixed with `gridRow_` (this can be customized by overriding `MigrateGridLayout()`); + - Similarly, grid editors are migrated to an existing or new element type with an alias based on the editor alias, prefixed with `gridEditor_` (this can be customized by overriding `MigrateGridEditor()`). The default editors used in version 13 are returned by `GetGridEditors()` and you can override this method to include your custom editors. Each migrated grid editor will have the following property types added to the element type: + - The `media` grid editor is migrated to multiple properties: the `value` property contains the selected media item (using Media Picker v3), `altText` the alternate text (using a Textbox) and `caption` the caption (also using a Textbox); + - The remaining grid editors create a single `value` property that uses the following editors: + - `rte` - the default 'Rich Text Editor', falling back to the first `Umbraco.TinyMCE` editor. + - `headline` - the default 'Textstring', falling back to the first `Umbraco.TextBox` editor. + - `macro` and `embed` grid editors are converted into rich text editors. + - `quote` or any other - use falling back to the first `Umbraco.TextArea` editor. + - The block label is also updated for the built-in grid editors, ensuring a nice preview is available (the WYSIWYG style previews are incompatible between these editors, so the custom views are not migrated); + - Grid settings config and styles are migrated to a new element type with a random alias, prefixed with `gridSettings_` (this can be customized by overriding `MigrateGridSettings()`). This is because the migration only has context about the Data Type configuration (not the actual Data Type) and multiple Data Type can potentially use the same configuration (for config and styles), so there's no predictable way to create a unique alias. The migrated settings element type will have the property types added for the config and styles: + - Each config setting is migrated to a property with an alias based on the key, prefixed with `setting_` and added below a 'Settings' property group; + - Similarly, each style is migrated to a property with an alias based on the key, prefixed with `style_` and added below a 'Styles' property group; + - The following property editors are used for these properties based on the config/style view: + - `radiobuttonlist` - a new 'Radio Button List' Data Type that uses the pre-values; + - `multivalues` - a new 'Checkbox List' Data Type that uses the pre-values; + - `textstring` - the default 'Textstring', falling back to the first `Umbraco.TextBox` editor. + - `mediapicker` and `imagepicker` - the default 'Media Picker' (v3, single image), falling back to the first `Umbraco.MediaPicker3` editor. + - `boolean` - the default 'Checkbox', falling back to the first `Umbraco.TrueFalse` editor. + - `number` - the default 'Numeric', falling back to the first `Umbraco.Integer` editor. + - `treepicker`, `treesource`, `textarea` or any other - the default 'Textarea', falling back to the first `Umbraco.TextArea` editor. +- `GridPropertyTypeMigrator`: + - Gets the grid layout and row configuration element types based on the alias prefix/name convention used by the Data Type artifact migrator; + - The grid editor values are migrated to the respective properties: + - The `media` grid editor converts the value to a media item with crops (based on the UDI or media path), including the focal point (although this needs to be enabled on the Data Type), alternate text and caption; + - All other values are converted to a text value or otherwise to a JSON string; + - If a row or cell contains settings config or styles and the corresponding block has a settings element type configured, the settings config and styles are migrated to their respective properties in a similar way, based on the property editor alias: + - `Umbraco.MediaPicker3` - removes `url('` from the beginning and `')` from the end of the value (commonly used as a modifier and added to the stored value), before trying to get the media item by a path. + - All other values are returned as-is. + +Given the flexibility of the grid editor and Block Grid you may want to take further control over the migration. You can do that by creating your own migrator classes, that make use of our provided base classes. You would then register your own migrators instead of the ones shipped with Umbraco Deploy in your composer. + +The base classes provide the following functionality. Methods you should look to override to amend the default behavior have been noted above. + +- `ReplaceGridDataTypeArtifactMigratorBase` - replaces the `Umbraco.Grid` Data Type editor alias with `Umbraco.BlockGrid` and migrates the configuration: + - The number of columns is copied over. + - Grid layouts, row configurations and grid editors are migrated to blocks: + - If multiple grid layouts are configured or if at least one contains multiple sections or isn't the full width, each grid layout will be migrated to a 'layout block' (an element type without properties). + - If multiple row configurations are configured or if at least one contains areas that don't allow all grid editors or has a maximum amount of items set, each row configuration is migrated to a block (this is also always done when there are multiple grid layouts, as each layout can configure allowed row configurations). + - All grid editors are migrated to blocks (allowing a single grid editor to be migrated to multiple blocks to support DocTypeGridEditor, as that allows selecting different element types). + - The settings config and styles are migrated to a single element type (even though each setting can define whether it's supported for rows and/or cells) and used on the blocks that are allowed. + - Block groups are added for Layout and Content and used on the corresponding block types. +- `GridPropertyTypeMigratorBase` - migrates the property data from the `GridValue` into the `BlockValue` (using the `Umbraco.BlockGrid` layout): + - The related Data Type is retrieved to get the configured blocks. + - All grid control values are first migrated into their content blocks. + - Settings config and styles for 'grid cells' are stored on the area within a row, but areas in the Block Grid can't have settings, so this is migrated into the first migrated grid control content block instead. + - If a layout block can be found for the row configuration name, all grid controls are wrapped into that block. + - Similarly, if a layout block can be found for the grid layout name, all items are wrapped into that block. + - The JSON serialized `BlockValue` is returned. + +#### Migrating From Doc Type Grid Editor + +[Doc Type Grid Editor](https://our.umbraco.com/packages/backoffice-extensions/doc-type-grid-editor/) was a community package commonly used with the legacy grid editor. If you are using this with Umbraco 7 and up, you can export and migrate into the Block Grid on Umbraco 13 or above. + +Ensure you are running the latest version of `Umbraco.Deploy.Contrib` compatible with your Umbraco major version. + +In your new project, register the following migrators to add support for the import from Doc Type Grid Editor grids: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Deploy.Infrastructure.Migrators; + +internal sealed class DeployMigratorsComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.DeployArtifactMigrators() + .Append(); + + builder.DeployPropertyTypeMigrators() + .Append(); + } +} +``` + +The migrators add the following behavior: + +- `ReplaceDocTypeGridEditorDataTypeArtifactMigrator` extends `ReplaceGridDataTypeArtifactMigrator` and ensures any DocTypeGridEditor is migrated to blocks using the allowed element types. If the element types aren't found the default implementation will migrate to new element types. +- `DocTypeGridEditorPropertyTypeMigrator` extends `GridPropertyTypeMigrator` and ensures the Doc Type Grid Editor values are mapped one-to-one to the block item data. + +{% hint style="info" %} +The artifact migrator adds the default DocTypeGridEditor configuration (with alias `docType`). This can be disabled by setting the `AddDefaultDocTypeGridEditor` property to `false` in a custom/inherited class. Similar to the base migrator, any custom DocTypeGridEditor configurations must be available to migrate to the Block Grid editor correctly. +{% endhint %} + +#### Migrating from Matryoshka + +[Matryoshka](https://our.umbraco.com/packages/backoffice-extensions/matryoshka-tabs-for-umbraco-8/) was an Umbraco package that added tab support for document types in Umbraco. The feature was subsequently added to the product itself. + +We provide a migrator for this package in `Umbraco.Deploy.Contrib`. + +This adds support for migrating Matryoshka Group Separators into native property groups. It removes the Matryoshka Data Types during import and migrates the document, media and member types. Native property groups are also changed into tabs, similarly to how they were displayed with Matryoshka installed. + +To use, you register the migrators: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Deploy.Infrastructure.Migrators; + +internal sealed class DeployMigratorsComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.DeployArtifactMigrators() + .Append(); + } +} +``` + +### Source Code Example - Nested Content to Block List + +As described above, the nested content to block list migration will occur register the corresponding migrator with your application. + +To help write your own migrations, we share the source code of an example that ships with Umbraco Deploy. This migration converts Nested Content to Block List. + +First we have the artifact migrator that handles the conversion of the configuration stored with a datatype: + +
+ReplaceNestedContentDataTypeArtifactMigrator.cs (migrate Nested Content Data Type to Block List) + +```csharp +using System.Globalization; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Deploy.Infrastructure.Artifacts; + +public class ReplaceNestedContentDataTypeArtifactMigrator : ReplaceDataTypeArtifactMigratorBase +{ + private readonly IContentTypeService _contentTypeService; + + public ReplaceNestedContentDataTypeArtifactMigrator(PropertyEditorCollection propertyEditors, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer, IContentTypeService contentTypeService) + : base(Constants.PropertyEditors.Aliases.NestedContent, Constants.PropertyEditors.Aliases.BlockList, propertyEditors, configurationEditorJsonSerializer) + => _contentTypeService = contentTypeService; + + protected override BlockListConfiguration? MigrateConfiguration(NestedContentConfiguration configuration) + { + var blockListConfiguration = new BlockListConfiguration() + { + UseInlineEditingAsDefault = true // Similar to how Nested Content looks/works + }; + + if (configuration.MinItems > 0) + { + blockListConfiguration.ValidationLimit.Min = configuration.MinItems; + } + + if (configuration.MaxItems > 0) + { + blockListConfiguration.ValidationLimit.Max = configuration.MaxItems; + } + + if (configuration.ContentTypes is not null) + { + var blocks = new List(); + foreach (NestedContentConfiguration.ContentType nestedContentType in configuration.ContentTypes) + { + if (nestedContentType.Alias is not null && + GetContentTypeKey(nestedContentType.Alias) is Guid contentTypeKey) + { + blocks.Add(new BlockListConfiguration.BlockConfiguration() + { + Label = nestedContentType.Template, + ContentElementTypeKey = contentTypeKey + }); + } + } + + blockListConfiguration.Blocks = blocks.ToArray(); + } + + if (blockListConfiguration.ValidationLimit.Min == 1 && + blockListConfiguration.ValidationLimit.Max == 1 && + blockListConfiguration.Blocks.Length == 1) + { + blockListConfiguration.UseSingleBlockMode = true; + } + + return blockListConfiguration; + } + + protected virtual Guid? GetContentTypeKey(string alias) + { + if (_contentTypeService.Get(alias) is IContentType contentTypeByAlias) + { + return contentTypeByAlias.Key; + } + + // New content types are initially saved by Deploy with a custom postfix (to avoid duplicate aliases), so try to get the first matching item + string aliasPrefix = alias + "__"; + foreach (IContentType contentType in _contentTypeService.GetAll()) + { + if (contentType.Alias.StartsWith(aliasPrefix) && + int.TryParse(contentType.Alias[aliasPrefix.Length..], NumberStyles.HexNumber, null, out _)) + { + return contentType.Key; + } + } + + return null; + } +} +``` + +
+ +And secondly we have the property migrator that handles restructuring the content property data: + +
+NestedContentPropertyTypeMigrator.cs (migrate Nested Content property data to Block List) + +```csharp +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Deploy; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Blocks; +using Umbraco.Cms.Core.Services; +using Umbraco.Deploy.Core; +using Umbraco.Deploy.Core.Migrators; +using Umbraco.Deploy.Infrastructure.Extensions; + +public class NestedContentPropertyTypeMigrator : PropertyTypeMigratorBase +{ + private readonly ILogger _logger; + private readonly IContentTypeService _contentTypeService; + + public NestedContentPropertyTypeMigrator(ILogger logger, IContentTypeService contentTypeService) + : base(Constants.PropertyEditors.Aliases.NestedContent, Constants.PropertyEditors.Aliases.BlockList) + { + _logger = logger; + _contentTypeService = contentTypeService; + } + + public override object? Migrate(IPropertyType propertyType, object? value, IDictionary propertyEditorAliases, IContextCache contextCache) + { + if (value is not string stringValue || !stringValue.TryParseJson(out NestedContentItem[]? nestedContentItems) || nestedContentItems is null) + { + if (value is not null) + { + _logger.LogWarning("Skipping migration of Nested Content items ({PropertyTypeAlias}), because value could not be parsed: {Value}.", propertyType.Alias, value); + } + + return null; + } + + var layoutItems = new List(); + var contentData = new List(); + + foreach (NestedContentItem nestedContentItem in nestedContentItems) + { + IContentType? contentType = contextCache.GetContentTypeByAlias(_contentTypeService, nestedContentItem.ContentTypeAlias); + if (contentType is null) + { + _logger.LogWarning("Skipping migration of Nested Content item ({Id}), because content type does not exist: {ContentTypeAlias}.", nestedContentItem.Id, nestedContentItem.ContentTypeAlias); + continue; + } + + var udi = new GuidUdi(Constants.UdiEntityType.Element, nestedContentItem.Id); + + layoutItems.Add(new BlockListLayoutItem() + { + ContentUdi = udi + }); + + contentData.Add(new BlockItemData() + { + Udi = udi, + ContentTypeKey = contentType.Key, + RawPropertyValues = nestedContentItem.RawPropertyValues + }); + } + + var blockValue = new BlockValue() + { + Layout = new Dictionary() + { + { Constants.PropertyEditors.Aliases.BlockList, JToken.FromObject(layoutItems) } + }, + ContentData = contentData + }; + + return JsonConvert.SerializeObject(blockValue, Formatting.None); + } + + internal class NestedContentItem + { + [JsonProperty("key")] + public Guid Id { get; set; } = Guid.NewGuid(); // Ensure a unique key is set, even if the JSON doesn't have one + + [JsonProperty("name")] + public string? Name { get; set; } + + [JsonIgnore] + public object? PropType { get; set; } // Ensure this property is ignored + + [JsonProperty("ncContentTypeAlias")] + public string ContentTypeAlias { get; set; } = null!; + + [JsonExtensionData] + public Dictionary RawPropertyValues { get; set; } = null!; + } +} +``` + +
+ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/README.md b/14/umbraco-deploy/deployment-workflow/restoring-content/README.md new file mode 100644 index 00000000000..38e1bb62146 --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/restoring-content/README.md @@ -0,0 +1,65 @@ +--- +description: How to restore content in Umbraco Deploy +--- + +# Restoring content + +When you have content on your environment and you clone down your Umbraco project to your local machine, you will need to do an extra step, in order to see your content locally. + +The restore option also comes in really handy when you have content editors creating content on different environments. You will be able to restore and work with that content on your different environments and locally. + +## Step-by-step + +There are four options when it comes to restoring content. + +1. [Restore when starting up the project locally](./#restore-when-starting-up-the-project-locally) +2. [Restore everything through the Umbraco backoffice](./#restore-everything-through-the-umbraco-backoffice) +3. [Restore a single tree through the Umbraco backoffice](./#restore-a-single-tree-through-the-umbraco-backoffice) +4. [Partial Restores](partial-restore.md) + +### Restore when starting up the project locally + +The first time you run your project locally you will have the option to restore your content and media before going to the Umbraco backoffice. + +{% hint style="info" %} +This will restore **all** content and media, plus any other entities configured for back-office transfer. +{% endhint %} + +1. When your site is done spinning up, click the green _Restore_ button - this will restore all content and media. +2. Wait till the process completes - this might take a while, depending on the amount of content and media you have on your Umbraco site. +3. When it's complete select _Open Umbraco_ to go to the backoffice. +4. You will now see all your content and media in the Umbraco backoffice. + +![Restore from start-up](../../../umbraco-cloud/deployment/restoring-content/images/Normal-Restore.gif) + +### Restore everything through the Umbraco backoffice + +The second option for restoring your content and media is found in the Umbraco backoffice. + +1. Go to the Umbraco backoffice on the environment you want to restore content and media to. +2. Click **...** next to the Content Tree. +3. Choose _Workspace restore..._ from the menu. +4. You will now have the option to restore content from any environment that's _to the right of_ the current environment in the deployment workflow. +5. To ensure the restore will succeed, [make sure that your environments have the same meta data and structure files](../deploying-changes.md). +6. Click _Restore from .._ and wait till the process completes - this might take a while, depending on the amount of content and media you have on your project. +7. When it's done, click **...** next to the Content tree again and choose _Reload_ to see your content in the tree. + +{% hint style="info" %} +As well as content, media and any other entities configured for back-office transfer, will also be restored in the process. + +To see the media, go to the Media section and _Reload_ the tree. +{% endhint %} + +{% embed url="https://www.youtube.com/embed/poRzuBB11pc?rel=0" %} +Umbraco Deploy - Content transfer and restore +{% endembed %} + +### Restore a single tree through the Umbraco backoffice + +The operation is triggered in the same way as when restoring everything, but instead the _Tree restore..._ menu option should be selected. + +For example, if triggered from the content tree, only content entities will be restored. This will also restore any media that’s referenced in that content, but it won’t attempt to restore the full media library, nor any other entities. + +### [Partial Restore](partial-restore.md) + +By using the Partial Restore option, you can make sure that you only restore the part of the content that you need to work with. You can either restore a single item, or include all the descendents of that item too. diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/images/Normal-Restore.gif b/14/umbraco-deploy/deployment-workflow/restoring-content/images/Normal-Restore.gif new file mode 100644 index 00000000000..45e8a8011c6 Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/restoring-content/images/Normal-Restore.gif differ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/images/Restore-from-Backoffice.gif b/14/umbraco-deploy/deployment-workflow/restoring-content/images/Restore-from-Backoffice.gif new file mode 100644 index 00000000000..d1728748e6a Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/restoring-content/images/Restore-from-Backoffice.gif differ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1) (1) (1) (1).gif b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1) (1) (1) (1).gif new file mode 100644 index 00000000000..4c96d15e2dd Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1) (1) (1) (1).gif differ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1) (1) (1).gif b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1) (1) (1).gif new file mode 100644 index 00000000000..4c96d15e2dd Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1) (1) (1).gif differ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1) (1).gif b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1) (1).gif new file mode 100644 index 00000000000..4c96d15e2dd Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1) (1).gif differ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1).gif b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1).gif new file mode 100644 index 00000000000..4c96d15e2dd Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty (1).gif differ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty-v9.gif b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty-v9.gif new file mode 100644 index 00000000000..84cb5f8ce58 Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty-v9.gif differ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty.gif b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty.gif new file mode 100644 index 00000000000..4c96d15e2dd Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty.gif differ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEnvWithContent.png b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEnvWithContent.png new file mode 100644 index 00000000000..c5b457cdbf4 Binary files /dev/null and b/14/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEnvWithContent.png differ diff --git a/14/umbraco-deploy/deployment-workflow/restoring-content/partial-restore.md b/14/umbraco-deploy/deployment-workflow/restoring-content/partial-restore.md new file mode 100644 index 00000000000..3a561fec218 --- /dev/null +++ b/14/umbraco-deploy/deployment-workflow/restoring-content/partial-restore.md @@ -0,0 +1,60 @@ +--- +description: How to partially restore content in Umbraco Deploy +--- + +# Partial Restores + +In some cases you might not want to restore the entire content tree, but only the parts that you need. **Partial restores** is a feature that allows for restoring specific parts of your content instead of restoring everything. + +You can use Partial Restore on + +* [Environments with existing content or media](partial-restore.md#environment-with-existing-content-or-media), and on +* [Empty environments](partial-restore.md#empty-environment) + +## Empty environment + +In this scenario you've cloned down your environment to your local machine or setup a new environment. In both cases the new environment will have an empty Content section as well as an empty Media section. + +{% hint style="info" %} +Be aware that this feature will also restore all dependencies on the selected content. + +E.g. when you restore a content node which references media items as well as other content nodes, these will all be restored as well, including any parent nodes that these nodes depend on. +{% endhint %} + +Follow these steps to perform a partial restore to get only the parts you need: + +1. Go to the Content section of the Umbraco backoffice on your environment or locally. +2. Click **...** next to the Content Tree. +3. Choose _Partial Restore_. +4. Select the environment that you would like to restore content from. +5. Click "_Select content to restore_" - this will open a dialog with a _preview of the content tree_ from the environment you selected. +6. Select the content node you would like to restore. +7. Decide whether you also want to restore any child nodes _below_ the selected node. +8. Start the restore by clicking _Restore_. +9. To see the restored content, _reload_ the content tree - Click **...** next to the Content tree to find this option. + +{% hint style="info" %} +Keep in mind if you select a content node deeper down the tree, all the parents above it, required for the node to exist, will be restored as well. +{% endhint %} + +![Partial restore on empty environment](../../../../10/umbraco-deploy/deployment-workflow/restoring-content/images/partialRestore-onEmpty-v9.gif) + +Partial Restores on empty environments are especially helpful when you have a large amount of content and media and do not necessarily need it all for the task you need to do. + +Instead of having to restore everything which could potentially take a long time, doing a partial restore can be used to shorten the waiting time by only restoring the parts you need. This will ensure that you can quickly get on your way with the task at hand. + +## Environment with existing content or media + +It is also possible to use the Partial Restore feature on environments where you already have content in the Content tree. + +Imagine that you are working with your Umbraco project locally. One of your content editors updates a section in the content tree on the production environment. You would like to see how this updated content looks with the new code you are working on. Follow these steps to do a Partial Restore of the updated content node: + +1. Go to the Content section of your local Umbraco backoffice +2. Click **...** next to the content node which you know contains updates +3. Choose _Partial Restore_ +4. Select the environment that you would like to restore content from +5. Decide whether you also want restore any child nodes under the selected node +6. Start the restore by clicking _Restore_ +7. When the restore is done, reload the content tree to see the changes + +![Partial restore](../../../umbraco-cloud/deployment/restoring-content/images/partialRestore-onEnvWithContent.png) diff --git a/14/umbraco-deploy/extending/extending.md b/14/umbraco-deploy/extending/extending.md new file mode 100644 index 00000000000..b302cfa7c72 --- /dev/null +++ b/14/umbraco-deploy/extending/extending.md @@ -0,0 +1,691 @@ +--- +description: How to extend Umbraco Deploy to synchronize custom data +--- + +# Extend Deploy + +Umbraco Deploy supports the deployment of CMS schema information and definitions from the HQ's Forms package, along with managed content and media. Additionally, it can be extended by package or custom solution developers. This allows the deployment of custom data, such as that stored in your own database tables. + +As a package or solution developer, you can hook into the disk-based serialization and deployment. It is similar to that used for Umbraco Document Types and Data Types. It's also possible to provide the ability for editors to deploy custom data via the Backoffice. In the same way that Umbraco content and media can be queued for transfer and restored. + +## Concepts and Examples + +### Entities + +_Entities_ are what you may be looking to transfer between two websites using Deploy. Within Umbraco, they are the Document Types, Data Type, documents etc. In a custom solution or a package, there may be representations of some other data that's being stored separately from Umbraco content. These can still be managed in the Backoffice using custom trees and editors. + +For the purposes of subsequent code samples, we'll consider an example entity as a Plain Old Class Object (POCO) with a few properties. + +{% hint style="info" %} +The entity has no dependency on Umbraco or Umbraco Deploy; it can be constructed and managed however makes sense for the package or solution. The only requirement is that it has an ID that will be consistent across the environments (normally a Guid) and a name. +{% endhint %} + +```csharp +public class Example +{ + public Guid Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } +} +``` + +### Artifacts + +Every entity Deploy works with, whether from Umbraco core or custom data, needs to have an _artifact_ representation. You can consider an artifact as a container capable of knowing everything there is to know about a particular entity is defined. They are used as a transport object for communicating between Deploy environments. + +They can also be serialized to JSON representations. These are visible in the .uda files seen on disk in the `/data/revisions/` folder for schema transfers. It is also used when transferring content between different environments over HTTP requests. + +Artifact classes must inherit from `DeployArtifactBase`. + +The following example shows an artifact representing the entity and it's single property for transfer: + +```csharp +public class ExampleArtifact : DeployArtifactBase +{ + public ExampleArtifact(GuidUdi udi, IEnumerable dependencies = null) + : base(udi, dependencies) + { } + + public string Description { get; set; } +} +``` + +#### Control Over Serialization + +In most cases the default settings Umbraco Deploy uses for serialization will be appropriate. For example, it ensures that culture specific values such as dates and decimal numbers are rendered using an invariant culture. This ensures that any differences in regional settings between source and destination servers are not a concern. + +If you do need more control, attributes can be applied to the artifact properties. + +For example, to ensure a decimal value is serialized to a consistent number of decimal places you can use the following. `RoundingDecimalJsonConverter` is found in the `Umbraco.Deploy.Serialization` namespace + +```csharp +[JsonConverter(typeof(RoundingDecimalJsonConverter), 2)] +public decimal Amount { get; set; } +``` + +### Service Connectors + +Service connectors are responsible for knowing how to handle the mapping between artifacts and entities. They know how to gather all the data required for the type of entity they correspond to, including figuring out what dependencies are needed. For example, in Umbraco, how a Document Type depends on a Data Type. They are responsible for packaging an entity as an artifact and for extracting an entity from an artifact and persisting it in a destination site. + +Service connectors inherit from `ServiceConnectorBase` and are constructed with the artifact and entity as generic type arguments. + +The class is decorated with a `UdiDefinition` via which the name of the entity type is provided. This needs to be unique across all entities so it's likely worth prefixing with something specific to your package or application. + +The following example shows a service connector, responsible for handling the artifact shown above and it's related entity. There are no dependencies to consider here. More complex examples involve collating the dependencies and potentially handling extraction in more than one pass to ensure updates are made in the correct order. + +An illustrative data service is provided via dependency injection. This will be whatever is appropriate for to use for Create, Read, Update and Delete (CRUD) operations around reading and writing of entities. + +{% hint style="info" %} +In Deploy 9.5/10.1, to improve performance on deploy operations, we introduced a cache. This change required the addition of new methods to interfaces, allowing the passing in of a cache parameter. In order to introduce this without breaking changes, we created some new interfaces and base classes. + +In the example below, if instead we inherited from `ServiceConnectorBase2`, which has a type parameter of `IServiceConnector2`, we would be able to implement `IArtifact? IServiceConnector2.GetArtifact(Udi udi, IContextCache contextCache)`. This would allow the connector to read and write to the cache and remove the use of the obsolete methods. + +There's no harm in what is listed below though. It's only that the connectors won't be able to use the cache for any look-ups that are repeated in deploy operations. The obsolete methods won't be removed until Deploy 11. In that version we plan to return back to the original interface and class names. We also plan to introduce the new method overloads which will be a documented breaking change. +{% endhint %} + +```csharp +[UdiDefinition("mypackage-example", UdiType.GuidUdi)] +public class ExampleServiceConnector : ServiceConnectorBase> +{ + private readonly IExampleDataService _exampleDataService; + + public ExampleServiceConnector(IExampleDataService exampleDataService) => _exampleDataService = exampleDataService; + + public override ExampleArtifact GetArtifact(object o) + { + var entity = o as Example; + if (entity == null) + { + throw new InvalidEntityTypeException($"Unexpected entity type \"{o.GetType().FullName}\"."); + } + + return GetArtifact(entity.GetUdi(), entity); + } + + public override ExampleArtifact GetArtifact(GuidUdi udi) + { + EnsureType(udi); + var entity = _exampleDataService.GetExampleById(udi.Guid); + + return GetArtifact(udi, entity); + } + + private ExampleArtifact GetArtifact(GuidUdi udi, Example entity) + { + if (entity == null) + { + return null; + } + + var dependencies = new ArtifactDependencyCollection(); + var artifact = Map(udi, entity, dependencies); + artifact.Dependencies = dependencies; + + return artifact; + } + + private ExampleArtifact Map(GuidUdi udi, Example entity, ICollection dependencies) + { + var artifact = new ExampleArtifact(udi); + artifact.Description = example.Description; + return artifact; + } + + private string[] ValidOpenSelectors => new[] + { + DeploySelector.This, + DeploySelector.ThisAndDescendants, + DeploySelector.DescendantsOfThis + }; + private const string OpenUdiName = "All Examples"; + + public override void Explode(UdiRange range, List udis) + { + EnsureType(range.Udi); + + if (range.Udi.IsRoot) + { + EnsureSelector(range, ValidOpenSelectors); + udis.AddRange(_exampleDataService.GetExamples().Select(e => e.GetUdi())); + } + else + { + var entity = _exampleDataService.GetExampleById(((GuidUdi)range.Udi).Guid); + if (entity == null) + { + return; + } + + EnsureSelector(range.Selector, DeploySelector.This); + udis.Add(entity.GetUdi()); + } + } + + public override NamedUdiRange GetRange(string entityType, string sid, string selector) + { + if (sid == "-1") + { + EnsureSelector(selector, ValidOpenSelectors); + return new NamedUdiRange(Udi.Create("mypackage-example"), OpenUdiName, selector); + } + + if (!Guid.TryParse(sid, out Guid id)) + { + throw new ArgumentException("Invalid identifier.", nameof(sid)); + } + + var entity = _exampleDataService.GetExampleById(id); + if (entity == null) + { + throw new ArgumentException("Could not find an entity with the specified identifier.", nameof(sid)); + } + + return GetRange(entity, selector); + } + + public override NamedUdiRange GetRange(GuidUdi udi, string selector) + { + EnsureType(udi); + + if (udi.IsRoot) + { + EnsureSelector(selector, ValidOpenSelectors); + return new NamedUdiRange(udi, OpenUdiName, selector); + } + + var entity = _exampleDataService.GetExampleById(udi.Guid); + if (entity == null) + { + throw new ArgumentException("Could not find an entity with the specified identifier.", nameof(udi)); + } + + return GetRange(entity, selector); + } + + private static NamedUdiRange GetRange(Example e, string selector) => new NamedUdiRange(e.GetUdi(), e.Name, selector); + + public override ArtifactDeployState ProcessInit(ExampleArtifact art, IDeployContext context) + { + EnsureType(art.Udi); + + var entity = _exampleDataService.GetExampleById(art.Udi.Guid); + + return ArtifactDeployState.Create(art, entity, this, 1); + } + + public override void Process(ArtifactDeployState state, IDeployContext context, int pass) + { + switch (pass) + { + case 1: + Pass1(state, context); + state.NextPass = 2; + break; + default: + state.NextPass = -1; // exit + break; + } + } + + private void Pass1(ArtifactDeployState state, IDeployContext context) + { + var artifact = state.Artifact; + + artifact.Udi.EnsureType("mypackage-example"); + + var isNew = state.Entity == null; + + var entity = state.Entity ?? new Example { Id = artifact.Udi.Guid }; + + entity.Name = artifact.Name; + entity.Description = artifact.Description; + + if (isNew) + { + _exampleDataService.AddExample(entity); + } + else + { + _exampleDataService.UpdateExample(entity); + } + } +} +``` + +It's also necessary to provide an extension method to generate the appropriate identifier: + +```csharp +public static GuidUdi GetUdi(this Example entity) +{ + if (entity == null) throw new ArgumentNullException("entity"); + return new GuidUdi("mypackage-example", entity.Id).EnsureClosed(); +} +``` + +#### Handling Dependencies + +Umbraco entities often have dependencies on one another, this may also be the case for any custom data you are looking to deploy. If so, you can add the necessary logic to your service connector to ensure dependencies are added. This will ensure Umbraco Deploy also ensures the appropriate dependencies are in place before initiating a transfer. + +If the dependent entity is also deployable, it will be included in the transfer. Or if not, the deployment will be blocked and the reason presented to the user. + +In the following illustrative example, if deploying a representation of a "Person", we ensure their "Department" dependency is added. This will indicate that it must exist to allow the transfer. We can also use `ArtifactDependencyMode.Match` to ensure the dependent entity not only exists but also matches in all properties. + +```csharp +private PersonArtifact Map(GuidUdi udi, Person person, ICollection dependencies) +{ + var artifact = new PersonArtifact(udi) + { + Alias = person.Name, + Name = person.Name, + DepartmentId = person.Department.Id, + }; + + // Department node must exist to deploy the person. + dependencies.Add(new ArtifactDependency(person.Department.GetUdi(), true, ArtifactDependencyMode.Exist)); + + return artifact; +} +``` + +### Value Connectors + +As well as dependencies at the level of entities, we can also have dependencies in the property values as well. In Umbraco, an example of this is the multi-node tree picker property editor. It contains references to other content items, that should also be deployed along with the content that hosts the property itself. + +Value connectors are used to track these dependencies and can also be used to transform property data as it is moved between environments. + +The following illustrative example considers a property editor that stores the integer ID of an media item. The integer ID of a media item is not consistent between environments, so we'll need to transform it. And we also want to ensure that the related media item itself is transferred as well as the integer ID reference. + +```c# +using Umbraco.Cms.Core.Deploy; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Deploy.Core.Connectors.ValueConnectors; + +namespace MyExtensions; + +public class MyMediaPropertyValueConnector : ValueConnectorBase +{ + private readonly IEntityService _entityService; + private readonly ILogger _logger; + + public MyMediaPropertyValueConnector(IEntityService entityService, ILogger logger) + { + _entityService = entityService; + _logger = logger; + } + + public override IEnumerable PropertyEditorAliases => new[] { "MyMediaPropertyEditor" }; + + public override string? ToArtifact(object? value, IPropertyType propertyType, ICollection dependencies, IContextCache contextCache) + { + var svalue = value as string; + if (string.IsNullOrWhiteSpace(svalue)) + { + return null; + } + + if (!int.TryParse(svalue, out var intvalue)) + { + return null; + } + + Attempt getKeyAttempt = _entityService.GetKey(intvalue, UmbracoObjectTypes.Media); + + if (getKeyAttempt.Success) + { + var udi = new GuidUdi(Constants.UdiEntityType.Media, getKeyAttempt.Result); + dependencies.Add(new ArtifactDependency(udi, false, ArtifactDependencyMode.Exist)); + + return udi.ToString(); + } + else + { + _logger.LogDebug($"Couldn't convert integer value #{intvalue} to UDI"); + } + + return null; + } + + public override object? FromArtifact(string? value, IPropertyType propertyType, object? currentValue, IContextCache contextCache) + { + if (string.IsNullOrWhiteSpace(value)) + { + return null; + } + + if (!UdiParser.TryParse(value, out GuidUdi? udi) || udi!.Guid == Guid.Empty) + { + return null; + } + + Attempt getIdAttempt = _entityService.GetId(udi.Guid, UmbracoObjectTypes.Media); + + if (!getIdAttempt.Success) + { + return null; + } + + return getIdAttempt.Result.ToString(); + } +} +``` + +## Registration + +With the artifact and connectors in place, the final step necessary is to register your entity for deployment. + +Connectors do not need to be registered. The fact that they inherit from particular interfaces known to Umbraco Deploy is enough to ensure that they will be used. + +### Custom Entity Types + +If custom entity types are introduced that will be handled by Umbraco Deploy, they need to be registered with Umbraco to parse the UDI references. + +This is done via the following code, which can be triggered from a Umbraco component or an `UmbracoApplicationStartingNotification` handler. + +``` +UdiParser.RegisterUdiType("mypackage-example", UdiType.GuidUdi); +``` + +### Disk Based Transfers + +To deploy the entity as schema, via disk based representations held in `.uda` files, it's necessary to register the entity with the disk entity service. This is done in a component, where events are used to trigger a serialization of the entity to disk whenever one of them is saved. + +```csharp +public class ExampleDataDeployComponent : IComponent +{ + private readonly IDiskEntityService _diskEntityService; + private readonly IServiceConnectorFactory _serviceConnectorFactory; + private readonly IExampleDataService _exampleDataService; + + public ExampleDataDeployComponent( + IDiskEntityService diskEntityService, + IServiceConnectorFactory serviceConnectorFactory, + IExampleDataService exampleDataService) + { + _diskEntityService = diskEntityService; + _serviceConnectorFactory = serviceConnectorFactory; + _exampleDataService = exampleDataService; + } + + public void Initialize() + { + _diskEntityService.RegisterDiskEntityType("mypackage-example"); + _exampleDataService.ExampleSaved += ExampleOnSaved; + } + + private void ExampleOnSaved(object sender, ExampleEventArgs e) + { + var artifact = GetExampleArtifactFromEvent(e); + _diskEntityService.WriteArtifacts(new[] { artifact }); + } + + private IArtifact GetExampleArtifactFromEvent(ExampleEventArgs e) + { + var udi = e.Example.GetUdi(); + return _serviceConnectorFactory.GetConnector(udi.EntityType).GetArtifact(e.Example); + } + + public void Terminate() + { + } +} +``` + +#### Including Plugin Registered Disk Entities in the Schema Comparison Dashboard + +In Umbraco Deploy 9.4 a schema comparison feature was added to the dashboard available under _Settings > Deploy_. This lists the Deploy managed entities held in Umbraco and shows a comparison with the data held in the `.uda` files on disk. + +All core Umbraco entities, such as Document Types and Data Types, will be shown. + +To include entities from plugins, they need to be registered using a method overload as shown above, that allows to provide additional detail, e.g.: + +```csharp +_diskEntityService.RegisterDiskEntityType( + "mypackage-example", + "Examples", + false, + _exampleDataService.GetAll().Select(x => new DeployDiskRegisteredEntityTypeDetail.InstalledEntityDetail(x.GetUdi(), x.Name, x)))); +``` + +The parameters are as follows: + +* The system name of the entity type (as used in the `UdiDefinition` attribute). +* A human readable, pluralized name for display in the schema comparison dashboard user interface. +* A flag indicating whether the entity is an Umbraco one, which should be set to `false`. +* A function that returns all entities of the type installed in Umbraco, mapped to an object exposing the Udi and name of the entity. + +### Backoffice Integrated Transfers + +If the optimal deployment workflow for your entity is to have editors control the deployment operations, the transfer entity service should be used. This would be instead of registering with the disk entity service. The process is similar, but a bit more involved. There's a need to also register details of the tree being used for editing the entities. In more complex cases, we also need to be able to handle the situation where multiple entity types are managed within a single tree. + +An introduction to this feature can be found in the second half of [this recorded session from Codegarden 2021](https://youtu.be/8bgZmlJ7ScI?t=938). + +There's also a code sample, demonstrated in the video linked above, available [here](https://github.com/AndyButland/RaceData). + +The following code shows the registration of an entity for Backoffice deployment, where we have the simplest case of a single tree for the entity. + +```csharp +public class ExampleDataDeployComponent : IComponent +{ + private readonly ITransferEntityService _transferEntityService; + private readonly IExampleDataService exampleDataService; + + public ExampleDataDeployComponent( + ITransferEntityService transferEntityService, + IExampleDataService exampleDataService) + { + _transferEntityService = transferEntityService; + _exampleDataService = exampleDataService; + } + + public void Initialize() + { + _transferEntityService.RegisterTransferEntityType( + "mypackage-example", + "Examples", + new DeployRegisteredEntityTypeDetailOptions + { + SupportsQueueForTransfer = true, + SupportsQueueForTransferOfDescendents = true, + SupportsRestore = true, + PermittedToRestore = true, + SupportsPartialRestore = true, + }, + false, + "exampleTreeAlias", + (string routePath, HttpContext httpContext) => true, + (string nodeId, HttpContext httpContext) => true, + (string nodeId, HttpContext httpContext, out Guid entityId) => Guid.TryParse(nodeId, out entityId), + new DeployRegisteredEntityTypeDetail.RemoteTreeDetail(FormsTreeHelper.GetExampleTree, "example", "externalExampleTree"), + entitiesGetter: () => _exampleDataService.Get()); + } + + public void Terminate() + { + } +} +``` + +The `RegisterTransferEntityType` method on the `ITransferEntityService` takes the following parameters: + +* The name of the entity type, as configured in the `UdiDefinition` attribute associated with your custom service connector. +* A pluralized, human-readable name of the entity, which is used in the transfer queue visual presentation to users. +* A set of options, allowing configuration of whether different deploy operations like queue for transfer and partial restore are made available from the tree menu for the entity. +* A value indicating whether the entity is an Umbraco entity, queryable via the `IEntityService`. For custom solutions and packages, the value to use here is always `false`. +* The alias of the tree used for creating and editing the entity data. + +We then have three functions, which are used to determine if the registered entity matches a specific node and tree alias. For trees managing single entities as we have here, we know that all nodes related to that tree alias will be for the registered entity. And that each node Id is the Guid identifier for the entity. Hence we can use the following function definitions: + +* Return `true` for all route paths. +* Return `true` for all node Ids. +* Return `true` and parse the Guid identity value from the provided string. + +For more complex cases we need the means to distinguish between entities. An example could be when a tree manages more than one entity type. Here we would need to identify whether the entity is being referenced by a particular route path or node ID. A common way to handle this is to prefix the GUID identifier with a different value for each entity. It can then be used to determine to which entity the value refers. + +For example, as shown in the linked sample and video, we have entities for "Team" and "Rider", both managed in the same tree. When rendering the tree, a prefix of "team-" or "rider-" is added to the Guid identifier for the team or rider respectively. We then register the following functions, firstly for the team entity registration: + +```csharp +_transferEntityService.RegisterTransferEntityType( + ... + "teams", + (string routePath, HttpContext httpContext) => routePath.Contains($"/teamEdit/") || routePath.Contains($"/teamsOverview"), + (string nodeId, HttpContext httpContext) => nodeId == "-1" || nodeId.StartsWith("team-"), + (string nodeId, HttpContext httpContext, out Guid entityId) => Guid.TryParse(nodeId.Substring("team-".Length), out entityId); +``` + +And then for the rider: + +```csharp +_transferEntityService.RegisterTransferEntityType( + ... + "teams", + (string routePath) => routePath.Contains($"/riderEdit/"), + (string nodeId) => nodeId.StartsWith("rider-"), + (string nodeId, HttpContext httpContext, out Guid entityId) => Guid.TryParse(nodeId.Substring("rider-".Length), out entityId); +``` + +If access to services is required when parsing the entity ID, where the `HttpContext` is provided as a parameter, a service can be retrieved. For example: + +```csharp +var localizationService = httpContext.RequestServices.GetRequiredService(); +``` + +The `remoteTree` optional parameter adds support for plugins to implement Deploy's "partial restore" feature. This gives the editor the option to select an item to restore, from a tree picker displaying details from a remote environment. The parameter is of type `DeployRegisteredEntityTypeDetail.RemoteTreeDetail` that defines three pieces of information: + +* A function responsible for returning a level of a tree. +* The name of the entity (or entities) that can be restored from the remote tree. +* The remote tree alias. + +An example function that returns a level of a remote tree may look like this: + +```csharp +public static IEnumerable GetExampleTree(string parentId, HttpContext httpContext) +{ + var exampleDataService = httpContext.RequestServices.GetRequiredService(); + var items = exampleDataService.GetItems(parentId); + return items + .Select(x => new RemoteTreeNode + { + Id = x.Id,, + Title = x.Name, + Icon = "icon-box", + ParentId = parentId, + HasChildren = true, + }) + .ToList(); +} +``` + +Finally, the `entitiesGetter` parameter allows you to pass a function that will return all entities for the registered type. This is necessary to allow support for the "set signatures" operation available via the backoffice settings dashboard. By providing a function that returns the collection of entities, the triggered operation will be able to prepare the signature for each one. + +To complete the setup for partial restore support, an external tree controller needs to be added, attributed to match the registered tree alias. Using a base class available in `Umbraco.Deploy.Forms.Tree`, this can look like the following: + +```csharp +[Tree(DeployConstants.SectionAlias, "externalExampleTree", TreeUse = TreeUse.Dialog)] +public class ExternalDataSourcesTreeController : ExternalTreeControllerBase +{ + public ExternalDataSourcesTreeController( + ILocalizedTextService localizedTextService, + UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, + IEventAggregator eventAggregator, + IExtractEnvironmentInfo environmentInfoExtractor, + LinkGenerator linkGenerator, + ILoggerFactory loggerFactory, + IOptions deploySettings) + : base(localizedTextService, umbracoApiControllerTypeCollection, eventAggregator, environmentInfoExtractor, linkGenerator, loggerFactory, deploySettings, "mypackage-example") + { + } +} +``` + +#### Client-Side Registration + +Most features that are available for the deployment of Umbraco entities will also be accessible to entities defined in custom solutions or packages. The "Transfer Now" option available from "Save and Publish" or "Save" button for content/media is only available to custom entities if requested client-side. + +You would do this in the custom AngularJS controller responsible for handling the edit operations on your entity. Inject the `pluginEntityService` and calling the `addInstantDeployButton` function as shown in the following stripped down sample (for the full code, see the sample data repository linked above): + +```js +(function () { + "use strict"; + + function MyController($scope, $routeParams, myResource, formHelper, notificationsService, editorState, pluginEntityService) { + + var vm = this; + + vm.page = {}; + vm.entity = {}; + ... + + vm.page.defaultButton = { + alias: "save", + hotKey: "ctrl+s", + hotKeyWhenHidden: true, + labelKey: "buttons_save", + letter: "S", + handler: function () { vm.save(); } + }; + vm.page.subButtons = []; + + function init() { + + ... + + if (!$routeParams.create) { + + myResource.getById($routeParams.id).then(function (entity) { + + vm.entity = entity; + + // Augment with additional details necessary for identifying the node for a deployment. + vm.entity.metaData = { treeAlias: $routeParams.tree }; + + ... + }); + } + + pluginEntityService.addInstantDeployButton(vm.page.subButtons); + } + + ... + + init(); + + } + + angular.module("umbraco").controller("MyController", MyController); + +})(); +``` + +### Refreshing Signatures + +Umbraco Deploy improves the efficiency of transfers by caching signatures of each artifacts in the database for each environment. The signature is a string based, hashed representation of the serialized artifact. When an update is made to an entity, this signature value should be refreshed. + +Hooking this up can be achieved by applying code similar to the following, extending the `ExampleDataDeployComponent` shown above. + +```csharp +public class ExampleDataDeployComponent : IComponent +{ + ... + private readonly ISignatureService _signatureService; + + public ExampleDataDeployComponent( + ... + ISignatureService signatureService) + { + _signatureService = signatureService; + } + + public void Initialize() + { + ... + _signatureService.RegisterHandler(nameof(IExampleDataService.ExampleSaved), (refresher, args) => refresher.SetSignature(GetExampleArtifactFromEvent(args))); + } + + ... +} +``` diff --git a/14/umbraco-deploy/extending/handling-cache-refresher-notifications.md b/14/umbraco-deploy/extending/handling-cache-refresher-notifications.md new file mode 100644 index 00000000000..d7ea9a6480e --- /dev/null +++ b/14/umbraco-deploy/extending/handling-cache-refresher-notifications.md @@ -0,0 +1,166 @@ +--- +description: How to respond to deployment events using cache refresher notifications +--- + +# Handling Cache Refresher Notifications + +## Background + +When you deploy content or other Umbraco data between environments, some notifications that are normally fired in CMS operations are suppressed. + +For example, you may handle a `ContentPublishedNotification` to apply some custom logic when a content item is published. This code will run in a normal CMS publish operation. However, when deploying a content item into another environment and triggering it's publishing there, the notification will not be issued. And the custom logic in the notification handler will not run. + +This behavior is deliberate and done for performance and reliability reasons. A normal save and publish operation by an editor operates on one item at a time. With deployments, we may have many, and publishing these notifications may lead to at best slow operations, and at worst inconsistent data. + +The notification will also already be published on the environment where the actual operation was carried out. So repeating this with each content transfer might also result in unwanted behavior. + +However, what if you do want to run some code on an update, even if this is happening as part of a Deploy operation? + +Not all notifications are suppressed by Umbraco Deploy. Some are batched and fired after the deploy operation is complete. These include those related to refreshing the Umbraco cache and rebuilding indexes. + +You can use these cache refresher notifications to handle operations that should occur after a deployment is completed. All notification issued by the CMS are made available. So when deploying a set of content items, a refresher notification will be issued for each. + +## Implementing a Cache Refresher Notification + +The following two code samples illustrate how this can be done. + +The first handles a content cache refresher, which takes a payload from where the content ID can be extracted. Using that the content can be retrieved in the local Umbraco instance and used as appropriate. + +For more details and further examples, please see the [CMS Cache Refresher Notifications documentation](https://docs.umbraco.com/umbraco-cms/reference/notifications/cacherefresher-notifications). + +```csharp +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Sync; + +namespace TestSite.Business.NotificationHandlers; + +public class ContentCacheRefresherNotificationHandler : INotificationHandler +{ + private readonly ILogger _logger; + private readonly IContentService _contentService; + + public ContentCacheRefresherNotificationHandler( + ILogger logger, + IContentService contentService) + { + _logger = logger; + _contentService = contentService; + } + + public void Handle(ContentCacheRefresherNotification notification) + { + // We only want to handle the RefreshByPayload message type. + if (notification.MessageType != MessageType.RefreshByPayload) + { + return; + } + + // Cast the payload to the expected type. + var payload = (ContentCacheRefresher.JsonPayload[])notification.MessageObject; + + // Handle each content item in the payload. + foreach (ContentCacheRefresher.JsonPayload item in payload) + { + // Retrieve the content item. + var contentItemId = item.Id; + IContent? contentItem = _contentService.GetById(contentItemId); + if (contentItem is null) + { + _logger.LogWarning( + "ContentCacheRefresherNotification handled for type {MessageType} but content item with Id {Id} could not be found.", + notification.MessageType, + contentItemId); + return; + } + + // Do something with the content item. Here we'll just log some details. + _logger.LogInformation( + "ContentCacheRefresherNotification handled for type {MessageType} and id {Id}. " + + "Key: {Key}, Name: {Name}", + notification.MessageType, + contentItemId, + contentItem.Key, + contentItem.Name); + } + } +} +``` + +The second example is similar, but handles an update to a dictionary item. With this one we get a parameter that consists of the item's ID. Again we can retrieve it and carry out some further processing. + +```csharp +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Sync; + +namespace TestSite.Business.NotificationHandlers; + +public class DictionaryCacheRefresherNotificationHandler : INotificationHandler +{ + private readonly ILogger _logger; + private readonly ILocalizationService _localizationService; + + public DictionaryCacheRefresherNotificationHandler( + ILogger logger, + ILocalizationService localizationService) + { + _logger = logger; + _localizationService = localizationService; + } + + public void Handle(DictionaryCacheRefresherNotification notification) + { + // We only want to handle the RefreshById message type. + if (notification.MessageType != MessageType.RefreshById) + { + return; + } + + // Retrieve the dictionary item. + var dictionaryItemId = (int)notification.MessageObject; + IDictionaryItem? dictionaryItem = _localizationService.GetDictionaryItemById(dictionaryItemId); + if (dictionaryItem is null) + { + _logger.LogWarning( + "DictionaryCacheRefresherNotification handled for type {MessageType} but dictionary item with Id {Id} could not be found.", + notification.MessageType, + dictionaryItemId); + return; + } + + // Do something with the dictionary item. Here we'll just log some details. + _logger.LogInformation( + "DictionaryCacheRefresherNotification handled for type {MessageType} and id {Id}. " + + "Key: {Key}, Default Value: {DefaultValue}", + notification.MessageType, + dictionaryItemId, + dictionaryItem.ItemKey, + dictionaryItem.GetDefaultValue()); + } +} +``` + +In both cases, as is usual for notification handlers, you will need to register them via a composer: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Notifications; +using TestSite.Business.NotificationHandlers; + +namespace TestSite.Business; + +public class SiteComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.AddNotificationHandler(); + builder.AddNotificationHandler(); + } +} +``` diff --git a/14/umbraco-deploy/getting-started/Streamlining-Local-Development/index.md b/14/umbraco-deploy/getting-started/Streamlining-Local-Development/index.md new file mode 100644 index 00000000000..922f749f037 --- /dev/null +++ b/14/umbraco-deploy/getting-started/Streamlining-Local-Development/index.md @@ -0,0 +1,40 @@ +--- +description: "Additional steps you can carry out to streamline your local development workflow" +--- + +# Streamlining Local Development + +In this section we discuss some additional steps you can carry out to streamline your local development workflow. + +## Creating Git Hooks + +Working in a team, it's common for developers to pull code from source control to update their local environment with the latest Umbraco schema. + +They can do this by starting up the website, navigating to the _Settings > Deploy_ dashboard and triggering a data extraction. + +We can automate this step using a [git hook](https://www.atlassian.com/git/tutorials/git-hooks). + +When working with Umbraco Cloud, this step is configured automatically for you when you clone and run your project the first time. If working with Umbraco Deploy On-Premise, you can set it up yourself. + +The process works by using the marker file Umbraco Deploy uses to trigger an update of the Umbraco schema from the `.uda` files from source control. + +If a file named `deploy-on-start` is found in the `/umbraco/Deploy` folder, an update will run automatically when the site starts up. + +Therefore, if we ensure that the file is created everytime the source code is pulled from the remote repository, we can automate the update. + +To do this, carry out the following steps: + +- Find the `.git` folder within your solution root. + - It might be a hidden folder, so if you don't see it, make sure your file browser is configured to show hidden files and folders. +- Within that you'll find a `hooks` folder, and inside that, a file called `post-merge.sample`. +- Rename the file to remove the `.sample` extension and open it in a text editor. +- Apply the following text and save the file (amending the path to the web project as appropriate for your solution structure): + +```sh +#!/bin/sh +echo > src/UmbracoProject/umbraco/Deploy/deploy-on-start +``` + +- Run a `git pull origin `. +- Start up the website and you should find the Umbraco schema update has been triggered. + diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/README.md b/14/umbraco-deploy/getting-started/cicd-pipeline/README.md new file mode 100644 index 00000000000..fd0e7d33a39 --- /dev/null +++ b/14/umbraco-deploy/getting-started/cicd-pipeline/README.md @@ -0,0 +1,45 @@ +--- +description: >- + Steps and examples on how Umbraco Deploy can be integrated into an automated + build and deployment pipeline +--- + +# CI/CD Build and Deployment Pipeline + +Once Umbraco Deploy has been installed and the schema data has been generated, a CI/CD build server needs to be set up. + +The build server will extract the changes that has been pushed to the repository into your production website that has been connected with Umbraco Deploy. + +This is something that can be done in many different ways depending on where your website is hosted and your setup. + +Umbraco Deploy does not require the use of any particular build or deployment tools and hence we expect that you should be able to continue using the tool or tools of your choice. Any that have support for .NET website deployments and the running of Powershell scripts. such as Azure DevOps or GitHub Actions, would be appropriate. + +Above and beyond the normal steps of a build pipeline for a .NET web application - tasks like NuGet restore, solution build, running of tests etc. - Umbraco Deploy requires three additional steps. + +* The license file needs to be deployed into the target environment's `umbraco/Licenses` folder. +* The `.uda` schema files that are written to disk and included in source control, need to be made available in the build artifact that is deployed to the target environment. +* Once the build is complete, the extraction of the updated schema in the target environment needs to be triggered. + +The first two steps will be implemented in a similar way. There will need to be a step added to the pipeline that runs after the main build of the website, to copy the license file and data files into the published build output, such that they are included in the build artifacts that are deployed to the target environment. + +The third step needs to run last in the pipeline, once the built web application is deployed to the target environment. Umbraco Deploy provides a Powershell script that can be used for the purpose of triggering the extraction of the schema information and update of the target Umbraco installation. + +## Background on the Schema Extraction Process + +Without a CI/CD pipeline step in place to trigger the extraction, following a deployment, the process would need to be carried out manually. This can be done by logging into the backoffice, navigating to _Settings > Deploy_ and triggering the operation via the dashboard. + +Behind the scenes what happens here is a marker file being written to disk - in the `/umbraco/Deploy/` folder and with a name of `deploy`. It’s by monitoring this directory for a file with this name that Umbraco Deploy knows to trigger the extraction. + +Umbraco Deploy also provides an HTTPS endpoint that can be called by an authenticated request. This will write the marker file, which will trigger the extraction. + +Umbraco Deploy On-Premises also ships with a Powershell script, that when executed will call the endpoint, which will write the file, and which will trigger the extraction. + +So while it may be possible to have the CI/CD step directly write the file or call the endpoint, so long as the build used supports running Powershell scripts this is the method we’d recommend, as it has some necessary error checking and retry logic built-in. + +## [Setting up CI/CD pipeline with GitHub Actions](ci-cd-github-actions.md) + +Details the setup of a CI/CD pipeline using GitHub Actions. + +## [Setting up CI/CD pipeline with Azure DevOps](ci-cd-azure-dev-ops.md) + +Details the setup of a CI/CD pipeline using Azure DevOps. diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/ci-cd-azure-dev-ops.md b/14/umbraco-deploy/getting-started/cicd-pipeline/ci-cd-azure-dev-ops.md new file mode 100644 index 00000000000..71082522aa6 --- /dev/null +++ b/14/umbraco-deploy/getting-started/cicd-pipeline/ci-cd-azure-dev-ops.md @@ -0,0 +1,105 @@ +--- +description: "Steps and examples on how to setup a build and deployment pipeline for Umbraco Deploy using Azure DevOps." +--- + +# Azure DevOps + +In this section, we provide a full example of how Umbraco Deploy running on Umbraco 9 and above can be utilized. This can be used as a part of a build and deployment pipeline using Azure DevOps. You can use this directly or adapt it for your needs. + +## Discussion on the Provided Example + +We have defined a single stage build and deployment pipeline, configured in YAML format. While not as visually intuitive as a drag-and-drop task list, it provides the advantage of source control management. + +We then have a number of variables defined, that are used in the build configuration below. By using variables we have the ability to modify the script for use on other web applications. Some values are set in the script, and some via Azure DevOps variables or secrets. + +Most tasks in the pipeline are standard steps that will be used in any .NET web application release, such as the first steps: + +\#1 Install of the NuGet tooling, + +\#2 Restore of NuGet dependencies, + +\#3 And the project build. + +Additional steps can be added as required, for example for running automated tests. + +The Umbraco Deploy license file and the schema data files will automatically be included within the build output. + +The deployment part of the pipeline stage consists of two steps. + +Firstly a web deployment (#4), takes the packaged build artifact and deploys it, in this case, to an Azure Web App slot. + +The final step (#5) is Umbraco Deploy specific - to call a function defined in the PowerShell script and trigger the extraction. Replace `ApiSecret` with `ApiKey` if you're using the deprecated API key setting instead. + +{% hint style="info" %} +The Microsoft docs contain useful information, if you are unsure of how to set secrets for your pipeline: +* [Set secret variables](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-secret-variables?view=azure-devops&tabs=yaml%2Cbash) + +* [Protecting secrets in Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/security/secrets?view=azure-devops) +{% endhint %} + +## Full Example + +```yaml +trigger: +- main + +pool: + vmImage: 'windows-latest' + +variables: + solution: '**/*.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + + vsSolutionName: DeployOnPremSite + vsProjectName: DeployOnPremSite + umbracoDeployTriggerDeploy: $(Build.SourcesDirectory)\$(vsSolutionName)\$(vsProjectName)\TriggerDeploy.ps1 + umbracoDeployReason: AzureDeployment + + deployApiSecret: + azureSubscription: + webAppName: + resourceGroupName: + deploySlotName: + deployBaseUrl: + +steps: +#1 NuGet Tool Install +- task: NuGetToolInstaller@1 + displayName: Install NuGet + +#2 NuGet Restore +- task: NuGetCommand@2 + displayName: Restore NuGet packages + inputs: + restoreSolution: '$(solution)' + +#3 Build the VS Solution and publish the output to a zip file +- task: VSBuild@1 + displayName: Build solution + inputs: + solution: '$(solution)' + msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +#4 Deploy to an Azure web app slot +- task: AzureRmWebAppDeployment@4 + displayName: Deploy to web app + inputs: + ConnectionType: 'AzureRM' + azureSubscription: '$(azureSubscription)' + appType: 'webApp' + WebAppName: '$(webAppName)' + deployToSlotOrASE: true + ResourceGroupName: '$(resourceGroupName)' + SlotName: '$(deploySlotName)' + packageForLinux: '$(build.artifactStagingDirectory)\WebApp.zip' + +#5 Trigger the Umbraco Deploy extraction +- task: PowerShell@2 + displayName: Run PowerShell script + inputs: + filePath: '$(umbracoDeployTriggerDeploy)' + arguments: '-InformationAction:Continue -Action TriggerWithStatus -ApiSecret $(deployApiSecret) -BaseUrl $(deployBaseUrl) -Reason $(umbracoDeployReason) -Verbose' +``` diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/ci-cd-github-actions.md b/14/umbraco-deploy/getting-started/cicd-pipeline/ci-cd-github-actions.md new file mode 100644 index 00000000000..da1103674f1 --- /dev/null +++ b/14/umbraco-deploy/getting-started/cicd-pipeline/ci-cd-github-actions.md @@ -0,0 +1,165 @@ +--- +description: >- + Steps and examples on how to setup a build and deployment pipeline for Umbraco + Deploy using GitHub Actions. +--- + +# GitHub Actions + +{% hint style="info" %} +In this example we will show how you can set up a CI/CD build server using GitHub Actions in Azure Web Apps. + +We will not cover how you can set up the site itself as this is beyond this documentation. +{% endhint %} + +The following steps will take you through setting up a build server in Azure Web Apps. Go to the Azure portal and find the empty website that we have set up and want to connect to. + +1. Go to the Deployment Center. + +![Azure deployments](<../../../../10/umbraco-deploy/getting-started/images/Deployment-center (1) (1).png>) + +In the Deployment Center we can set up the CI/CD build server. With this example we are going to set up our build server by using GitHub Actions. It is possible to set up the build server however you want as long as it supports executing powershell scripts. + +2. Go to the Settings tab. +3. Choose which source and build provider to use. + * In this case we want to choose GitHub. + +![Build server clean](./images/Build-server-v10.png) + +4. Choose the Organization which you created our GitHub repository under. +5. Choose the repository that was set up earlier in this guide. +6. Select which branch that we want the build server to build into. + +We can see which runtime stack and version we are running, in this example we are running .NET and Version 6.0. + +Once the information has been added we can go ahead and preview the YAML file that will be used for the build server: + +![Workflow configuration](./images/workflow-preview-v10.png) + +7. Save the workflow. + +The website and the GitHub repository are now connected. + +If we go back to the GitHub repository we can see that a new folder have been created called Workflows: + +![Workflows](<../../../../10/umbraco-deploy/getting-started/images/workflows (1).png>) + +Inside the folder, we find that the YAML file has been created with the default settings from the Azure Portal. The file will need to be configured so it fits into your set up. + +8. Pull down the new file and folder, so you can work with the YAML file on your local machine. +9. Configure it to work with our Umbraco Deploy installation. + +When it have been configured it will look something like this: + +```yaml +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions +name: Build and deploy ASP.Net Core app to Azure Web App - Jonathan-deploy-v10 +on: + push: + branches: + - main + workflow_dispatch: +jobs: + build: + runs-on: windows-latest + steps: + - name: Checkout the git repository + uses: actions/checkout@v3 + - name: Setup dotnet 6 + uses: actions/setup-dotnet@v2 + with: + dotnet-version: '6.0.x' + - name: Build with dotnet + working-directory: 'Jonathan-Deploy-V10' + run: dotnet build --configuration Release + - name: Publish with dotnet + working-directory: 'Jonathan-Deploy-V10' + run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v4 + with: + name: .net-app + path: ${{env.DOTNET_ROOT}}/myapp + deploy: + runs-on: windows-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + env: + deployBaseUrl: https://jonathan-testing-deploy-v10.testsite.net + umbracoDeployReason: DeployingMySite + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: .net-app + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v2 + with: + app-name: 'Jonathan-Deploy-V10' + slot-name: 'Production' + publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_ABC78A5A9E9FG07F87E8R5G9H9J0J7J8 }} + package: . + - name: Run Deploy Powershell - triggers deployment on remote env + shell: powershell + run: .\TriggerDeploy.ps1 -InformationAction:Continue -Action TriggerWithStatus -ApiSecret ${{ secrets.deployApiSecret }} -BaseUrl ${{ env.deployBaseUrl }} -Reason ${{ env.umbracoDeployReason }} -Verbose +``` + +{% hint style="info" %} +This is only an example of how you can set up the CI/CD pipeline for Umbraco Deploy. It is possible to set it up in a way that works for you and your preferred workflow. +{% endhint %} + +We also need to add the License file and `TriggerDeploy.ps1` file in an item group in the `csproj` file: + +``` + + + + +``` + +As well as enabling Unattended install in the **appsettings.json** file so Umbraco installs automatically: + +``` +{ + "Umbraco": { + "CMS": { + "Unattended": { + "InstallUnattended": true + } + } + } +} +``` + +Before the build can work, we will need to set up our generated API key to work with the build server in GitHub Actions. + +1. Open your GitHub repository. +2. Navigate to Settings. +3. Go to the Secrets tab. +4. Select "New repository secret". +5. Call the new secret **"DEPLOYAPISECRET"**. +6. Add the API secret from the `appsettings.json` file (replace `ApiSecet` with `ApiKey` in the script and use the corresponding value if you're using the deprecated API key setting instead). +7. Save the secret. + +We can now go ahead and commit the configured YAML file and push up all the files to the repository. + +Go to GitHub where you will now be able to see that the CI/CD build has started running: + +![Deployment build started](<../../../../10/umbraco-deploy/getting-started/images/Deploying-meta-data (1).png>) + +The build server will go through the steps in the YAML file, and once it is done the deployment have gone through successfully: + +![Deployment Complete](<../../../../10/umbraco-deploy/getting-started/images/deployment-complete (1) (1).png>) + +You can now start creating content on the local machine. Once you create something like a Document Type, the changes will get picked up in Git. + +When you're done making changes, commit them and deploy them to GitHub. The build server will run and extract the changes into the website in Azure. + +This will only deploy the schema data for our local site to your website. + +You will need to transfer content and media from the backoffice on your local project using the [queue for transfer feature](../../deployment-workflow/content-transfer.md). diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-clean.png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-clean.png new file mode 100644 index 00000000000..e20e5e6b8a8 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-clean.png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10 (1) (1) (1).png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10 (1) (1) (1).png new file mode 100644 index 00000000000..80026302be3 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10 (1) (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10 (1) (1).png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10 (1) (1).png new file mode 100644 index 00000000000..80026302be3 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10 (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10 (1).png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10 (1).png new file mode 100644 index 00000000000..80026302be3 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10 (1).png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10.png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10.png new file mode 100644 index 00000000000..80026302be3 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Build-server-v10.png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/Deploying-meta-data.png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Deploying-meta-data.png new file mode 100644 index 00000000000..3f74a18335e Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Deploying-meta-data.png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/Deployment-center.png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Deployment-center.png new file mode 100644 index 00000000000..f47e12edd19 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/Deployment-center.png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/deployment-complete.png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/deployment-complete.png new file mode 100644 index 00000000000..ee12f34a23a Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/deployment-complete.png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10 (1) (1) (1).png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10 (1) (1) (1).png new file mode 100644 index 00000000000..cab06a25845 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10 (1) (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10 (1) (1).png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10 (1) (1).png new file mode 100644 index 00000000000..cab06a25845 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10 (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10 (1).png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10 (1).png new file mode 100644 index 00000000000..cab06a25845 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10 (1).png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10.png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10.png new file mode 100644 index 00000000000..cab06a25845 Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview-v10.png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview.png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview.png new file mode 100644 index 00000000000..78a9a74b67a Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflow-preview.png differ diff --git a/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflows.png b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflows.png new file mode 100644 index 00000000000..2d7956e4a0e Binary files /dev/null and b/14/umbraco-deploy/getting-started/cicd-pipeline/images/workflows.png differ diff --git a/14/umbraco-deploy/getting-started/deploy-settings.md b/14/umbraco-deploy/getting-started/deploy-settings.md new file mode 100644 index 00000000000..a15f3180c5a --- /dev/null +++ b/14/umbraco-deploy/getting-started/deploy-settings.md @@ -0,0 +1,547 @@ +--- +description: >- + Learn about the different settings and configurations available in Umbraco + Deploy. +--- + +# Configuration + +Most configuration for Umbraco Deploy is provided via dotnet configuration. This is most often stored 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`. Umbraco Deploy configuration follows this pattern, i.e.: + +```json +{ + ... + "Umbraco": { + "CMS": { + ... + }, + "Deploy": { + ... + } + } +} +``` + +There are some required settings but most configuration for Umbraco Deploy is optional. In other words, 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 Umbraco Deploy, along with the default values. This will help when you need to provide a different setting to understand where it should be applied. + +```json +{ + ... + "Umbraco": { + "Deploy": { + "Settings": { + "ApiKey": "", + "ApiSecret": "", + "Edition": "Default", + "ExcludedEntityTypes": [], + "RelationTypes" : [], + "ValueConnectors": [], + "SessionTimeout": "0.0:20:00", + "SourceDeployTimeout": "0.0:20:00", + "DatabaseCommandTimeout": "0.0:20:00", + "EnableSignatureCacheReads": true, + "HttpClientTimeout": "0.0:20:00", + "DiskOperationsTimeout": "0.0:05:00", + "SourceDeployBatchSize": null, + "PackageBatchSize": null, + "MaxRequestLength": null, + "AllowIgnoreDependenciesOperations": "None", + "IgnoreBrokenDependenciesBehavior": "Restore", + "AcceptInvalidCertificates": false, + "TransferFormsAsContent": true, + "TransferDictionaryAsContent": false, + "IgnoreMissingLanguagesForDictionaryItems": false, + "SetEmptyDictionaryItemsOnTransfer": true, + "AllowMembersDeploymentOperations": "None", + "TransferMemberGroupsAsContent": false, + "ExportMemberGroups": true, + "ReloadMemoryCacheFollowingDiskReadOperation": false, + "AllowDomainsDeploymentOperations": "None", + "AllowWebhooksDeploymentOperations": "None", + "TrashedContentDeploymentOperations": "Import", + "PostDeploySchemaOperation": "None", + "PreferLocalDbConnectionString": false, + "MediaFileChecksumCalculationMethod": "PartialFileContents", + "NumberOfSignaturesToUseAllRelationCache": 100, + "ContinueOnMediaFilePathTooLongException": false, + "SuppressCacheRefresherNotifications": false, + "ResolveUserInTargetEnvironment": false, + "Suspensions": { + "DiskRead": "All", + "PartialRestore": "All", + "Restore": "All", + "Deploy": "All", + "Import": "All", + "Export": "All" + }, + "HideConfigurationDetails": false, + "HideVersionDetails": false, + "ValidateDependenciesOnImport": true + }, + "ImportOnStartup": { + "Enabled": true, + "Files": ["~/umbraco/Deploy/import-on-startup.zip"], + "FileAction": "Delete", + "WarningsAsErrors": false, + "EntityTypes": [], + "Cultures": [], + "Username": null + } + } + } +} +``` + +Some configuration is applied via code rather than application settings. Where this is the case is also discussed in the sections to follow. + +## Configuration via application settings + +### ApiKey or ApiSecret + +The `ApiKey` is a random string (of at least 10 characters) set to the same value on all environments to authenticate HTTP requests between them. For improved security, set the `ApiSecret` to a cryptographically random value of 64 bytes instead (using Base64-encoding). + +### Edition + +The default value for this setting is `Default`, which configures Umbraco Deploy to work according to how we expect most customers to use the product. Umbraco schema, such as Document and Data Types, are serialized to disk as `.uda` files in save operations. These are checked into source control and used to update the schema in the upstream environments via a trigger from your CI/CD pipeline, or automatically if using Umbraco Cloud. + +Items managed by editors - content, media and optionally forms, dictionary items and members - are deployed between environments using the transfer and restore options available in the backoffice. + +It is possible to use this method for all Umbraco data, by setting the value of this setting to `BackOfficeOnly`. With this in place, all data, including what is typically considered as schema, are available for transfer via the backoffice. + +Our recommended approach is to leave this setting as `Default` and use source control and a deployment pipeline to ensure that structural changes to Umbraco are always aligned with the code and template amends that use them. + +However, we are aware that some customers prefer the option to use the backoffice for all data transfers. If that is the case, the `BackOfficeOnly` setting will allow this. + +### ExcludedEntityTypes {#excludedentitytypes} + +This setting allows you to exclude a certain type of entity from being deployed. This is **not** recommended to set, but sometimes there may be issues with the way a custom media fileprovider works with your site and you will need to set it for media files. Here is an example: + +```json +"ExcludedEntityTypes": ["media-file"], +``` + +### RelationTypes + +This setting allows you to manage how relations are deployed between environments. You will need to specify an alias and a mode for each relation type. The mode can be either: + +* `Exclude` - This causes the relation to be excluded and not transferred on deployments +* `Weak` - This causes the relation to be deployed if both content items are found on the target environment +* `Strong` - This requires the content item that is related is set as a dependency, so if anything is added as a relation it would also add it as a dependency + +```json +"RelationTypes": { + "relateParentDocumentOnDelete": "Weak", + "relateShopItemOnCreate": "Exclude" +}, +``` + +As of Deploy 10.1.2, 11.0.1 and higher, if this setting is left blank, the relation types used for usage tracking are omitted. These relations are rebuilt by the CMS following a save of an item in the target environment and so don't need to be transferred. + +If a particular relation type is not listed, it's considered as a "weak" relation. + +### ValueConnectors + +This setting is used by package creators who want their custom editors to work with Deploy. The packages should be creating this setting automatically. There is a community-driven package that has value connectors for Deploy called [Deploy Contrib](https://github.com/umbraco/Umbraco.Deploy.Contrib). + +Here is an example of how the setting can look: + +```json +"ValueConnectors": { + "nuPickers.DotNetCheckBoxPicker": "Umbraco.Deploy.Contrib.Connectors.ValueConnectors.NuPickersValueConnector, Umbraco.Deploy.Contrib.Connectors" +}, +``` + +### Timeout settings {#timeout-settings} + +Umbraco Deploy has a few built-in timeouts, which on larger sites might need to be modified. You will usually see these timeouts in the backoffice with an exception mentioning a timeout. It will be as part of a full restore or a full deployment of an entire site. In the normal workflow, you should never hit these timeouts. + +There are four settings available relating to backoffice deployment operations: + +* `SessionTimeout` +* `SourceDeployTimeout` +* `HttpClientTimeout` +* `DatabaseCommandTimeout` + +These timeout settings default to 20 minutes, but if you are transferring a lot of data you may need to increase it. + +{% hint style="info" %} +It's important that these settings are added to both the source and target environments in order to work. +{% endhint %} + +A fifth timeout setting is available from Umbraco Deploy 9.5 and 10.1, allowing for the adjustment of the maximum time allowed for disk operations such as schema updates. + +* `DiskOperationsTimeout` + +This setting defaults to 5 minutes. + +All of these times are configured using [standard timespan format strings](https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-timespan-format-strings). + +### Batch settings {#batch-settings} + +Even with appropriate settings of the above timeouts, Deploy's backoffice transfer operations can hit a hard limit imposed by the hosting environment. For Azure, this is around 4 minutes. This will typically only be reached if deploying a considerable amount of items in one go. For example, a media folder with thousands of items can reach this limit. + +An error message of "The remote API has returned a response indicating a platform timeout" will be reported. + +If encountering this issue, there are two batch settings that can be applied with integer values (for example 500). This will cause Deploy to transfer items in batches, up to a maximum size. This will allow each individual batch to complete within the time available. The higher the value, the bigger the batches. + +* `SourceDeployBatchSize` - applies a batch setting for the transfer of multiple selected items to an upstream environment (such as a media folder with many images) +* `PackageBatchSize` - applies a batch setting to the processing of a Deploy "package", which contains all the items selected for a Deploy operation, plus all the determined dependencies and relations + +### MaxRequestLength + +When Deploy transfers files between unconnected environments (like a non-public local environment), it falls back from fetching/downloading the files to uploading them. This is done in fixed-sized chunks, so multiple files can be combined in a single request or a large file into multiple requests. This setting can specify the size of these chunks **(in bytes)**. + +If no value is set, Deploy will create 16MB chunks, unless the [CMS `MaxRequestLength` setting](../../umbraco-cms/reference/configuration/runtimesettings.md) is lower (CMS setting is configured in kilobytes). Setting a value higher than the CMS `MaxRequestLength` (multiplied by 1024) will cause a validation error. Similarly, configuring a value higher than the [server or infrastructure limits](../../umbraco-cms/reference/configuration/maximumuploadsizesettings.md) will result in file transfers failures. + +### TransferFormsAsContent {#transfer-forms-data-as-content} + +In order for Deploy to handle Forms data as content, you'll to ensure the `TransferFormsAsContent` setting is set to `true`. To transfer Forms data as schema, i.e. via .uda files committed to source control, use a value of `false`. + +{% hint style="info" %} +On changing this value from `false` to `true`, make sure to remove any `.uda` files for Forms entities that have already been serialized to disk. These will no longer be updated. By deleting them you avoid any risk of them being processed in the future and inadvertently reverting a form to an earlier state. +{% endhint %} + +### TransferDictionaryAsContent {#transfer-dictionary-items-as-content} + +In a similar way, Deploy can be configured to allow for backoffice transfers of dictionary items instead of using files serialized to disk, by setting `TransferDictionaryAsContent` as `true`. + +Please see the note above under _TransferFormsAsContent_ on the topic of removing any existing serialized files having changed this value to `true`. + +### IgnoreMissingLanguagesForDictionaryItems {#ignore-missing-languages-for-dictionary-items} + +When deploying dictionary items, an exception will be thrown if a translation is provided for a language that doesn't exist in the target environment. + +Normally this is a useful fail-safe to ensure translations aren't lost in the transfer operation. + +If you have deleted languages that have already existing translations, you may want to temporarily remove this check. You can do that by setting this value to `true`. + +When this is in place a translation for a language that doesn't exist in the target environment will be ignored. A warning message will be output to the log. + +### SetEmptyDictionaryItemsOnTransfer {#set-empty-dictionary-items-on-transfer} + +When deploying dictionary items, Umbraco Deploy follows the approach used for all content, emptying values that are transferred and set. + +If you transfer a dictionary item with an empty translation to another environment that already contains a translation, it will be overwritten. + +Set this value to `false` to not overwrite already populated values with empty strings. + +### AllowMembersDeploymentOperations and TransferMemberGroupsAsContent {#transfer-members} + +It's also possible to transfer members and member groups via the backoffice between environments. This is disabled by default as a deliberate decision to make use of the feature needs to be taken, as for most installations it will make sense to have member data created and managed only in production. There are obvious potential privacy concerns to consider too. However, if being able to deploy and restore this information between environments makes sense for the specific workflow of your project, it's a supported scenario. + +To enable, you can add or amend the `AllowMembersDeploymentOperations` and `TransferMemberGroupsAsContent` settings. + +The `AllowMembersDeploymentOperations` setting can take four values: + +* `None` - member deployment operations are not enabled (the default value if the setting is missing) +* `Restore` - restore of members from upstream environments via the backoffice is enabled +* `Transfer` - transfer of members to upstream environments via the backoffice is enabled +* `All` - restore and transfer of members from upstream environments via the backoffice is enabled + +With `TransferMemberGroupsAsContent` set to `true`, member groups can also be transferred via the backoffice, and groups identified as dependencies of members being transferred will be automatically deployed. + +Please see the note above under _TransferFormsAsContent_ on the topic of removing any existing serialized files having changed this value to `true`. + +### ExportMemberGroups {#exporting-member-groups} + +This setting is to be defined and set to `false` only if you are using an external membership provider for your members. You will not want to export Member Groups that would no longer be managed by Umbraco but by an external membership provider. + +Setting `ExportMemberGroups` to `false` will no longer export Member Groups to .uda files on disk. The default for this setting is `true`, as most sites use Umbraco's built-in membership provider and thus will want the membership groups exported. + +### AllowIgnoreDependenciesOperations {#allow-ignore-dependencies} + +When restoring/transferring content or other items, Deploy will ensure any dependencies that don't exist on the target environment are included in the operation. + +Example: You have a media picker on a content item, that references a media item that doesn't exist on the target environment yet. The media item will be created when transferring only that content. This ensures the target environment doesn't end up with broken dependencies (references/links to other items that don't exist). + +When these dependencies are ignored only the selected item(s) are restored/transferred. This allows more control over what is included in the operation. Ignoring dependencies can also help resolve deployment issues with a large amount of content, media, or other items. + +You can configure which operations are allowed to ignore dependencies when these are performed in the backoffice. Ignoring dependencies can result in deployment errors (like parent items that aren't included) or content with broken dependencies. + +* `None` - ignoring dependencies is not allowed (the default value if the setting is missing) +* `Restore` - dependencies can only be ignored when restoring from upstream environments +* `Transfer` - dependencies can only be ignored when transferring upstream environments +* `All` - dependencies can be ignored when restoring from and transferring to upstream environments + +### IgnoreBrokenDependenciesBehavior {#ignore-broken-dependencies} + +When restoring or transferring content, Umbraco Deploy will make checks to ensure that any dependent content, media or other items are either present in the target environment, or can be deployed from the source environment. + +For example, you may have a media picker on a content item, referencing media that has been deleted or is in the recycle bin. In this situation the dependency won't be available in the target environment. + +Deploy can halt at this point, so you get an error and the deployment won't complete until the issue is resolved. To fix, you would need to remove the reference to the deleted media item. + +Alternatively, you can configure Deploy to ignore these issues and proceed with the transfer operation without warning. + +To configure the behavior you prefer, amend this value to either `None`, `Transfer`, `Restore` or `All`. + +For example, using the following settings, you will have an installation that ignores broken dependencies when restoring from an upstream environment. It will however still prevent deployment and report any dependency issues when attempting a transfer to an upstream environment. + +```json +"IgnoreBrokenDependenciesBehavior": "Restore", +``` + +When configuring for Deploy 9, an additional `IgnoreBrokenDependencies` setting existed that took a value of `true` or `false`. To achieve the same result as the example above, the following configuration was required: + +```json +"IgnoreBrokenDependencies": true, +"IgnoreBrokenDependenciesBehavior": "Restore", +``` + +### Memory cache reload {#memory-cache-reload} + +Some customers have reported intermittent issues related to Umbraco's memory cache following deployments, which are resolved by a manual reload of the cache via the _Settings > Published Status > Caches_ dashboard. If you are running into such issues and are able to accommodate a cache clear after deployment, this workaround can be automated via the following setting: + +```json +"ReloadMemoryCacheFollowingDiskReadOperation": true, +``` + +By upgrading to the most recent available version of the CMS major you are running, you'll be able to benefit from the latest bug fixes and optimizations in this area. That should be your first option if encountering cache related issues. Failing that, or if a CMS upgrade is not an option, then this workaround can be considered. + +### Deployment of culture & hostnames settings {#deployment-of-culture--hostnames-settings} + +Culture and hostname settings, defined per content item for culture invariant content, are not deployed between environments by default. They can be opted into via configuration. + +```json +"AllowDomainsDeploymentOperations": "None|Culture|AbsolutePath|Hostname|All", +``` + +To enable this, set the configuration value as appropriate for the types of domains you want to allow: + +* `Culture` - the language setting for the content, defined under "Culture" +* `AbsolutePath` - values defined under "Domains" with an absolute path, e.g. "/en" +* `Hostname` - values defined under "Domains" with a full host name, e.g. "en.mysite.com" + +Combinations of settings can be applied, e.g. `Hostname,AbsolutePath`. + +### Deployment of public access settings {#deployment-of-public-access-settings} + +When deploying content items, public access rules based on member groups are transferred. You can amend this behavior using this setting. + +```json +"AllowPublicAccessDeploymentOperations": "None|AddOrUpdate|Remove|All", +``` + +* `None` - no public access rules will be transferred +* `AddOrUpdate` - public access rules added or updated in a source environment will be transferred to the destination +* `Remove` - public access rules removed a source environment will be removed in the destination +* `All` - all public access information will be transferred + +`AddOrUpdate` is the default setting used if no value is configured. + +### Deployment of webhooks {#deployment-of-webhooks} + +Webhooks may be considered environment specific or schema information that you would like to synchronize between environments. As such, by default, Umbraco Deploy does not include webhooks in schema deployment operations. + +```json +"AllowWebhooksDeploymentOperations": "None|All", +``` + +If you would like you include them you can adjust this setting: + +* `None` - webhooks are not deployed and are expected to be managed independently in each environment +* `All` - webhooks included in schema deployments + +### Deployment of trashed content {#deployment-of-trashed-content} + +Specifies options for handling trashed content (documents, media and members) on export or import: + +```json +"TrashedContentDeploymentOperations": "None|Export|Import|All" +``` + +You can amend this behavior using this setting: + +* `None` - trashed content will not be exported or imported +* `Export` - trashed content will be included in an export +* `Import` - trashed content will be processed and moved to the recycle bin on import +* `All` - trashed content will be included in an export, processed and moved to the recycle bin on import + +### PostDeploySchemaOperation {#post-deploy-schema-operation} + +After the schema is deployed from the files on disk, the current environment might still have items that don't have corresponding files on disk. + +You can automatically perform an operation after a schema deployment to align this: + +* `None` - no operation is performed +* `CleanSchema` - items that don't have a corresponding file on disk will be deleted +* `ExtractSchema` - all items will be written to files on disk + +A common use case is to configure `CleanSchema` on local/development environments. Deleted schema items will then be cleaned automatically, ensuring they aren't re-created when an environment writes the item back and deploys the changes. Take caution when using this value on a live environment, as missing schema files can result in additional deletions. Deleting a Document Type, for example, will also delete all content using that type. + +### PreferLocalDbConnectionString + +When using Umbraco Deploy with Umbraco Cloud, a development database is automatically created when restoring a project into a local environment for the first time. + +For Umbraco 10, by default, a SQLite database is created. + +If you would prefer to use SQL Server LocalDb when it's available on your local machine, set this value to `true`. If LocalDB isn't reported as being available by Umbraco, it will fallback to using a SQLite database instead. + +```json +"PreferLocalDbConnectionString": true +``` + +### MediaFileChecksumCalculationMethod {#media-file-checksum-calculation-method} + +Deploy will do comparisons between the entities in different environments to determine if they match and decide whether to include them in the operation. By default, for media files, a check is made on a portion of the initial bytes of the file. + +This corresponds to the default setting of `PartialFileContents`. + +If a lot of files need to be checked, this can be slow, and a faster option is available that uses the file metadata. The only downside of changing this option is a marginally increased chance of Deploy considering a media file hasn't changed when it has. This would omit it from the deployment. + +To use this method, set the value to `Metadata`. + +### NumberOfSignaturesToUseAllRelationCache {#number-of-signatures-to-use-all-relation-cache} + +When reviewing a set of items for a deployment operation, Deploy will retrieve and include relations. It does this either via single database lookups, or by bringing all relations into memory in one step, and retrieving them from there. + +For small deployment operations, the former is the more optimal approach. It gets slow though when the number of items being transferred is large. + +The cut-off before switching methods is set by this configuration value, and it defaults to an operation size of `100` items. + +### ContinueOnMediaFilePathTooLongException {#ignore-media-file-path-too-long-exception} + +When restoring between different media systems exceptions can occur due to file paths. They can happen between a local file system and a remote system based on blob storage. What is accepted on one system may be rejected on another as the file path is too long. Normally this will only happen for files with particularly long names. + +If you are happy to continue without throwing exceptions in these instances you can set this value to `true`. For example, this may make sense if restoring to a local or development environment. If this is done such files will be skipped, and although the media item will exist there will be no associated file. + +### SuppressCacheRefresherNotifications {#suppress-cache-refresher-notifications} + +When a Deploy operation completes, cache refresher notifications are fired. These are used to update Umbraco's cache and search index. + +In production this setting shouldn't be changed from it's default value of `false`, to ensure these additional data stores are kept up to date. + +If attempting a one-off, large transfer operation, before a site is live, you could set this value to `true`. That would omit the firing and handling of these notifications and remove their performance overhead. Following which you would need to ensure to rebuild the cache and search index manually via the backoffice _Settings_ dashboards. + +### ResolveUserInTargetEnvironment {#resolve-user-in-target-environment} + +With this setting assigned a value of `true`, Umbraco Deploy will attempt to resolve users when transfers are made to new environments. + +Users and user groups are maintained separately in different environments, so it isn't always the case that an editor has accounts across all environments. When an account exists matching by email address, Deploy will associate the changes made in upstream environments with the user that initiated the transfer. Allowing the expected information about save and publish operations to be available in the audit log of the environment where the data was transferred. + +When the setting is set to `false`, or a matching account isn't found, the audit records will be associated with the super-user administrator account. + +### Suspensions {#suspensions} + +Deploy operations suspend scheduled publishing, Examine indexing, document cache and/or signature database update events by default. You can amend this behavior for all supported or specific operations using these settings. + +Each setting within this section represents a Deploy operation. For each, the suspensions that are carried out can be amended with one or more of following values: + +* `DiskRead` - `None, ScheduledPublishing, Examine, DocumentCache, All` +* `PartialRestore` - `None, ScheduledPublishing, Examine, DocumentCache, All` +* `Restore` - `None, ScheduledPublishing, Examine, DocumentCache, Signatures, All` +* `Deploy` - `None, ScheduledPublishing, All` +* `Import` - `None, ScheduledPublishing, Examine, DocumentCache, All` +* `Export` - `None, ScheduledPublishing, All` + +The default value for all suspension settings is `All`. + +So for example if you wanted to remove Examine indexing suspension and resumption during partial restore operations, you could set the following: + +```json +"Suspensions": { + "PartialRestore": "ScheduledPublishing, DocumentCache" +}, +``` + +It's also possible to set the values for all operations by setting `Suspensions` to a value instead of an object, for example: + +```json +"Suspensions": "ScheduledPublishing, DocumentCache, Signatures", +``` + +If you prefer configuration in code, operators overloads on the settings class make this process straightforward, as shown in the following example: + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Deploy.Core.Configuration.DeployConfiguration; + +internal sealed class DeploySuspensionsComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.Services.Configure(options => + { + // No suspensions during import + options.Suspensions.Import = SuspensionOptions.None; + + // No Examine suspensions on all operations (using bitwise negation operator) + options.Suspensions &= ~SuspensionOptions.Examine; + + // Add scheduled publishing suspension to all operations + options.Suspensions |= SuspensionOptions.ScheduledPublishing; + }); +} +``` + +### HideConfigurationDetails {#hide-configuration-details} + +If set to `true` the configuration details shown on the setting's dashboard will be hidden. + +### HideVersionDetails {#hide-version-details} + +If set to `true` the version details shown on the setting's dashboard will be hidden. + +### ValidateDependenciesOnImport {#validate-dependencies-on-import} + +A default notification handler for the `ValidateArtifactImportNotification` is registered by Deploy that: + +* Adds warnings for dependencies that must match exactly, and are both not in the import and not with matching checksums in the target environment +* Adds warnings for all remaining content dependencies and errors for all schema dependencies that don't exist in the import + +To avoid this handler from being registered, you can set this setting to `false`. + +### Import on startup {#import-on-startup} + +Deploy can [import content and/or schema previously exported from another Umbraco installation on start-up](../deployment-workflow/import-on-startup.md). This can be customized by changing the `Umbraco:Deploy:ImportOnStartup` settings (note that this is directly below the `Deploy` section and not nested below `Settings`): + +* `Enabled` - this feature is enabled by default, but can be disabled (e.g. to prevent importing on specific environments) +* `Files` - the files that are imported on start-up (relative to the project content root, defaults to `umbraco\Deploy\import-on-startup.zip`), which are checked individually (files that do not exist are skipped and a warning will be logged) +* `FileAction` - `None` will leave the file on disk (and potentially import it again on the next start-up), `Archive` renames the file to end with `.imported` and `Delete` (the default) will remove the file on successful import +* `WarningsAsErrors` - indicates whether warnings should be considered as errors +* `EntityTypes` - sets the entity types to import, note that the default import validation will return warnings for entity types in the ZIP archive that are skipped due to this setting +* `Cultures` - the ISO codes of content variants that should be imported +* `Username` - the email address of the user that performs the import (used for auditing), uses the 'super-user' administrator account if not set + +## Configuration via code + +### Webhook Events + +Umbraco Deploy can optionally register events that you can use with Umbraco webhooks. You can add them via code, for which we provide an extension method. The following example shows how you can use this within a composer. + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Deploy.Infrastructure.Extensions; + +internal sealed class DeployWebhookEventsComposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + => builder.WebhookEvents().AddDeploy(deployBuilder => deployBuilder.AddTask()); +} +``` + +With that in place you should see two new events available that you can use in creating your webhooks. + +* Deploy operation was completed +* Deploy operation failed + +An example of the payload sent is shown below: + +```json +{ + "Id": "dc93c9ec-fbc9-4be4-91ad-f195e0c12f43", + "WorkItemType": "DiskReadWorkItem", + "Environment": { + "Name": "Live", + "Uri": "https://localhost:44309" + }, + "Result": "Completed", + "Duration": "00:00:00.8125947", + "Udis": [ + "umb://document-type/a0b5933193b8460c8eda57408f088a2e" + ] +} +``` diff --git a/14/umbraco-deploy/getting-started/get-started-with-deploy.md b/14/umbraco-deploy/getting-started/get-started-with-deploy.md new file mode 100644 index 00000000000..1d9927e1fa0 --- /dev/null +++ b/14/umbraco-deploy/getting-started/get-started-with-deploy.md @@ -0,0 +1,30 @@ +--- +description: How does Umbraco Deploy work and how to get started using Umbraco Deploy +--- + +# Getting started + +In this article you can learn more about what it takes to get started using Umbraco Deploy. You can also get a high-level overview of how the product works. + +## How Umbraco Deploy works + +Umbraco Deploy works by serializing non-content Umbraco items (called “Schema” items) to disk. These serialized files are located in the `/umbraco/Deploy/Revision` folder at the root of your website. + +These items are entities like Document Types, Media Types, Data Types, etc, and these files must be committed to source control (for example Git). Umbraco Deploy works by “extracting” this serialized information back into your Umbraco installation. This is done by deployment triggers when a deployment is sent to a target environment. + +For example, when working locally you might create a new Document Type. This will automatically create a new on-disk file in the `umbraco/Deploy/Revision` folder which is the serialized version of the new Document Type. You would then commit this file to your repository and push this change to your hosted source control (for example GitHub). + +When you want this deployed to your next environment, you would trigger your CI/CD process (for example Azure DevOps or GitHub Actions). This will push the changes to your environment. Once the build deployment completes successfully, a Deployment Trigger would be executed as an HTTPS request to your target environment. All changes found in the `umbraco/Deploy/Revision` folder will then be extracted into the Umbraco target environment. + +![Deploy workflow](../images/Deploy_concept.png) + +## [Quick start (new sites)](../installation/install-configure.md) + +There are three main steps you need to go through in order to start using Umbraco Deploy on your website. + +1. [Set up Git repository and new Umbraco project](../installation/install-configure.md#prerequisites) + * Set up a repository and then install a new Umbraco project inside it. +2. [Install Umbraco Deploy via NuGet](../installation/install-configure.md#installing-and-configuring-umbraco-deploy) + * Umbraco Deploy can be installed via NuGet. +3. [Configure CI/CD build server](../getting-started/cicd-pipeline/README.md) + * Umbraco Deploy needs a CI/CD build server needs to be set up to run when you want changes to be deployed to next upstream environment \ No newline at end of file diff --git a/14/umbraco-deploy/getting-started/images/Build-server-clean.png b/14/umbraco-deploy/getting-started/images/Build-server-clean.png new file mode 100644 index 00000000000..e20e5e6b8a8 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Build-server-clean.png differ diff --git a/14/umbraco-deploy/getting-started/images/Build-server.png b/14/umbraco-deploy/getting-started/images/Build-server.png new file mode 100644 index 00000000000..50cc11843e4 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Build-server.png differ diff --git a/14/umbraco-deploy/getting-started/images/Deploy-operation.png b/14/umbraco-deploy/getting-started/images/Deploy-operation.png new file mode 100644 index 00000000000..f14079eafd2 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Deploy-operation.png differ diff --git a/14/umbraco-deploy/getting-started/images/Deploy-section.png b/14/umbraco-deploy/getting-started/images/Deploy-section.png new file mode 100644 index 00000000000..1a4bed94f20 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Deploy-section.png differ diff --git a/14/umbraco-deploy/getting-started/images/Deploying-meta-data (1) (1).png b/14/umbraco-deploy/getting-started/images/Deploying-meta-data (1) (1).png new file mode 100644 index 00000000000..3f74a18335e Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Deploying-meta-data (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/Deploying-meta-data (1).png b/14/umbraco-deploy/getting-started/images/Deploying-meta-data (1).png new file mode 100644 index 00000000000..3f74a18335e Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Deploying-meta-data (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/Deploying-meta-data.png b/14/umbraco-deploy/getting-started/images/Deploying-meta-data.png new file mode 100644 index 00000000000..3f74a18335e Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Deploying-meta-data.png differ diff --git a/14/umbraco-deploy/getting-started/images/Deployment-center (1) (1).png b/14/umbraco-deploy/getting-started/images/Deployment-center (1) (1).png new file mode 100644 index 00000000000..f47e12edd19 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Deployment-center (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/Deployment-center (1).png b/14/umbraco-deploy/getting-started/images/Deployment-center (1).png new file mode 100644 index 00000000000..f47e12edd19 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Deployment-center (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/Deployment-center.png b/14/umbraco-deploy/getting-started/images/Deployment-center.png new file mode 100644 index 00000000000..f47e12edd19 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Deployment-center.png differ diff --git a/14/umbraco-deploy/getting-started/images/Generated-uda-files.png b/14/umbraco-deploy/getting-started/images/Generated-uda-files.png new file mode 100644 index 00000000000..a203c104ab6 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/Generated-uda-files.png differ diff --git a/14/umbraco-deploy/getting-started/images/deployment-acivity-complete.png b/14/umbraco-deploy/getting-started/images/deployment-acivity-complete.png new file mode 100644 index 00000000000..3e5e6a82254 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/deployment-acivity-complete.png differ diff --git a/14/umbraco-deploy/getting-started/images/deployment-activity-log.png b/14/umbraco-deploy/getting-started/images/deployment-activity-log.png new file mode 100644 index 00000000000..8e339c471c8 Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/deployment-activity-log.png differ diff --git a/14/umbraco-deploy/getting-started/images/deployment-complete (1) (1).png b/14/umbraco-deploy/getting-started/images/deployment-complete (1) (1).png new file mode 100644 index 00000000000..ee12f34a23a Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/deployment-complete (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/deployment-complete (1).png b/14/umbraco-deploy/getting-started/images/deployment-complete (1).png new file mode 100644 index 00000000000..ee12f34a23a Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/deployment-complete (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/deployment-complete.png b/14/umbraco-deploy/getting-started/images/deployment-complete.png new file mode 100644 index 00000000000..ee12f34a23a Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/deployment-complete.png differ diff --git a/14/umbraco-deploy/getting-started/images/test-UDA (1) (1) (1).png b/14/umbraco-deploy/getting-started/images/test-UDA (1) (1) (1).png new file mode 100644 index 00000000000..2c929784cdc Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/test-UDA (1) (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/test-UDA (1) (1).png b/14/umbraco-deploy/getting-started/images/test-UDA (1) (1).png new file mode 100644 index 00000000000..2c929784cdc Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/test-UDA (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/test-UDA (1).png b/14/umbraco-deploy/getting-started/images/test-UDA (1).png new file mode 100644 index 00000000000..2c929784cdc Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/test-UDA (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/test-UDA.png b/14/umbraco-deploy/getting-started/images/test-UDA.png new file mode 100644 index 00000000000..2c929784cdc Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/test-UDA.png differ diff --git a/14/umbraco-deploy/getting-started/images/workflow-preview.png b/14/umbraco-deploy/getting-started/images/workflow-preview.png new file mode 100644 index 00000000000..78a9a74b67a Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/workflow-preview.png differ diff --git a/14/umbraco-deploy/getting-started/images/workflows (1) (1).png b/14/umbraco-deploy/getting-started/images/workflows (1) (1).png new file mode 100644 index 00000000000..2d7956e4a0e Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/workflows (1) (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/workflows (1).png b/14/umbraco-deploy/getting-started/images/workflows (1).png new file mode 100644 index 00000000000..2d7956e4a0e Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/workflows (1).png differ diff --git a/14/umbraco-deploy/getting-started/images/workflows.png b/14/umbraco-deploy/getting-started/images/workflows.png new file mode 100644 index 00000000000..2d7956e4a0e Binary files /dev/null and b/14/umbraco-deploy/getting-started/images/workflows.png differ diff --git a/14/umbraco-deploy/getting-started/streamlining-local-development.md b/14/umbraco-deploy/getting-started/streamlining-local-development.md new file mode 100644 index 00000000000..de18c3fe6aa --- /dev/null +++ b/14/umbraco-deploy/getting-started/streamlining-local-development.md @@ -0,0 +1,35 @@ +# Streamlining Local Development + +In this section we discuss some additional steps you can carry out to streamline your local development workflow. + +## Creating Git Hooks + +Working in a team, it's common for developers to pull code from source control to update their local environment with the latest Umbraco schema. + +They can do this by starting up the website, navigating to the _Settings > Deploy_ dashboard and triggering a data extraction. + +We can automate this step using a [git hook](https://www.atlassian.com/git/tutorials/git-hooks). + +When working with Umbraco Cloud, this step is configured automatically for you when you clone and run your project the first time. If working with Umbraco Deploy On-Premise, you can set it up yourself. + +The process works by using the marker file Umbraco Deploy uses to trigger an update of the Umbraco schema from the `.uda` files from source control. + +If a file named `deploy-on-start` is found in the `/umbraco/Deploy` folder, an update will run automatically when the site starts up. + +Therefore, if we ensure that the file is created everytime the source code is pulled from the remote repository, we can automate the update. + +To do this, carry out the following steps: + +* Find the `.git` folder within your solution root. + * It might be a hidden folder, so if you don't see it, make sure your file browser is configured to show hidden files and folders. +* Within that you'll find a `hooks` folder, and inside that, a file called `post-merge.sample`. +* Rename the file to remove the `.sample` extension and open it in a text editor. +* Apply the following text and save the file (amending the path to the web project as appropriate for your solution structure): + +``` +#!/bin/sh +echo > src/UmbracoProject/umbraco/Deploy/deploy-on-start +``` + +* Run a `git pull origin `. +* Start up the website and you should find the Umbraco schema update has been triggered. diff --git a/14/umbraco-deploy/images/Deploy_concept.png b/14/umbraco-deploy/images/Deploy_concept.png new file mode 100644 index 00000000000..2b371aa8687 Binary files /dev/null and b/14/umbraco-deploy/images/Deploy_concept.png differ diff --git a/14/umbraco-deploy/images/clear-cached-sigs.png b/14/umbraco-deploy/images/clear-cached-sigs.png new file mode 100644 index 00000000000..e55f3753ddb Binary files /dev/null and b/14/umbraco-deploy/images/clear-cached-sigs.png differ diff --git a/14/umbraco-deploy/images/export-schema.png b/14/umbraco-deploy/images/export-schema.png new file mode 100644 index 00000000000..09355cb6fb1 Binary files /dev/null and b/14/umbraco-deploy/images/export-schema.png differ diff --git a/14/umbraco-deploy/images/licenses-screen.png b/14/umbraco-deploy/images/licenses-screen.png new file mode 100644 index 00000000000..034ab1de85e Binary files /dev/null and b/14/umbraco-deploy/images/licenses-screen.png differ diff --git a/14/umbraco-deploy/images/schema-mismatch-on-transfer.png b/14/umbraco-deploy/images/schema-mismatch-on-transfer.png new file mode 100644 index 00000000000..575a93ac732 Binary files /dev/null and b/14/umbraco-deploy/images/schema-mismatch-on-transfer.png differ diff --git a/14/umbraco-deploy/images/set-cached-sigs.png b/14/umbraco-deploy/images/set-cached-sigs.png new file mode 100644 index 00000000000..fb1ff4ee178 Binary files /dev/null and b/14/umbraco-deploy/images/set-cached-sigs.png differ diff --git a/14/umbraco-deploy/installation/install-configure.md b/14/umbraco-deploy/installation/install-configure.md new file mode 100644 index 00000000000..9af30dd86c0 --- /dev/null +++ b/14/umbraco-deploy/installation/install-configure.md @@ -0,0 +1,305 @@ +--- +description: >- + In this article, we will cover the steps in order for you to install and + configure Umbraco Deploy on a new or existing website. +--- + +# Setting up Umbraco Deploy + +## Prerequisites + +Ensure to first read and follow the setup guides for either new or existing projects below: + +
+ +New project + +Here we will cover how to install and set up Umbraco Deploy on a new website. + +#### Requirement + +* Visual Studio 2017 v15.9.6 or later +* Umbraco Deploy license +* SQL Server Database + +**Set up the Git repository and Umbraco project** + +The first step to get Umbraco Deploy up and running is to set up a GitHub repository. This will be where source code is stored, and, following the GitHub Actions example, act as our environment where we will set up a CI/CD pipeline. + +1. Using the Visual Studio template, set up a GitHub repository with a .gitignore file. +2. Clone down the repository to your local machine. +3. Create a new Umbraco project. +4. Run the project. +5. Choose to use a custom SQL connection string pointing to your local database. +6. Commit the files so they are ready to be pushed up once we have set up the build server. + +When Umbraco has been installed in a repository, we can continue to install and configure Umbraco Deploy in the project. + +
+ +
+ +Existing project + +Here we will cover the steps in order for you to install Umbraco deploy on your already existing website with content. + +We will cover how to install and set up Umbraco deploy on your website and how to generate the UDA files based on your production website's database. + +#### Requirement + +* Visual Studio 2017 v15.9.6 or later +* Umbraco Deploy license +* Copy of your production site's database +* Copy of views, CSS, and scripts folder from production + +**Step 1: Install Umbraco Deploy on Existing site** + +To install Umbraco Deploy on an existing site there are additional steps that need to be taken so Umbraco Deploy can run with your website. On an existing Umbraco website, there is already a set of Document Types, Templates, and Data Types with IDs in the database. In order for Umbraco Deploy to work with your website, you will need to make sure that these IDs are in sync between the different environments that you want to add to your setup. + +1. Make a copy of the database on the production site. +2. Download your `/Views` folder as well as the folders holding your css files and scripts. + +When the production database, folder, and files have been copied down, it's time to set up a git repository and a new Umbraco project. + +**Step 2: Set up Git repository and Umbraco project** + +The next step to get Umbraco Deploy up and running is to set up a repository and install Umbraco into it. + +1. Set up a repository with a .gitignore file using the Visual Studio template. +2. Clone down the repository to your local machine. +3. Create a new Umbraco project. +4. Use the copy of your production Database when setting up the database for the empty project. +5. Add the `/Views` folder as well as the folders holding your css files and scripts. +6. Commit the files so they are ready to be pushed up once you have set up the build server. +7. Run the project. + +When Umbraco has been installed in a repository, we can continue to install and configure Umbraco Deploy in the project. + +
+ +## Source Control Configuration + +After the Umbraco files have been committed add the following lines to the .gitignore so that they will not be picked up by Git when we are deploying. + +``` +**/media/* + +# Umbraco deploy specific +**/umbraco/Deploy/deploy* +``` + +{% hint style="info" %} +The deploy-specific update here will ensure that temporary files generated by Deploy during its operations will not be included in source control. +{% endhint %} + +Make sure that the updates to the .gitignore file are also committed. + +## Installing and Configuring Umbraco Deploy + +When Umbraco has been installed in a repository, we can install Umbraco Deploy in the project. + +To install Umbraco Deploy, run `dotnet add package Umbraco.Deploy.OnPrem` from the command line or `Install-Package Umbraco.Deploy.OnPrem` from the package manager console in Visual Studio. + +{% hint style="info" %} +To be able to use Umbraco Forms with Umbraco Deploy, you need to install the `Umbraco.Forms.Deploy` package as well. +{% endhint %} + +{% hint style="info" %} +In order to deploy content based on certain rich core and community property editors - including Multi URL Picker and Block List/Grid Editor - there is one further NuGet package to install: `Umbraco.Deploy.Contrib`. +{% endhint %} + +With Umbraco Deploy installed, to use it in the project you will need to create and add configuration for an API key/secret. + +For improved security, it is recommended to set the `ApiSecret` (instead of the `ApiKey`) setting to a **cryptographically random value of 64 bytes**. Using Base64-encoding to get the string representation, will result in a value of 88 characters. For versions prior to Deploy 12 or when not using the API secret setting, the recommendation is to set the `ApiKey` to a randomly generated string of 64 characters. + +
+ +Generate and set API secret (recommended) + +You can use the following C# code to generate the API secret: + +```csharp +using System; +using System.Security.Cryptography; + +byte[] secret = new byte[64]; +RandomNumberGenerator.Create().GetBytes(secret); +string apiSecret = Convert.ToBase64String(secret); + +Console.Write(apiSecret); +``` + +Or by running the following PowerShell command: +```pwsh +$secret = [byte[]]::new(64); [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($secret); return [System.Convert]::ToBase64String($secret) +``` + +This same Deploy API secret must be used on each environment for the website. + +{% hint style="info" %} +We strongly recommend generating different secrets for different websites/projects. +{% endhint %} + +The key should be applied in `appsettings.json`: + +```json +{ + "Umbraco": { + "Deploy": { + "Settings": { + "ApiSecret": "", + } + } + } +} +``` + +
+ +
+ +Generate and set API key (deprecated) + +You can use the following C# code to generate the API key: + +```csharp +using System; +using System.Security.Cryptography; + +byte[] secret = new byte[32]; +RandomNumberGenerator.Create().GetBytes(secret); + +var apiKey = new StringBuilder(secret.Length * 2); +for (int i = 0; i < secret.Length; i++) +{ + apiKey.AppendFormat("{0:X2}", secret[i]); +} + +Console.Write(apiKey.ToString()); +``` + +Or by running the following PowerShell command: +```pwsh +$secret = [byte[]]::new(32); [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($secret); return -join ($secret | %{ '{0:X2}' -f $_ }) +``` + +This same Deploy API key must be used on each environment for the website. + +{% hint style="info" %} +We strongly recommend generating different keys for different websites/projects. +{% endhint %} + +The key should be applied in `appsettings.json`: + +```json +{ + "Umbraco": { + "Deploy": { + "Settings": { + "ApiKey": "", + } + } + } +} +``` + +
+ +#### Configuring Environments + +Once the API secret has been added, it is now time to configure the environments, also in the `appsettings.json` file. + +An example configuration with a single upstream environment file will look like this: + +```json +{ + "Umbraco": { + "Deploy": { + "Settings": { + "ApiSecret": "" + }, + "Project": { + "CurrentWorkspaceName": "Live", + "Workspaces": [ + { + "Id": "efef5e89-a19b-434b-b68a-26e022a0ad52", + "Name": "Live", + "Type": "live", + "Url" :"https://localhost:44307" + } + ] + } + } + } +} +``` + +The setting under _Project:CurrentWorkspaceName_ should match the _Name_ provided in the list of _Workspaces_ that match the current environment. Using this Umbraco Deploy will indicate the correct current environment on the "Workspaces" dashboard. + +{% hint style="info" %} +In Umbraco Deploy 9, this value was set using the configuration key _Debug:EnvironmentName_. Although included under a "Debug" section, this setting is required for the installations of Umbraco Deploy on-premises (i.e. other than on Umbraco Cloud). Hence why it was moved to the "Project" section in Umbraco Deploy 10. +{% endhint %} + +Expected values for _Type_ are "development", "staging" or "live". These settings are required, though strictly only for the latter is it necessary to use the specific value of "live", so other values can be used if you have more than these three environments. + +You will need to generate a unique GUID for each environment. This can be done in Visual Studio: + +1. Open "Tools". +2. Select "Create GUID". +3. Use the Registry Format. +4. Copy the GUID into the `id` value. +5. Generate a "New GUID" for each environment you will be adding to your setup. + +Or by running the following PowerShell command: +```pwsh +[guid]::NewGuid().ToString() +``` + +The URL configured for each environment should be the root URL for the website and needs to be accessible by the other environments over **HTTPS**. + +#### Validating Source Control + +Once the configuration has been set up with the correct information we can now go ahead and make sure that the source control is including our files in the `/umbraco/Deploy` folder of our Umbraco project. + +This can be done by going to the `/umbraco/Deploy/Revision` folder of the project and create a test `.uda` file, and then check in either your Git GUI or in the command line and verify whether the test file is being tracked. + +![Test UDA file]() + +We can see that the file has been created and it is being tracked by Git and we can go ahead and delete the test file. + +Now that Umbraco Deploy has been installed on the project, we can go ahead and commit the files to the repository. + +**Do not push the files up yet** as a CI/CD build server will first need to be set up and connected to our repository. + +#### Include your Umbraco Deploy license file + +Before moving on to setting up the build server, make sure that your license is included in your project. + +For Umbraco Deploy On-Premise, this will be a key provided to you when taking out your subscription to the product. It should be added to your configuration at the key `Umbraco:Licenses:Umbraco.Deploy.OnPrem`. + +For example, in `appsettings.json`: + +```json + "Umbraco": { + "CMS": { + ... + }, + "Licenses": { + "Umbraco.Deploy.OnPrem": "" + }, + "Deploy": { + ... + } +``` + +{% 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_Deploy_OnPrem": "YOUR_LICENSE_KEY" +``` +{% endhint %} + +Umbraco Cloud projects use a license file placed in the `/umbraco/Licenses` folder that is provided when your project is created. + +Read more about the [Umbraco Deploy licensing model](../installation/the-licensing-model.md). diff --git a/14/umbraco-deploy/installation/the-licensing-model.md b/14/umbraco-deploy/installation/the-licensing-model.md new file mode 100644 index 00000000000..4bb9d4eb722 --- /dev/null +++ b/14/umbraco-deploy/installation/the-licensing-model.md @@ -0,0 +1,160 @@ +# The Licensing Model + +Umbraco Deploy is a commercial product. You will need a **valid license** to use the product. + +A license for Umbraco Deploy is included when hosting on Umbraco Cloud. + +## How does it work? + +Licenses are sold per domain and will also work on all subdomains. With every license, you will also be able to configure two development/testing domains. + +### Example + +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 one Umbraco solution. It includes all domains hosted by the solution, all production environments (if load-balancing), and all non-production environments. + +To clarify the above: + +* You only need one license when you have a solution covering multiple domains- for example, www.mysite.com and www.mysite.dk - load balanced in production over multiple servers running from the same database, managed from the same backoffice instance, and with any number of non-production environments (staging, QA, etc.) +* You need two licenses if you have a web presence that consists of two separate websites hosted on different domains or sub-domains - for example, www.mysite.com and shop.mysite.com - with each of these managed as a separate Umbraco installation using their own database and backoffice in production. + +{% hint style="info" %} +The license for Umbraco Deploy comes with a recurring yearly fee. Learn more about this and pricing on [Umbraco.com](https://umbraco.com/products/umbraco-deploy/). +{% endhint %} + +## Purchasing your license + +You can look at the pricing, plans, features, and purchase the license on the [Umbraco Deploy On-premises](https://umbraco.com/products/add-ons/deploy/umbraco-deploy-on-premises/) page. + +## Installing your license + +Once you've configured your license with the correct domains, you are ready to install the license on your Umbraco installation. + +For Umbraco Deploy On-Premise 12 and above, this will be a key provided to you when taking out your subscription to the product. It should be added to your configuration at the key `Umbraco:Licenses:Umbraco.Deploy.OnPrem`. + +For example, in `appsettings.json`: + +```json + "Umbraco": { + "CMS": { + ... + }, + "Licenses": { + "Products": { + "Umbraco.Deploy.OnPrem": "" + } + }, + "Deploy": { + ... + } +``` + +{% 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_Deploy_OnPrem": "YOUR_LICENSE_KEY" +``` +{% endhint %} + +Umbraco Cloud projects use a license file placed in the `/umbraco/Licenses` folder that is provided automatically when your project is created. + +## Validating the license + +On start-up and on a schedule, Umbraco running Deploy On-premise will call out to a service. It will pass the configured license key to determine its validity. The response triggers a notification that the Umbraco Deploy will handle. It will amend the available functionality as appropriate to a valid, invalid or expired license. + +You can view the status of the Umbraco Deploy On-premise license in the backoffice. This is available via the _Settings_ section, listed along with any other products using the same licensing service: + +![Licenses screen in Umbraco backoffice](./images/licenses-screen.png) + +### 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. + +### 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 Deploy 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. This will be the case if you are running Umbraco Deploy 13.1 or higher. If you are 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.Deploy.OnPrem": "" + }, + "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.Deploy.OnPrem", + "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/14/umbraco-deploy/legacy-documentation.md b/14/umbraco-deploy/legacy-documentation.md new file mode 100644 index 00000000000..6878c5a0999 --- /dev/null +++ b/14/umbraco-deploy/legacy-documentation.md @@ -0,0 +1,7 @@ +# Legacy Documentation + +This documentation platform covers only major versions of the Umbraco Deploy since Umbraco 9+. If you are using an older version of Umbraco Deploy, 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-deploy
Umbraco 8 Documentationhttps://our.umbraco.com/documentation/Add-ons/Umbraco-Deploy/
diff --git a/14/umbraco-deploy/release-notes.md b/14/umbraco-deploy/release-notes.md new file mode 100644 index 00000000000..7700ba269e2 --- /dev/null +++ b/14/umbraco-deploy/release-notes.md @@ -0,0 +1,146 @@ +--- +description: Get an overview of the things changed and fixed in each version of Umbraco Deploy. +--- + +# Release notes + +In this section we have summarised the changes to Umbraco Deploy and [Deploy Contrib](https://github.com/umbraco/Umbraco.Deploy.Contrib) released in each version. Each version is presented with a link to the [Deploy issue tracker](https://github.com/umbraco/Umbraco.Deploy.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 the details about the breaking changes in the [version specific updates](upgrades/version-specific.md) article. +{% endhint %} + +## Release history + +This section contains the release notes for Umbraco Deploy 14 including all changes for this version. + +### [14.3.0](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.3.0) (February 6th 2025) + +* All items from 14.3.0-rc1 + +### [14.3.0-rc1](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.3.0) (January 30th 2025) + +* Schema cleanup and item actions triggered from Deploy's management dashboard (create or delete UDA files and Umbraco items) +* Allow ignoring dependencies in transfer/restore operations +* Ignore `Dependencies` artifact property when calculating the checksum and fix schema comparison [#246](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/246) +* Add 'Hide up to date' toggle to schema comparison [#245](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/245) +* Fix parsing dictionary item root UDI range from node ID +* Ensure work item references/action results are deallocated (reduces overall memory usage in Deploy) +* Allow disabling warnings as errors on import + +### [14.2.2](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.2) (December 23rd 2024) + +* Ensure environment-to-environment actions are executed asynchronously on background job (fixes timeout issues on large deployments) [#179](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/179) +* Only require default, allowed and master templates and their associated files to exist (avoids schema mismatches on template changes) [156](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/156) + +### [14.2.1](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.1) (November 29th 2024) + +* Update documentation links in management dashboard to include major version in the URL +* Add `ValidateDependenciesOnImport` setting to management dashboard +* Fix tree restore for custom entities [#241](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/241) +* Disable import button when no file is selected + +### [14.2.0](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.0) (November 21st 2024) + +* All items from 14.2.0-rc1 + +### [14.2.0-rc1](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.0) (November 13th 2024) + +* Add option to include all schema in a workspace export +* Add option to export from transfer queue +* Combine migrated grid editor with default Block Grid block configuration (set `RowMinSpan` and `RowMaxSpan` to `1` and `EditorSize` to `medium`) +* Import on startup +* Added `ValidateDependenciesOnImport` setting to disable dependency validation on import +* Fixed issue where content was not saved when transferring variant content with a release date +* Support flexible environments on Umbraco Cloud (remove requirement for environment types to be Development, Staging or Live) + +### [14.1.4](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.4) (October 3rd 2024) + +* Support migrating legacy Grid editor settings (config/styles) using JSON object pre-values +* Fix parsing JSON serialized legacy Grid editor control values + +### [14.1.3](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.3) (September 19th 2024) + +* Resolved forbidden API requests on content section display when the user does not have access to the settings section. + +### [14.1.2](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.2) (September 17th 2024) + +* Fix document blueprint connector and add support for containers +* Fix tree export of members by member type +* Ensure release date of invariant content is correctly transferred [#233](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/233) +* Parse nested JSON property values from artifact values [#234](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/234) + +### [14.1.1](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.1) (August 20th 2024) + +* Support getting artifacts from exploded/expanded `NamedUdiRange` with different entity types +* Fixed typo in `DefaultLegacyDataTypeConfigurationArtifactMigrator` when migrating Color Picker items in v8 format + +### [14.1.0](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.0) (August 15th 2024) + +* All items from 14.1.0-rc1 +* Fixed `Could not create Udi node: {Id} and entity type {EntityType}` exception when exporting tree nodes without children +* Fixed deploy signatures not getting cleared when members are deleted [#230](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/230) +* Allow members to be deployed when selected as items in a multi-node tree picker [#231](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/231) +* Apply `ExcludedEntityTypes` configuration to disk operations [#232](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/232) +* Fixed issues with partial restore from an external tree that contains more than one entity +* Fixed formatting of trial expiry days and added missing translations [#229](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/229) +* Fixed `Could not get physical path for "umb://template-file/".` exception when deploying/exporting template without physical file on disk + +### [14.1.0-rc1](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.0) (July 19th 2024) + +* Add migrators to support legacy Grid layout to Block Grid migration +* Fix schema mismatch when saving templates in production runtime mode [#228](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/228) +* Add default migrator to add missing editor UI aliases and update when replacing editor +* Add default migrator to update Data Type configuration +* Support processing Document/Media Type list view keys and add migrator + +### [14.0.2](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.0.2) (July 11th 2024) + +* Set trashed state when processing content [#223](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/223) +* Improve exception message when parent can't be found when getting artifact [#216](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/216) +* Add `MaxRequestLength` Deploy setting to break file upload into multiple requests +* Set variant names when creating new content [#222](https://github.com/umbraco/Umbraco.Deploy.Issues/issues/222) + +### [14.0.1](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.0.1) (June 6th 2024) + +* Ensure remote tree uses correct entity type (if multiple entities like folders and items are present in a tree): + * `ITransferEntityService.RegisterTransferEntityType(...)` accepts an optional `RemoteTreeDetail` that now exposes the entity type when getting remote entities; +* Fix `GetMaxRequestLength` endpoint (misaligned HTTP method) preventing file transfers/uploads from local environments; +* Fix Data Type deployment due to missing `EditorUiAlias` (requires a schema extraction/Data Type save to fix); +* Fix JSON serialization errors in trigger endpoints (extract and status report); +* Obsolete and hide `NestedContentValueConnector` and add import migrators for unsupported legacy editors by default: + * Adds `ReplaceMediaPickerDataTypeArtifactMigrator` and `ReplaceNestedContentDataTypeArtifactMigrator` artifact migrators to replace the Data Types with the Media Picker v3 and Block List respectively; + * Adds `MediaPickerPropertyTypeMigrator` and `NestedContentPropertyTypeMigrator` property type migrators to ensure content (property data) is migrated as well; +* Support import with unknown UDI types (like macro, macroscript and partial-view-macro); +* Fix JSON serialization error in value connectors for `BlockValue`. + +### [14.0.0](https://github.com/umbraco/Umbraco.Deploy.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.0.0) (May 30th 2024) + +* Compatibility with Umbraco 14 + * See full details of breaking changes under the [Version-specific Upgrade Guide](upgrades/version-specific.md). + +## Umbraco.Deploy.Contrib + +### [14.2.0](https://github.com/umbraco/Umbraco.Deploy.Contrib/releases/tag/release-14.2.0) (October 3rd 2024) + +* Migrate nested/recursive legacy pre-value property values [#71](https://github.com/umbraco/Umbraco.Deploy.Contrib/pull/71) + +### [14.1.0](https://github.com/umbraco/Umbraco.Deploy.Contrib/releases/tag/release-14.1.0) (August 15th 2024) + +* All items from 14.1.0-rc1 + +### [14.1.0-rc1](https://github.com/umbraco/Umbraco.Deploy.Contrib/releases/tag/release-14.1.0-rc1) (July 19th 2024) + +* Add Matryoshka Group Separator artifact migrator [#67](https://github.com/umbraco/Umbraco.Deploy.Contrib/pull/67) +* Add migrators to support DocTypeGridEditor to Block Grid migration [#66](https://github.com/umbraco/Umbraco.Deploy.Contrib/pull/66) +* Fix and enable remaining legacy artifact migrators [#68](https://github.com/umbraco/Umbraco.Deploy.Contrib/pull/68) + +### [14.0.0](https://github.com/umbraco/Umbraco.Deploy.Contrib/releases/tag/release-14.0.0) (May 30th 2024) + +* Compatibility with Umbraco 14 and Deploy 14. + +## 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-deploy/release-notes.md) and [Umbraco Deploy Package page](https://our.umbraco.com/packages/developer-tools/umbraco-deploy/) diff --git a/14/umbraco-deploy/troubleshooting.md b/14/umbraco-deploy/troubleshooting.md new file mode 100644 index 00000000000..669d3b751d6 --- /dev/null +++ b/14/umbraco-deploy/troubleshooting.md @@ -0,0 +1,117 @@ +--- +description: The troubleshooting section for Umbraco Deploy +--- + +# Troubleshooting + +In this troubleshooting section, you can find help to resolve issues that you might run into when using Umbraco Deploy. + +If you are unable to find the issue you are having, then please reach out to our friendly support team at contact@umbraco.com. + +## Schema mismatches + +When transferring or restoring content between two Umbraco Deploy environments, you might run into **Schema mismatch** errors. For more information on how to resolve schema mismatch issues, see the [Schema Mismatches](https://docs.umbraco.com/umbraco-cloud/troubleshooting/deployments/schema-mismatches) article. + +Umbraco Deploy maintains a cached set of signatures that represent each schema and content item. They are used when transferring or restoring content between environments to aid performance. + +If having resolved schema mismatches you still have reports of errors, it might be that the signatures are out of date. In other words, Deploy is using a cached representation of an item that no longer matches the actual item stored in Umbraco. + +This should not be necessary in normal use but can occur after upgrades. If you have this situation, you can clear the cached signatures in both the upstream and downstream environments. You do this via the _Clear Cached Signatures_ operation available on the _Settings > Deploy_ dashboard: + +
Clear cached signatures

Clear cached signatures

+ +## Slow responses or timeouts when restoring or transferring + +When transferring or restoring content between environments, Deploy needs to ensure that all related items are updated together. It also checks that any schema dependencies an item has also exist in the target environment. When a large amount of content is selected for transfer or restore, this process of determining all the dependent items can take some time. + +In some cases, a hard limit imposed by the Cloud hosting platforms such as Azure, used by Umbraco Cloud, can be reached. + +If you find the process slow or reporting a platform timeout, there are a few options you can take. + +### Consider partial restore + +If restoring, you can choose to pull down a smaller set of content via the partial restore feature. With this you select an item in the remote environment to restore. You can select to include child items. Any items related to the selected ones, for example via content or media pickers, will also be restored. + +### Consider import/export + +In addition to transferring content via the backoffice, it is possible to move both content and schema between environments via Deploy's import/export feature. With this, a selection of Umbraco data can be exported from one environment to a .zip file. That file can then be imported into another environment. + +As this process requires less inter-environment communication, it's possible to transfer much larger amounts of content without running into the hard platform limits. + +[Read more about the import/export feature here](deployment-workflow/import-export.md). + +### Review timeouts + +Firstly, you can review and update the [timeout settings available with Deploy](getting-started/deploy-settings.md#timeout-settings). Increasing these from the default values may help, but won't necessarily resolve all issues. This is because, as noted, some timeouts are fixed values set by the hosting environment. + +### Use batch configurations + +There are two places where Deploy operations can be batched. This allows breaking up of a single, long process into multiple, smaller ones. By doing this it's possible to complete each smaller operation within the platform imposed timeout. + +#### For transfers to upstream environments + +If transferring items from a downstream environment to an upstream one, it's possible to [configure a batch size](getting-started/deploy-settings.md#batch-settings). With this in place, transfers will be batched into separate operations, allowing each single operation to complete before any hosting environment-enforced timeout. + +This will take effect only for transfers to upstream environments and when multiple items are selected in the backoffice. An example is the selection of a single media folder containing many files. + +#### For processing of a Deploy "package" + +A package is an ordered structure containing all the items selected for a Deploy operation, plus all the determined dependencies and relations. The processing of this package in the target environment can also be batched via a [configuration setting](getting-started/deploy-settings.md#batch-settings). + +When set, if the number of items determined for the package exceeds the batch size, the processing will be chunked into batches. + +### Ensure signatures are pre-cached + +For transfer or restore operations, it's worth ensuring Deploy's cached signatures are fully populated in both the upstream and downstream environments. This can be done via the _Set Cached Signatures_ operation available on the _Settings > Deploy_ dashboard: + +
Set cached signatures

Set cached signatures

+ +The process may take a few minutes to complete if you have a lot of content or media in your installation. Information is written to the log indicating the signatures calculated for each entity type. + +Now the checks Deploy has to do to figure out the items and dependencies to process will complete much more quickly. + +### Modify the checksum calculation method for media files + +Deploy will do comparisons between the entities in different environments to determine if they match and decide whether to include them in the operation. By default, for media files, a check is made on a portion of the initial bytes of the file. + +If a lot of files need to be checked, this can be slow, and a faster option is available that uses the file metadata. The only downside of changing this option is a marginally increased chance of Deploy considering a media file hasn't changed when it has. This would omit it from the deployment. + +This option can be [set in configuration](getting-started/deploy-settings.md#mediafilechecksumcalculationmethod). + +### Consider disabling cache refresher notifications + +When a Deploy operation completes, cache refresher notifications are fired. These are used to update Umbraco's cache and search index. + +In production these should always be enabled, to ensure these additional data stores are kept up to date. + +If attempting a one-off, large transfer operation, before a site is live, you could disable these via a [configuration setting](getting-started/deploy-settings.md#suppresscacherefreshernotifications). That would omit the firing and handling of these notifications and remove their performance overhead. Following which you would need to ensure to rebuild the cache and search index manually via the backoffice _Settings_ dashboards. + +### Review relation types included in deploy operations + +As well as transferring entities between environments Deploy will also include the relations between them. As of 10.1.2 and 11.0.1, two relation types used for usage tracking are omitted by default. These do not need to be transferred as they are recreated by the CMS as part of the save operation on the entity. + +If using an earlier version, or to make further adjustments, modify the [settings for relation types](getting-started/deploy-settings.md#relationtypes) in configuration. + +## Path too long exceptions + +When restoring between different media systems exceptions can occur due to file paths. They can happen between a local file system and a remote system based on blob storage. What is accepted on one system may be rejected on another as the file path is too long. Normally this will only happen for files with particularly long names. + +If you are happy to continue without throwing exceptions in these instances you can [modify the configuration](getting-started/deploy-settings.md#continueonmediafilepathtoolongexception). If this is done such files will be skipped, and although the media item will exist there will be no associated file. + +## Schema files following upgrades + +When Umbraco schema items are created, a representation of them is saved to disk as a `.uda` file in the `/data/revision/` folder. The representation is known as an artifact. It will be refreshed on further updates to represent the current state of the schema item. + +Following an upgrade, it's possible the contents of the file will no longer match what would be generated by the current version. For example, if a property has been added to an artifact, this will be absent in the file. It would be added if the file was recreated following the upgrade. + +This can lead to situations where Deploy continues to process a file it considers changed, even though the item represented is up-to-date. This in turn means slow updates of Umbraco schema, as Deploy is processing more files than it needs to do. + +To resolve this situation, following an upgrade, it is good practice to re-save the `.uda` files in the "left-most" environment. This will usually be the local one, or if not using that, the Development environment. You can do this via the _Export Schema To Data Files_ operation available on the _Settings > Deploy_ dashboard: + +
+ +
Export schema

Export schema

+ +
+ +The updated files should be committed to source control and deployed to upstream environments. diff --git a/14/umbraco-deploy/upgrades/README.md b/14/umbraco-deploy/upgrades/README.md new file mode 100644 index 00000000000..bf71871eb32 --- /dev/null +++ b/14/umbraco-deploy/upgrades/README.md @@ -0,0 +1,23 @@ +--- +description: How to upgrade Umbraco Deploy +--- + +# Upgrading + +As with all of our products, it is always recommended to run the latest version of Umbraco Deploy. + +On the Umbraco Deploy page in the [Packages page](https://our.umbraco.com/packages/developer-tools/umbraco-deploy/) you can see what the latest version is, as well as read the changelog. + +Umbraco Deploy can be upgraded via NuGet. + +Open the **Package Console** in Visual Studio and type: + +`Update-Package Umbraco.Deploy.OnPrem` + +You will be prompted to overwrite files. You should choose **"No to All"** by pressing **"L"** . + +You can open the **NuGet Package Manager** and select the **Updates** pane to get a list of available updates. Choose the package called **Umbraco.Deploy.OnPrem** and click update. This will run through all the files and make sure you have the latest changes while leaving the files you have updated. + +## [Version Specific Upgrade Details](version-specific.md) + +Contains version-specific documentation for when upgrading to new major versions of Umbraco Deploy. diff --git a/14/umbraco-deploy/upgrades/version-specific.md b/14/umbraco-deploy/upgrades/version-specific.md new file mode 100644 index 00000000000..c263779f0e2 --- /dev/null +++ b/14/umbraco-deploy/upgrades/version-specific.md @@ -0,0 +1,111 @@ +--- +description: >- + Version specific documentation for upgrading to new major versions of Umbraco Deploy. +--- + +# Version Specific Upgrade Details +This article provides specific upgrade documentation for migrating to Umbraco Deploy version 14. + +{% 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 14 of Umbraco Deploy has a minimum dependency on Umbraco CMS core of `14.0.0`. It runs on .NET 8. + +### **Breaking changes** +Version 14 contains some breaking changes. Not many projects are expected to be affected by them, as they are in relevant areas when extending Deploy to support additional entities and/or property editors. For reference though, the full details are listed here: + +#### Async methods +Asynchronous methods have been added to the following interfaces (in the CMS `Umbraco.Cms.Core.Deploy` namespace): +- `IContextCache`: + - `GetOrCreateAsync(...)` +- `IDataTypeConfigurationConnector`, `IImageSourceParser`, `ILocalLinkParser` and `IValueConnector`: + - `ToArtifactAsync(...)` + - `FromArtifactAsync(...)` +- `IServiceConnector`: + - `GetArtifactAsync(...)` + - `ProcessInitAsync(...)` + - `ProcessAsync(...)` + - `ExpandRangeAsync(...)` + - `GetRangeAsync(...)` + +These methods all have a default implementation that forwards the calls to the synchronous methods (to maintain backwards compatibility). The synchronous methods have been obsoleted and Deploy will now always call the new asynchronous methods. Implementations should be updated to start using those instead. + +Within Deploy, the following base classes and methods have been updated to take advantage of the asynchronous methods: +- `ValueConnectorBase`, `RecursiveValueConnectorBase`, `DataTypeConfigurationConnectorBase` and `ServiceConnectorBase`: all synchronous methods are obsoleted and cause compiler errors when directly invoked (to avoid potential deadlocks, because they all forward to the asynchronous methods using `GetAwaiter().GetResult()`); +- All service and value connector implementations inheriting from the above base classes have been updated to use the asynchronous methods as well; +- `builder.DeployDataTypeConfigurationConnectors().AddCustom(...)`: both `toArtifact` and `fromArtifact` parameters now align with the `ToArtifactAsync(...)` and `FromArtifactAsync(...)` method signatures; +- `IArtifactImportExportService.ExportArtifactsAsync(...)`: the artifacts parameter is updated to `IAsyncEnumerable`, so artifacts are asynchronously created when iterating; +- `IServiceConnector.GetArtifactsAsync(...)` and `IServiceConnectorFactory.GetArtifactsAsync(...)`: these new extension methods call `GetArtifactAsync(...)` on the relevant service connectors and returns `IAsyncEnumerable`. + +#### Signature notification handling +Deploy stores artifact signatures (hashes) in the database to avoid creating the artifact to for example compare them between disk/database or environments. To ensure the signatures are always up-to-date, the `ISignatureService` used custom notification handling via the `RegisterHandler(...)` and `HandleExternalNotification(...)` methods (because Deploy suppresses notifications during deployment). CMS version 12 introduced the `IDistributedCacheNotificationHandler` marker interface and Deploy 12 the `IDeployRefresherNotificationHandler` that will still handle the notifications during deployments. The following methods are therefore removed: +- `RegisterHandler(...)`: register your handler using the standard `builder.AddNotificationHandler<>()` or `builder.AddNotificationAsyncHandler()` method; +- `HandleExternalNotification(...)`: implement your handler using `IDeployRefresherNotificationHandler` or `IDeployRefresherNotificationAsyncHandler`. + +#### Return type of Data Type configuration has changed to a dictionary +The return type of `IDataTypeConfigurationConnector.FromArtifact()/FromArtifactAsync()` has changed from `object` to `IDictionary` to align with the Data Type configuration changes in the CMS (see [PR #13605](https://github.com/umbraco/Umbraco-CMS/pull/13605)). Also, obsoleted methods and default interface implementations on Deploy interfaces have been removed (see [PR #15965](https://github.com/umbraco/Umbraco-CMS/pull/15965)). + +#### Removed code due to changes in the CMS +The CMS removed support for the legacy Media Picker, Grid layout, Nested Content editors and macros, which means Deploy doesn't provide support for transferring these editors. The following related code has been removed: +- `IGridCellValueConnector`, `IGridCellValueConnector2` and `IGridCellValueConnectorFactory`: including all Grid cell value connector implementations; +- `GridDataTypeConfigurationConnector`, `NestedContentDataTypeConfigurationConnector`; +- `IMacroParser` (in the CMS), `MacroParserBase` and `MacroParser`; +- `MediaPickerValueConnector` and `MacroConnector`. + +#### Backoffice related code/Deploy Management API +Due to the new backoffice, all code related to sections, trees, actions, dashboards and models have been removed or updated. The new backoffice components now also use the Deploy Management API for all operations. + +#### Permissions +Version 14 now uses permission verbs (instead of single characters/action letters) and upgrading will automatically migrate any existing permissions: + +| Letter | Verb | +| -------| --------------------------| +| Q | Deploy.EnvironmentRestore | +| Ψ | Deploy.TreeRestore | +| Ø | Deploy.PartialRestore | +| T | Deploy.QueueForTransfer | +| П | Deploy.Export | +| Џ | Deploy.Import | + +##### JSON artifact migrators +The `IArtifactJsonMigrator.Migrate(...)` method now accepts/returns a `JsonNode` value (instead of `JToken`) due to the change from Newtonsoft.Json to System.Text.Json. + +### **Behavior** + +#### JSON serialization +Deploy artifacts are serialized as JSON, either stored as schema on disk (UDA files in `umbraco\Deploy\Revision`), exported into a ZIP archive or when being transferred between environments. We aligned with the CMS and migrated to use System.Text.Json (instead of Newtonsoft.Json). Although we've not changed the artifacts themselves, these libraries have [differences in default behavior](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft?pivots=dotnet-8-0). + +#### No-nodes page environment restore +An empty local environment previously had the option to do an environment restore without logging in to the backoffice. This option now redirects you to the backoffice and once logged in, will show a modal to deploy the schema and restore all content from the upstream environment. + +#### Uploaded files for import +Deploy now uses the `ITemporaryFileService` from the CMS to temporarily store the uploaded ZIP archive to import. This also means the cleanup is handled by the CMS and the 'Delete import archives' Deploy operation and support for the `deploy-deleteimportarchives` trigger file are removed. + +### **Configuration** + +#### Deploy On-prem license key +For Deploy On-premise, configuring the license key has slightly changed, as we introduced additional options for license validation. The product license keys should be moved to the following structure: + +```json +{ + "Umbraco": { + "Licenses": { + "Products": { + "Umbraco.Deploy.OnPrem": "" + }, + + } + } +} +``` + +#### Transfer forms as content +The setting `TransferFormsAsContent` has moved to `FormsDeploySettings` in the Forms Deploy package. It is still bound to the `Umbraco:Deploy:Settings:TransferFormsAsContent` configuration key (used in previous versions), so it only affects configuration via code. + +### **Dependencies** +* Umbraco CMS dependency was updated to `14.0.0`. + +## 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-deploy/upgrades/version-specific.md). \ No newline at end of file diff --git a/14/umbraco-forms/.gitbook.yaml b/14/umbraco-forms/.gitbook.yaml new file mode 100644 index 00000000000..8865254d413 --- /dev/null +++ b/14/umbraco-forms/.gitbook.yaml @@ -0,0 +1,10 @@ +root: ./ + +​structure: + readme: README.md + summary: SUMMARY.md + +redirects: + the-licensing-model: installation/the-licensing-model.md + installation/manualupgrade: upgrading/manualupgrade.md + installation/version-specific: upgrading/version-specific.md diff --git a/14/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_ (1).png b/14/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/14/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_ (1).png differ diff --git a/14/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_.png b/14/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/14/umbraco-forms/.gitbook/assets/Blog_post_for_com_900x400px_1_8_7_.png differ diff --git a/14/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete (1).png b/14/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete (1).png new file mode 100644 index 00000000000..148c59918e3 Binary files /dev/null and b/14/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete (1).png differ diff --git a/14/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete.png b/14/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete.png new file mode 100644 index 00000000000..148c59918e3 Binary files /dev/null and b/14/umbraco-forms/.gitbook/assets/FormSettingsAutocomplete.png differ diff --git a/14/umbraco-forms/.gitbook/assets/FormSettingsFieldsDisplayed.png b/14/umbraco-forms/.gitbook/assets/FormSettingsFieldsDisplayed.png new file mode 100644 index 00000000000..18cc4170619 Binary files /dev/null and b/14/umbraco-forms/.gitbook/assets/FormSettingsFieldsDisplayed.png differ diff --git a/14/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80 (1).jpg b/14/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/14/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80 (1).jpg differ diff --git a/14/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80.jpg b/14/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/14/umbraco-forms/.gitbook/assets/Umbraco 9.3RC- Blog_post_for_com_900x400px_1@2x-80.jpg differ diff --git a/14/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px (1).png b/14/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px (1).png new file mode 100644 index 00000000000..824e289115a Binary files /dev/null and b/14/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px (1).png differ diff --git a/14/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px.png b/14/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px.png new file mode 100644 index 00000000000..824e289115a Binary files /dev/null and b/14/umbraco-forms/.gitbook/assets/_packageBlog_post_for_com_900x400px.png differ diff --git a/14/umbraco-forms/.gitbook/assets/image.png b/14/umbraco-forms/.gitbook/assets/image.png new file mode 100644 index 00000000000..002dbcbe5c8 Binary files /dev/null and b/14/umbraco-forms/.gitbook/assets/image.png differ diff --git a/14/umbraco-forms/.gitbook/assets/umbraco_forms_swagger.json b/14/umbraco-forms/.gitbook/assets/umbraco_forms_swagger.json new file mode 100644 index 00000000000..360a0c02bf4 --- /dev/null +++ b/14/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/14/umbraco-forms/README.md b/14/umbraco-forms/README.md new file mode 100644 index 00000000000..5709fcb33dc --- /dev/null +++ b/14/umbraco-forms/README.md @@ -0,0 +1,29 @@ +--- +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 workflow 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
+ +{% embed url="" %} + +## Quick Links + +{% content-ref url="upgrading/manualupgrade.md" %} +[upgrading/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/14/umbraco-forms/SUMMARY.md b/14/umbraco-forms/SUMMARY.md new file mode 100644 index 00000000000..711c3dfbb64 --- /dev/null +++ b/14/umbraco-forms/SUMMARY.md @@ -0,0 +1,76 @@ +# 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 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/blocklistfilters.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/14/umbraco-forms/developer/ajaxforms.md b/14/umbraco-forms/developer/ajaxforms.md new file mode 100644 index 00000000000..ba1e678dab6 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/blocklistfilters.md b/14/umbraco-forms/developer/blocklistfilters.md new file mode 100644 index 00000000000..c522271a943 --- /dev/null +++ b/14/umbraco-forms/developer/blocklistfilters.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/14/umbraco-forms/developer/configuration/README.md b/14/umbraco-forms/developer/configuration/README.md new file mode 100644 index 00000000000..c6dde0aedbe --- /dev/null +++ b/14/umbraco-forms/developer/configuration/README.md @@ -0,0 +1,571 @@ +--- +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" + }, + "RemoveProvidedEmailTemplate": false, + "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": 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": false + }, + "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. + +### RemoveProvidedEmailTemplate + +The provided template can be removed from the selection if you have created email templates for the "send Razor email" workflow. To do this, set this value to `true`. + +### 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 here](type-details.md). + +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 disable 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 `false`. This ensures that, in an upgrade scenario, before the feature is used the necessary styling and/or theme updates can be prepared. + +To make the feature available to editors 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 + +By default the validation message returned from a failed reCAPTCHA 3 request will be displayed only in the form level validation summary. + +To render also at a field level, set this value to `true`. + +We expect to make the default value for this option `true` in Umbraco Forms 15. + +### 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/14/umbraco-forms/developer/configuration/type-details.md b/14/umbraco-forms/developer/configuration/type-details.md new file mode 100644 index 00000000000..3ea7f40e003 --- /dev/null +++ b/14/umbraco-forms/developer/configuration/type-details.md @@ -0,0 +1,528 @@ +--- +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` +* `ShowLabel` +* `AriaLabel` + +
+ +
+ +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/14/umbraco-forms/developer/custom-markup.md b/14/umbraco-forms/developer/custom-markup.md new file mode 100644 index 00000000000..65d29f0059a --- /dev/null +++ b/14/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/14/umbraco-forms/developer/email-templates.md b/14/umbraco-forms/developer/email-templates.md new file mode 100644 index 00000000000..6e175528457 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/README.md b/14/umbraco-forms/developer/extending/README.md new file mode 100644 index 00000000000..635b9fd8f8e --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/adding-a-exporttype.md b/14/umbraco-forms/developer/extending/adding-a-exporttype.md new file mode 100644 index 00000000000..22495e7db8b --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/adding-a-fieldtype.md b/14/umbraco-forms/developer/extending/adding-a-fieldtype.md new file mode 100644 index 00000000000..9999fdd7275 --- /dev/null +++ b/14/umbraco-forms/developer/extending/adding-a-fieldtype.md @@ -0,0 +1,513 @@ +# 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.md#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/extension-registry"; +import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element"; +import { + UmbPropertyValueChangeEvent, +} from "@umbraco-cms/backoffice/property-editor"; +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 UmbPropertyValueChangeEvent()); + } + + 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/extension-registry"; +import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element"; +import { + UmbPropertyValueChangeEvent, +} from "@umbraco-cms/backoffice/property-editor"; +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 UmbPropertyValueChangeEvent()); + } + + 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 are translated via language files. 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/extension-registry"; + +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/14/umbraco-forms/developer/extending/adding-a-magic-string-format-function.md b/14/umbraco-forms/developer/extending/adding-a-magic-string-format-function.md new file mode 100644 index 00000000000..e7fcd23d89a --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/adding-a-prevaluesourcetype.md b/14/umbraco-forms/developer/extending/adding-a-prevaluesourcetype.md new file mode 100644 index 00000000000..e7535c9526d --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/adding-a-type.md b/14/umbraco-forms/developer/extending/adding-a-type.md new file mode 100644 index 00000000000..c1b1784e3dc --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/adding-a-validation-pattern.md b/14/umbraco-forms/developer/extending/adding-a-validation-pattern.md new file mode 100644 index 00000000000..dc7ace93bb3 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/adding-a-workflowtype.md b/14/umbraco-forms/developer/extending/adding-a-workflowtype.md new file mode 100644 index 00000000000..019f24f030d --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/adding-an-event-handler.md b/14/umbraco-forms/developer/extending/adding-an-event-handler.md new file mode 100644 index 00000000000..0a6736dcdd9 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/customize-default-workflows.md b/14/umbraco-forms/developer/extending/customize-default-workflows.md new file mode 100644 index 00000000000..cd420da3ca3 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/excluding-a-built-in-field.md b/14/umbraco-forms/developer/extending/excluding-a-built-in-field.md new file mode 100644 index 00000000000..9714474a3e0 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/extending/images/text-with-field-picker.png b/14/umbraco-forms/developer/extending/images/text-with-field-picker.png new file mode 100644 index 00000000000..bc822cbc599 Binary files /dev/null and b/14/umbraco-forms/developer/extending/images/text-with-field-picker.png differ diff --git a/14/umbraco-forms/developer/extending/setting-types.md b/14/umbraco-forms/developer/extending/setting-types.md new file mode 100644 index 00000000000..3918acdcc0b --- /dev/null +++ b/14/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 custom field type](./adding-a-fieldtype.md#field-settings). diff --git a/14/umbraco-forms/developer/field-types.md b/14/umbraco-forms/developer/field-types.md new file mode 100644 index 00000000000..e6f058dd377 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.0.0.zip b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.0.0.zip new file mode 100644 index 00000000000..259a3800311 Binary files /dev/null and b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.0.0.zip differ diff --git a/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.0.1.zip b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.0.1.zip new file mode 100644 index 00000000000..9e8eef543d9 Binary files /dev/null and b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.0.1.zip differ diff --git a/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.1.0.zip b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.1.0.zip new file mode 100644 index 00000000000..0c7a79230c4 Binary files /dev/null and b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.1.0.zip differ diff --git a/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.1.4.zip b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.1.4.zip new file mode 100644 index 00000000000..495887875c7 Binary files /dev/null and b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.1.4.zip differ diff --git a/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.2.0.zip b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.2.0.zip new file mode 100644 index 00000000000..65651543110 Binary files /dev/null and b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.2.0.zip differ diff --git a/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.2.4.zip b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.2.4.zip new file mode 100644 index 00000000000..03e372d63c2 Binary files /dev/null and b/14/umbraco-forms/developer/files/umbraco-forms-default-theme-14.2.4.zip differ diff --git a/14/umbraco-forms/developer/forms-in-the-database.md b/14/umbraco-forms/developer/forms-in-the-database.md new file mode 100644 index 00000000000..e49ef383ec9 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/healthchecks/README.md b/14/umbraco-forms/developer/healthchecks/README.md new file mode 100644 index 00000000000..d9b34c2e10b --- /dev/null +++ b/14/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/14/umbraco-forms/developer/healthchecks/apply-keys.md b/14/umbraco-forms/developer/healthchecks/apply-keys.md new file mode 100644 index 00000000000..2a1213bd225 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/healthchecks/forms-in-the-database-apply-keys.md b/14/umbraco-forms/developer/healthchecks/forms-in-the-database-apply-keys.md new file mode 100644 index 00000000000..814bf15930d --- /dev/null +++ b/14/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/14/umbraco-forms/developer/healthchecks/images/Umb-backoffice.png b/14/umbraco-forms/developer/healthchecks/images/Umb-backoffice.png new file mode 100644 index 00000000000..7c006f92ca1 Binary files /dev/null and b/14/umbraco-forms/developer/healthchecks/images/Umb-backoffice.png differ diff --git a/14/umbraco-forms/developer/healthchecks/images/healthcheck-v14.png b/14/umbraco-forms/developer/healthchecks/images/healthcheck-v14.png new file mode 100644 index 00000000000..eb16cd812d5 Binary files /dev/null and b/14/umbraco-forms/developer/healthchecks/images/healthcheck-v14.png differ diff --git a/14/umbraco-forms/developer/healthchecks/images/healthcheck.png b/14/umbraco-forms/developer/healthchecks/images/healthcheck.png new file mode 100644 index 00000000000..c701f83f778 Binary files /dev/null and b/14/umbraco-forms/developer/healthchecks/images/healthcheck.png differ diff --git a/14/umbraco-forms/developer/images/assign-sensitive-data-to-user.png b/14/umbraco-forms/developer/images/assign-sensitive-data-to-user.png new file mode 100644 index 00000000000..a1cafe90d27 Binary files /dev/null and b/14/umbraco-forms/developer/images/assign-sensitive-data-to-user.png differ diff --git a/14/umbraco-forms/developer/images/content-app.png b/14/umbraco-forms/developer/images/content-app.png new file mode 100644 index 00000000000..2ebbfbbf08a Binary files /dev/null and b/14/umbraco-forms/developer/images/content-app.png differ diff --git a/14/umbraco-forms/developer/images/exclude-scripts-v9.png b/14/umbraco-forms/developer/images/exclude-scripts-v9.png new file mode 100644 index 00000000000..d592b5e73d6 Binary files /dev/null and b/14/umbraco-forms/developer/images/exclude-scripts-v9.png differ diff --git a/14/umbraco-forms/developer/images/exclude-scripts.png b/14/umbraco-forms/developer/images/exclude-scripts.png new file mode 100644 index 00000000000..571bd847008 Binary files /dev/null and b/14/umbraco-forms/developer/images/exclude-scripts.png differ diff --git a/14/umbraco-forms/developer/images/form-guid.png b/14/umbraco-forms/developer/images/form-guid.png new file mode 100644 index 00000000000..71a21c7618c Binary files /dev/null and b/14/umbraco-forms/developer/images/form-guid.png differ diff --git a/14/umbraco-forms/developer/images/form-picker-config.png b/14/umbraco-forms/developer/images/form-picker-config.png new file mode 100644 index 00000000000..d7c600b894e Binary files /dev/null and b/14/umbraco-forms/developer/images/form-picker-config.png differ diff --git a/14/umbraco-forms/developer/images/form-pickers.png b/14/umbraco-forms/developer/images/form-pickers.png new file mode 100644 index 00000000000..037e25fabe0 Binary files /dev/null and b/14/umbraco-forms/developer/images/form-pickers.png differ diff --git a/14/umbraco-forms/developer/images/mark-field-as-sensitive.png b/14/umbraco-forms/developer/images/mark-field-as-sensitive.png new file mode 100644 index 00000000000..06f2496feab Binary files /dev/null and b/14/umbraco-forms/developer/images/mark-field-as-sensitive.png differ diff --git a/14/umbraco-forms/developer/images/select-a-theme.png b/14/umbraco-forms/developer/images/select-a-theme.png new file mode 100644 index 00000000000..985dd572041 Binary files /dev/null and b/14/umbraco-forms/developer/images/select-a-theme.png differ diff --git a/14/umbraco-forms/developer/images/sensitive-data-field.png b/14/umbraco-forms/developer/images/sensitive-data-field.png new file mode 100644 index 00000000000..82243d3840d Binary files /dev/null and b/14/umbraco-forms/developer/images/sensitive-data-field.png differ diff --git a/14/umbraco-forms/developer/images/swagger-ui.png b/14/umbraco-forms/developer/images/swagger-ui.png new file mode 100644 index 00000000000..51358f36b64 Binary files /dev/null and b/14/umbraco-forms/developer/images/swagger-ui.png differ diff --git a/14/umbraco-forms/developer/images/user-group-permissions.png b/14/umbraco-forms/developer/images/user-group-permissions.png new file mode 100644 index 00000000000..43e7df5cb94 Binary files /dev/null and b/14/umbraco-forms/developer/images/user-group-permissions.png differ diff --git a/14/umbraco-forms/developer/images/user-start-folders-v14.png b/14/umbraco-forms/developer/images/user-start-folders-v14.png new file mode 100644 index 00000000000..d0df3ca2c23 Binary files /dev/null and b/14/umbraco-forms/developer/images/user-start-folders-v14.png differ diff --git a/14/umbraco-forms/developer/images/user-start-folders.png b/14/umbraco-forms/developer/images/user-start-folders.png new file mode 100644 index 00000000000..ff01a21c28c Binary files /dev/null and b/14/umbraco-forms/developer/images/user-start-folders.png differ diff --git a/14/umbraco-forms/developer/images/validation-pattern.png b/14/umbraco-forms/developer/images/validation-pattern.png new file mode 100644 index 00000000000..e90ec8642dc Binary files /dev/null and b/14/umbraco-forms/developer/images/validation-pattern.png differ diff --git a/14/umbraco-forms/developer/images/wehbook-events-v14.png b/14/umbraco-forms/developer/images/wehbook-events-v14.png new file mode 100644 index 00000000000..5d737e3c0c9 Binary files /dev/null and b/14/umbraco-forms/developer/images/wehbook-events-v14.png differ diff --git a/14/umbraco-forms/developer/images/wehbook-events.png b/14/umbraco-forms/developer/images/wehbook-events.png new file mode 100644 index 00000000000..c8ad67f92a3 Binary files /dev/null and b/14/umbraco-forms/developer/images/wehbook-events.png differ diff --git a/14/umbraco-forms/developer/iprevaluetextfilestorage.md b/14/umbraco-forms/developer/iprevaluetextfilestorage.md new file mode 100644 index 00000000000..d25103de140 --- /dev/null +++ b/14/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/14/umbraco-forms/developer/localization.md b/14/umbraco-forms/developer/localization.md new file mode 100644 index 00000000000..c2cefbd7512 --- /dev/null +++ b/14/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`) + - Spanish (`es-es.js`) + - French (`fr-fr.js`) + - Italian (`it-it.js`) + - Polish (`pl-pl.js`) + - UK English (`en-gb.js`) + - US English (`en-us.js`) + - Dutch (`nl-nl.js`) + +If the language you require does not exist, it's possible to create your own by duplicating the default `en-us.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-us.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/14/umbraco-forms/developer/magic-strings.md b/14/umbraco-forms/developer/magic-strings.md new file mode 100644 index 00000000000..5e8d9da683f --- /dev/null +++ b/14/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/14/umbraco-forms/developer/prepping-frontend.md b/14/umbraco-forms/developer/prepping-frontend.md new file mode 100644 index 00000000000..61217d57cdb --- /dev/null +++ b/14/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/14/umbraco-forms/developer/property-editors.md b/14/umbraco-forms/developer/property-editors.md new file mode 100644 index 00000000000..5789e0b4a17 --- /dev/null +++ b/14/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 in the [Working with the CMS Content Delivery API](./ajaxforms.md#working-with-the-cms-content-delivery-api) article. diff --git a/14/umbraco-forms/developer/rendering-forms.md b/14/umbraco-forms/developer/rendering-forms.md new file mode 100644 index 00000000000..9e5b31ff10f --- /dev/null +++ b/14/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/14/umbraco-forms/developer/rendering-scripts.md b/14/umbraco-forms/developer/rendering-scripts.md new file mode 100644 index 00000000000..fc99f1dcfdb --- /dev/null +++ b/14/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/14/umbraco-forms/developer/security.md b/14/umbraco-forms/developer/security.md new file mode 100644 index 00000000000..df6ea219a39 --- /dev/null +++ b/14/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) diff --git a/14/umbraco-forms/developer/themes.md b/14/umbraco-forms/developer/themes.md new file mode 100644 index 00000000000..5255d03f87e --- /dev/null +++ b/14/umbraco-forms/developer/themes.md @@ -0,0 +1,198 @@ +--- +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 version of the Forms default theme from the following links: + +* [14.0.0](./files/umbraco-forms-default-theme-14.0.0.zip) +* [14.0.1](./files/umbraco-forms-default-theme-14.0.1.zip) +* [14.1.0](./files/umbraco-forms-default-theme-14.1.0.zip) +* [14.1.4](./files/umbraco-forms-default-theme-14.1.4.zip) +* [14.2.0](./files/umbraco-forms-default-theme-14.2.0.zip) +* [14.2.4](./files/umbraco-forms-default-theme-14.2.4.zip) + +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 14.1.2, and no file for that version is available use version 14.1.0 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. + +From Forms 14.2 it is 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 Themes 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/14/umbraco-forms/developer/webhooks.md b/14/umbraco-forms/developer/webhooks.md new file mode 100644 index 00000000000..790d2d77a8d --- /dev/null +++ b/14/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/14/umbraco-forms/developer/working-with-data.md b/14/umbraco-forms/developer/working-with-data.md new file mode 100644 index 00000000000..eb4ef07555a --- /dev/null +++ b/14/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/14/umbraco-forms/editor/attaching-workflows/README.md b/14/umbraco-forms/editor/attaching-workflows/README.md new file mode 100644 index 00000000000..2885acb1e55 --- /dev/null +++ b/14/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/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit-v14.png new file mode 100644 index 00000000000..85a648b5bc1 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit.png b/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit.png new file mode 100644 index 00000000000..60cd7c57306 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmit.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText-v14.png new file mode 100644 index 00000000000..1d89cf21e13 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText.png b/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText.png new file mode 100644 index 00000000000..49b67e2cff7 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/MessageOnSubmitRichText.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowOverview.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowOverview.png new file mode 100644 index 00000000000..f156cca1d26 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowOverview.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/Workflownode.png b/14/umbraco-forms/editor/attaching-workflows/images/Workflownode.png new file mode 100644 index 00000000000..c236ee78763 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/Workflownode.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModal.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModal.png new file mode 100644 index 00000000000..3039c8ddd0f Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModal.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel-v14.png new file mode 100644 index 00000000000..5eaa074a6e8 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel.png new file mode 100644 index 00000000000..66598e8f552 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsAddModel.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage-v14.png new file mode 100644 index 00000000000..e6c0a82009c Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage.png new file mode 100644 index 00000000000..01815fa21e2 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPage.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAdd.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAdd.png new file mode 100644 index 00000000000..d924d7e420a Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAdd.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddAdd.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddAdd.png new file mode 100644 index 00000000000..49468a6b78f Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddAdd.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSelectType.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSelectType.png new file mode 100644 index 00000000000..1de9c4fc42f Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSelectType.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSubmit.PNG b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSubmit.PNG new file mode 100644 index 00000000000..544ea10c7c5 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddSubmit.PNG differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddTypeSettings.png b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddTypeSettings.png new file mode 100644 index 00000000000..c34d27e5e45 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/WorkflowsPageAddTypeSettings.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/change-record-state-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/change-record-state-v14.png new file mode 100644 index 00000000000..8153682ffde Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/change-record-state-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/change-record-state.png b/14/umbraco-forms/editor/attaching-workflows/images/change-record-state.png new file mode 100644 index 00000000000..85a3e5f177f Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/change-record-state.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/configure-workflows-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/configure-workflows-v14.png new file mode 100644 index 00000000000..7951c5b6f24 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/configure-workflows-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/configure-workflows.png b/14/umbraco-forms/editor/attaching-workflows/images/configure-workflows.png new file mode 100644 index 00000000000..a1419f8c13c Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/configure-workflows.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/create-new-node.png b/14/umbraco-forms/editor/attaching-workflows/images/create-new-node.png new file mode 100644 index 00000000000..fbf73980957 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/create-new-node.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/email-slack-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/email-slack-v14.png new file mode 100644 index 00000000000..202af5757e0 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/email-slack-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/email-slack.png b/14/umbraco-forms/editor/attaching-workflows/images/email-slack.png new file mode 100644 index 00000000000..03c8585713d Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/email-slack.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/post-as-xml-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/post-as-xml-v14.png new file mode 100644 index 00000000000..5d04edbb4ff Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/post-as-xml-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/post-as-xml.png b/14/umbraco-forms/editor/attaching-workflows/images/post-as-xml.png new file mode 100644 index 00000000000..ed22ad754a5 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/post-as-xml.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file-v14.png b/14/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/14/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file.png b/14/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/14/umbraco-forms/editor/attaching-workflows/images/save-as-an-xml-file.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/save-as-content-node-v14.png b/14/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/14/umbraco-forms/editor/attaching-workflows/images/save-as-content-node-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/save-as-content-node.png b/14/umbraco-forms/editor/attaching-workflows/images/save-as-content-node.png new file mode 100644 index 00000000000..394b3f0c5d0 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/save-as-content-node.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/send-email-razor-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/send-email-razor-v14.png new file mode 100644 index 00000000000..5710b6b84f8 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/send-email-razor-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/send-email-razor.png b/14/umbraco-forms/editor/attaching-workflows/images/send-email-razor.png new file mode 100644 index 00000000000..59cbe74aa75 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/send-email-razor.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/send-email-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/send-email-v14.png new file mode 100644 index 00000000000..b0efad6e23a Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/send-email-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/send-email.png b/14/umbraco-forms/editor/attaching-workflows/images/send-email.png new file mode 100644 index 00000000000..96b67e0ceb5 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/send-email.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/send-to-URL-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/send-to-URL-v14.png new file mode 100644 index 00000000000..3fad02e3ed2 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/send-to-URL-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/send-to-URL.png b/14/umbraco-forms/editor/attaching-workflows/images/send-to-URL.png new file mode 100644 index 00000000000..40b1ff4dfad Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/send-to-URL.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/workflow-audit.png b/14/umbraco-forms/editor/attaching-workflows/images/workflow-audit.png new file mode 100644 index 00000000000..2f4b33b5502 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/workflow-audit.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/workflow-conditions.png b/14/umbraco-forms/editor/attaching-workflows/images/workflow-conditions.png new file mode 100644 index 00000000000..c40623927ca Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/workflow-conditions.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/workflow-summary.png b/14/umbraco-forms/editor/attaching-workflows/images/workflow-summary.png new file mode 100644 index 00000000000..cb1553920b8 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/workflow-summary.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/workflowbutton.png b/14/umbraco-forms/editor/attaching-workflows/images/workflowbutton.png new file mode 100644 index 00000000000..734758ffc9e Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/workflowbutton.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/xslt-email-v14.png b/14/umbraco-forms/editor/attaching-workflows/images/xslt-email-v14.png new file mode 100644 index 00000000000..098799744ba Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/xslt-email-v14.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/images/xslt-email.png b/14/umbraco-forms/editor/attaching-workflows/images/xslt-email.png new file mode 100644 index 00000000000..faa1e070fd8 Binary files /dev/null and b/14/umbraco-forms/editor/attaching-workflows/images/xslt-email.png differ diff --git a/14/umbraco-forms/editor/attaching-workflows/workflow-types.md b/14/umbraco-forms/editor/attaching-workflows/workflow-types.md new file mode 100644 index 00000000000..4142596f260 --- /dev/null +++ b/14/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/14/umbraco-forms/editor/creating-a-form/README.md b/14/umbraco-forms/editor/creating-a-form/README.md new file mode 100644 index 00000000000..70a2086f24a --- /dev/null +++ b/14/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/14/umbraco-forms/editor/creating-a-form/conditional-logic.md b/14/umbraco-forms/editor/creating-a-form/conditional-logic.md new file mode 100644 index 00000000000..4ee8c8c0511 --- /dev/null +++ b/14/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/14/umbraco-forms/editor/creating-a-form/fieldtypes/README.md b/14/umbraco-forms/editor/creating-a-form/fieldtypes/README.md new file mode 100644 index 00000000000..f36c166aeb5 --- /dev/null +++ b/14/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/14/umbraco-forms/editor/creating-a-form/fieldtypes/date.md b/14/umbraco-forms/editor/creating-a-form/fieldtypes/date.md new file mode 100644 index 00000000000..73f841dc893 --- /dev/null +++ b/14/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/14/umbraco-forms/editor/creating-a-form/fieldtypes/fileupload.md b/14/umbraco-forms/editor/creating-a-form/fieldtypes/fileupload.md new file mode 100644 index 00000000000..4a201ca618b --- /dev/null +++ b/14/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/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v14.png new file mode 100644 index 00000000000..0236d22b7bd Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v9.png new file mode 100644 index 00000000000..b25bb9e7981 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox.png new file mode 100644 index 00000000000..83e772f6d8f Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/CheckBox.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v14.png new file mode 100644 index 00000000000..c79ab2a79b7 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v9.png new file mode 100644 index 00000000000..5593e50daed Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent.png new file mode 100644 index 00000000000..6212b9aaa08 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dataconsent.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-picker.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-picker.png new file mode 100644 index 00000000000..88438cf1128 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-picker.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v14.png new file mode 100644 index 00000000000..97e766caeb8 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v9.png new file mode 100644 index 00000000000..a7120c5bd61 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date.PNG b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date.PNG new file mode 100644 index 00000000000..29b4381bcbb Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/date.PNG differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v14.png new file mode 100644 index 00000000000..675c49aef4c Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v9.png new file mode 100644 index 00000000000..449893930f3 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown.PNG b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown.PNG new file mode 100644 index 00000000000..6e91b9d23f6 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/dropdown.PNG differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types.png new file mode 100644 index 00000000000..f00c05c4fc2 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-types.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v14.png new file mode 100644 index 00000000000..a0dbb52c581 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v9.png new file mode 100644 index 00000000000..4e60329f2fc Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload.png new file mode 100644 index 00000000000..f80a306f364 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/fileupload.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v14.png new file mode 100644 index 00000000000..bfdfe08a630 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v9.png new file mode 100644 index 00000000000..5ab1c600a3e Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden.PNG b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden.PNG new file mode 100644 index 00000000000..bc9f9ce9fa1 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/hidden.PNG differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v14.png new file mode 100644 index 00000000000..009387ada19 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v9.png new file mode 100644 index 00000000000..9980b404ede Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer.PNG b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer.PNG new file mode 100644 index 00000000000..077b1b2c7dc Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/longanswer.PNG differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v14.png new file mode 100644 index 00000000000..1e09a543229 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v9.png new file mode 100644 index 00000000000..d1a37cedf1c Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice.PNG b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice.PNG new file mode 100644 index 00000000000..8d3344212e7 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/multiplechoice.PNG differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v14.png new file mode 100644 index 00000000000..94909e503df Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v9.png new file mode 100644 index 00000000000..c771733f6f7 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/password-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/password.PNG b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/password.PNG new file mode 100644 index 00000000000..6ed6590fd8d Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/password.PNG differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v14.png new file mode 100644 index 00000000000..87d6f6e63c6 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v9.png new file mode 100644 index 00000000000..c5de9019855 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2.png new file mode 100644 index 00000000000..2ae28bcf014 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha2.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v14.png new file mode 100644 index 00000000000..c68b59b5eb3 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v9.png new file mode 100644 index 00000000000..41d9316ede4 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/recaptcha3-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext-v14.png new file mode 100644 index 00000000000..0ec23abba93 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext.png new file mode 100644 index 00000000000..da89d3394cc Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/richtext.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-V14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-V14.png new file mode 100644 index 00000000000..95dfabe1fca Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-v9.png new file mode 100644 index 00000000000..6e504b4aa61 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer.PNG b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer.PNG new file mode 100644 index 00000000000..bf130226f3b Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/shortanswer.PNG differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v14.png new file mode 100644 index 00000000000..1c36d09f476 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v9.png new file mode 100644 index 00000000000..f175439fd32 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice.PNG b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice.PNG new file mode 100644 index 00000000000..589dbd4d563 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/singlechoice.PNG differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v14.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v14.png new file mode 100644 index 00000000000..00b2877899d Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v9.png b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v9.png new file mode 100644 index 00000000000..1260f8cb9d2 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription.PNG b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription.PNG new file mode 100644 index 00000000000..02c2187853d Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/fieldtypes/images/titleanddescription.PNG differ diff --git a/14/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha2.md b/14/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha2.md new file mode 100644 index 00000000000..6ee355bd82d --- /dev/null +++ b/14/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/14/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha3.md b/14/umbraco-forms/editor/creating-a-form/fieldtypes/recaptcha3.md new file mode 100644 index 00000000000..e8d23ca9bc4 --- /dev/null +++ b/14/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/14/umbraco-forms/editor/creating-a-form/form-info.md b/14/umbraco-forms/editor/creating-a-form/form-info.md new file mode 100644 index 00000000000..ce615b50b51 --- /dev/null +++ b/14/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/14/umbraco-forms/editor/creating-a-form/form-settings.md b/14/umbraco-forms/editor/creating-a-form/form-settings.md new file mode 100644 index 00000000000..2139b30efed --- /dev/null +++ b/14/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 validations 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/14/umbraco-forms/editor/creating-a-form/images/ContentExampleMacroButton.png b/14/umbraco-forms/editor/creating-a-form/images/ContentExampleMacroButton.png new file mode 100644 index 00000000000..6eb9af9ba2a Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentExampleMacroButton.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentExamples-v14.png b/14/umbraco-forms/editor/creating-a-form/images/ContentExamples-v14.png new file mode 100644 index 00000000000..1631e9aa17f Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentExamples-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentExamples.png b/14/umbraco-forms/editor/creating-a-form/images/ContentExamples.png new file mode 100644 index 00000000000..4788a8051cb Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentExamples.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithForm.png b/14/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithForm.png new file mode 100644 index 00000000000..fbfac9ec1e2 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithForm.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithFormV14.png b/14/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithFormV14.png new file mode 100644 index 00000000000..aad96c12297 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentExamplesWithFormV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentPage.png b/14/umbraco-forms/editor/creating-a-form/images/ContentPage.png new file mode 100644 index 00000000000..4f69f96fbb9 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentPage.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentPageAddForm-v14.png b/14/umbraco-forms/editor/creating-a-form/images/ContentPageAddForm-v14.png new file mode 100644 index 00000000000..8193eb6a31d Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentPageAddForm-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialog.png b/14/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialog.png new file mode 100644 index 00000000000..768d74786e2 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialog.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialogChooseForm.png b/14/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialogChooseForm.png new file mode 100644 index 00000000000..0e7d474a735 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentPageAddMacroDialogChooseForm.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentPageMacroButton.png b/14/umbraco-forms/editor/creating-a-form/images/ContentPageMacroButton.png new file mode 100644 index 00000000000..4b246d8300e Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentPageMacroButton.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ContentPageWithForm.png b/14/umbraco-forms/editor/creating-a-form/images/ContentPageWithForm.png new file mode 100644 index 00000000000..20367d97c3a Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ContentPageWithForm.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/EnableConditions-v9.png b/14/umbraco-forms/editor/creating-a-form/images/EnableConditions-v9.png new file mode 100644 index 00000000000..c966c9dd1b5 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/EnableConditions-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/EnableConditions.png b/14/umbraco-forms/editor/creating-a-form/images/EnableConditions.png new file mode 100644 index 00000000000..6b340b94d29 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/EnableConditions.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ExampleForm-v14.png b/14/umbraco-forms/editor/creating-a-form/images/ExampleForm-v14.png new file mode 100644 index 00000000000..9c511f6dfe5 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ExampleForm-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/ExampleForm.png b/14/umbraco-forms/editor/creating-a-form/images/ExampleForm.png new file mode 100644 index 00000000000..ff0f3e4d85f Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/ExampleForm.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddField.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddField.png new file mode 100644 index 00000000000..8b0e1300dcd Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddField.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialog.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialog.png new file mode 100644 index 00000000000..98dccacddfb Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialog.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV14.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV14.png new file mode 100644 index 00000000000..acca60a6587 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV8.png new file mode 100644 index 00000000000..a3496f28f83 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldDialogV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV14.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV14.png new file mode 100644 index 00000000000..532d3ce4218 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV8.png new file mode 100644 index 00000000000..e299ae2e4c7 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerAddFieldV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAdded.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAdded.png new file mode 100644 index 00000000000..295eea6fb2e Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAdded.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV14.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV14.png new file mode 100644 index 00000000000..df5c3351312 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV8.png new file mode 100644 index 00000000000..dec6a524c71 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFieldAddedV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFormName.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFormName.png new file mode 100644 index 00000000000..44b3416ea87 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFormName.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNameV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNameV8.png new file mode 100644 index 00000000000..d6309410183 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNameV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNamev14.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNamev14.png new file mode 100644 index 00000000000..633800eb6db Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerFormNamev14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaption.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaption.png new file mode 100644 index 00000000000..86f6b8c0da9 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaption.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV14.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV14.png new file mode 100644 index 00000000000..abc1667bf8f Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV8.png new file mode 100644 index 00000000000..d3949955585 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageCaptionV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroup.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroup.png new file mode 100644 index 00000000000..21e7a5cfedb Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroup.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV14.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV14.png new file mode 100644 index 00000000000..2eec93fa39f Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV8.png new file mode 100644 index 00000000000..60b9ba0ec4c Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerPageGroupV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSave.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSave.png new file mode 100644 index 00000000000..9f7d175686c Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSave.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV14.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV14.png new file mode 100644 index 00000000000..14277e102f0 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV8.png new file mode 100644 index 00000000000..65ba8981085 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSaveV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSetFieldCaption.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSetFieldCaption.png new file mode 100644 index 00000000000..cccb58ed6fc Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerSetFieldCaption.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerStart.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerStart.png new file mode 100644 index 00000000000..1c8c630ba2b Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerStart.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV14.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV14.png new file mode 100644 index 00000000000..71d3d2f3908 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV8.png new file mode 100644 index 00000000000..c2d410cc4b8 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormDesignerStartV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettings-V14.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettings-V14.png new file mode 100644 index 00000000000..45713c06409 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettings-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettings.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettings.png new file mode 100644 index 00000000000..75869b154b9 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettings.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete (1).png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete (1).png new file mode 100644 index 00000000000..148c59918e3 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete (1).png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete-V14.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete-V14.png new file mode 100644 index 00000000000..7580de5f9d8 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete.png new file mode 100644 index 00000000000..148c59918e3 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsAutocomplete.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-V14.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-V14.png new file mode 100644 index 00000000000..6cfe5eba5cb Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-v9.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-v9.png new file mode 100644 index 00000000000..47d983ac098 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions.png new file mode 100644 index 00000000000..78aa8931291 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsCaptions.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention-V14.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention-V14.png new file mode 100644 index 00000000000..1285c139069 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention.png new file mode 100644 index 00000000000..9021062ac0a Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsDataRetention.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed-V14.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed-V14.png new file mode 100644 index 00000000000..9193b25fbe4 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed.png new file mode 100644 index 00000000000..18cc4170619 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsFieldsDisplayed.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration-V14.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration-V14.png new file mode 100644 index 00000000000..6ae72c1f72b Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration.png new file mode 100644 index 00000000000..02deafec93d Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsModeration.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling-V14.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling-V14.png new file mode 100644 index 00000000000..bfd37303560 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling.png new file mode 100644 index 00000000000..450a2a8ace6 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsStyling.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation-V14.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation-V14.png new file mode 100644 index 00000000000..d4ec44a8472 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation.png b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation.png new file mode 100644 index 00000000000..ed70a24c4af Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormSettingsValidation.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/Forms-folder-options-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/Forms-folder-options-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialog.png b/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialog.png new file mode 100644 index 00000000000..147cb920f8d Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialog.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV14.png b/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV14.png new file mode 100644 index 00000000000..7a0f7d6c053 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV8.png new file mode 100644 index 00000000000..ed694743220 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV9.png b/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV9.png new file mode 100644 index 00000000000..b607cfdfedc Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsCreateDialogV9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsFieldSettings.gif b/14/umbraco-forms/editor/creating-a-form/images/FormsFieldSettings.gif new file mode 100644 index 00000000000..eee91a2c3f2 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsFieldSettings.gif differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsSection.png b/14/umbraco-forms/editor/creating-a-form/images/FormsSection.png new file mode 100644 index 00000000000..388839d192e Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsSection.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsSectionV14.png b/14/umbraco-forms/editor/creating-a-form/images/FormsSectionV14.png new file mode 100644 index 00000000000..c8cbd01f797 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsSectionV14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsSectionV8.png b/14/umbraco-forms/editor/creating-a-form/images/FormsSectionV8.png new file mode 100644 index 00000000000..d10b6854700 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsSectionV8.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsSectionV9.png b/14/umbraco-forms/editor/creating-a-form/images/FormsSectionV9.png new file mode 100644 index 00000000000..ff9731388e2 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsSectionV9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsTree-v14.png b/14/umbraco-forms/editor/creating-a-form/images/FormsTree-v14.png new file mode 100644 index 00000000000..8d1af3e3ea6 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsTree-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/FormsTree.png b/14/umbraco-forms/editor/creating-a-form/images/FormsTree.png new file mode 100644 index 00000000000..83c8153e016 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/FormsTree.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/Reorder-Form-v14.png b/14/umbraco-forms/editor/creating-a-form/images/Reorder-Form-v14.png new file mode 100644 index 00000000000..e0424f8deb8 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/Reorder-Form-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/Reorder-form-fields-done-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/Reorder-form-fields-done-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/Reorder_Form.png b/14/umbraco-forms/editor/creating-a-form/images/Reorder_Form.png new file mode 100644 index 00000000000..46d08a18cce Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/Reorder_Form.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/Reorder_Form_1.png b/14/umbraco-forms/editor/creating-a-form/images/Reorder_Form_1.png new file mode 100644 index 00000000000..ca5c608127b Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/Reorder_Form_1.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/Store-Records-V14.png b/14/umbraco-forms/editor/creating-a-form/images/Store-Records-V14.png new file mode 100644 index 00000000000..2f1cc088557 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/Store-Records-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/Store-Records.png b/14/umbraco-forms/editor/creating-a-form/images/Store-Records.png new file mode 100644 index 00000000000..4c6b7287dd5 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/Store-Records.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/add-new-group-button-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/add-new-group-button-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/add-new-page-button-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/add-new-page-button-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/add-new-page-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/add-new-page-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/add-new-page.png b/14/umbraco-forms/editor/creating-a-form/images/add-new-page.png new file mode 100644 index 00000000000..c7eccc7a639 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/add-new-page.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/conditions-v14.png b/14/umbraco-forms/editor/creating-a-form/images/conditions-v14.png new file mode 100644 index 00000000000..71ff4f34777 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/conditions-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/conditions-v9.png b/14/umbraco-forms/editor/creating-a-form/images/conditions-v9.png new file mode 100644 index 00000000000..894fa43a1c5 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/conditions-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/conditions.png b/14/umbraco-forms/editor/creating-a-form/images/conditions.png new file mode 100644 index 00000000000..6fa49f4e76d Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/conditions.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/create-forms-folder-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/create-forms-folder-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/edit-group-columns.png b/14/umbraco-forms/editor/creating-a-form/images/edit-group-columns.png new file mode 100644 index 00000000000..a57099f3d6d Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/edit-group-columns.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/email.png b/14/umbraco-forms/editor/creating-a-form/images/email.png new file mode 100644 index 00000000000..bf8baf3211b Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/email.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v14.png b/14/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v14.png new file mode 100644 index 00000000000..c950da37724 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v9.png b/14/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v9.png new file mode 100644 index 00000000000..2a1c0a8d0d5 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/exampleBackoffice-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/exampleBackoffice.png b/14/umbraco-forms/editor/creating-a-form/images/exampleBackoffice.png new file mode 100644 index 00000000000..9e2798b2350 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/exampleBackoffice.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/exampleConditions.png b/14/umbraco-forms/editor/creating-a-form/images/exampleConditions.png new file mode 100644 index 00000000000..47720a8a894 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/exampleConditions.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v14.png b/14/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v14.png new file mode 100644 index 00000000000..3a2c1de6c25 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v9.png b/14/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v9.png new file mode 100644 index 00000000000..1d31ab79570 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/exampleFrontend-v9.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/exampleFrontend.png b/14/umbraco-forms/editor/creating-a-form/images/exampleFrontend.png new file mode 100644 index 00000000000..e400cd61780 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/exampleFrontend.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/form-info-V14.png b/14/umbraco-forms/editor/creating-a-form/images/form-info-V14.png new file mode 100644 index 00000000000..89076d66f75 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/form-info-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/form-info-general-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/form-info-general-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/form-info-general.png b/14/umbraco-forms/editor/creating-a-form/images/form-info-general.png new file mode 100644 index 00000000000..00f228f6e6a Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/form-info-general.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/form-info-references-V14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/form-info-references-V14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/form-info-relations.png b/14/umbraco-forms/editor/creating-a-form/images/form-info-relations.png new file mode 100644 index 00000000000..03eac1b8ec5 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/form-info-relations.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/form-info.png b/14/umbraco-forms/editor/creating-a-form/images/form-info.png new file mode 100644 index 00000000000..f0f8e36d94b Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/form-info.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/forms-folder-name-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/forms-folder-name-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/frontend-email.png b/14/umbraco-forms/editor/creating-a-form/images/frontend-email.png new file mode 100644 index 00000000000..1a30fbcdc0c Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/frontend-email.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/frontend-phone.png b/14/umbraco-forms/editor/creating-a-form/images/frontend-phone.png new file mode 100644 index 00000000000..662b35cec7a Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/frontend-phone.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/import-form.png b/14/umbraco-forms/editor/creating-a-form/images/import-form.png new file mode 100644 index 00000000000..ad5b8c6c180 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/import-form.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/move-form-in-folder-v14.png b/14/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/14/umbraco-forms/editor/creating-a-form/images/move-form-in-folder-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/phone-conditions-v14.png b/14/umbraco-forms/editor/creating-a-form/images/phone-conditions-v14.png new file mode 100644 index 00000000000..1e2425cd03e Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/phone-conditions-v14.png differ diff --git a/14/umbraco-forms/editor/creating-a-form/images/phone.png b/14/umbraco-forms/editor/creating-a-form/images/phone.png new file mode 100644 index 00000000000..77cc3f9a414 Binary files /dev/null and b/14/umbraco-forms/editor/creating-a-form/images/phone.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/README.md b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/README.md new file mode 100644 index 00000000000..5592c0ea01d --- /dev/null +++ b/14/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-v16.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/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource-v14.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource-v14.png new file mode 100644 index 00000000000..fa445776bcf Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource-v14.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource-v16.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource-v16.png new file mode 100644 index 00000000000..99840e59d7a Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource-v16.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource.png new file mode 100644 index 00000000000..c1293a4a9ae Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/FieldPrevalueSource.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/Prevalues-with-caption.png b/14/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/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/Prevalues-with-caption.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/SQLdatabase-v14.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/SQLdatabase-v14.png new file mode 100644 index 00000000000..e5793f6bfe6 Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/SQLdatabase-v14.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/SQLdatabase-v16.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/SQLdatabase-v16.png new file mode 100644 index 00000000000..7cfdf02ae49 Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/SQLdatabase-v16.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype-v14.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype-v14.png new file mode 100644 index 00000000000..5fe77bae083 Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype-v14.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype.png new file mode 100644 index 00000000000..3ed6b97bb94 Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/choosetype.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues-v14.png b/14/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/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues-v14.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues.png new file mode 100644 index 00000000000..4e0dd7513ce Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/datatype-prevalues.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/docs-from-xpath.png b/14/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/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/docs-from-xpath.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/fieldpreview.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/fieldpreview.png new file mode 100644 index 00000000000..ba1e9aeac2f Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/fieldpreview.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options-v14.png b/14/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/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options-v14.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options.png b/14/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/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevalue-cache-options.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree-v14.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree-v14.png new file mode 100644 index 00000000000..23ae81e8c86 Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree-v14.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree.png new file mode 100644 index 00000000000..bb90fa4e7d3 Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/prevaluesourcetree.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview-v14.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview-v14.png new file mode 100644 index 00000000000..94d165ae93b Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview-v14.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview.png new file mode 100644 index 00000000000..3fca5d00d48 Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/preview.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings-v14.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings-v14.png new file mode 100644 index 00000000000..aa1c171d39c Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings-v14.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings.png new file mode 100644 index 00000000000..8281c10fab2 Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/typesettings.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v14.png b/14/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/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v14.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v16.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v16.png new file mode 100644 index 00000000000..98135a6a5a9 Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v16.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v9.png b/14/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/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents-v9.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents.png b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents.png new file mode 100644 index 00000000000..ec43727e01e Binary files /dev/null and b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/images/umbraco-documents.png differ diff --git a/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/prevalue-source-types.md b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/prevalue-source-types.md new file mode 100644 index 00000000000..1573b5361c7 --- /dev/null +++ b/14/umbraco-forms/editor/defining-and-attaching-prevaluesources/prevalue-source-types.md @@ -0,0 +1,50 @@ +# 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 you to use content nodes from a specific source as prevalues. Configure the following options in the **Details** section: + +* Define the root node by either: + * Selecting the type of item the picker should target such as **Content**, **Media**, or **Members**, or + * Specifying a dynamic root. +* Enable **Use current page as root** instead of choosing a specific root node. _Preview is not available when this setting is enabled._ +* Choose a specific **Document type**, if the selected root node contains a different Document Type. +* Select the **Value field** to define the value stored for the prevalue. +* Select the **Caption field** to define the label shown in the list. +* Enable **List all Descendants** of the selected root node to include all child nodes beneath the root. +* Select **Order by** from the drop-down list to display how the prevalue list is sorted. +* Select your preferred **Cache option** for caching the list of prevalues when rendering in a form. + +![Umbraco Documents](images/umbraco-documents-v16.png) + +## SQL Database + +Connect to a OleDB compatible database table and construct a prevalue source from it. Once selected, it will be editable from the Forms interface. + +Configure the following options 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-v16.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/14/umbraco-forms/editor/images/BulkActions.png b/14/umbraco-forms/editor/images/BulkActions.png new file mode 100644 index 00000000000..dfb879546e9 Binary files /dev/null and b/14/umbraco-forms/editor/images/BulkActions.png differ diff --git a/14/umbraco-forms/editor/images/EntriesViewer.png b/14/umbraco-forms/editor/images/EntriesViewer.png new file mode 100644 index 00000000000..fe077a4161f Binary files /dev/null and b/14/umbraco-forms/editor/images/EntriesViewer.png differ diff --git a/14/umbraco-forms/editor/images/Export-v14.png b/14/umbraco-forms/editor/images/Export-v14.png new file mode 100644 index 00000000000..efc9bb7686b Binary files /dev/null and b/14/umbraco-forms/editor/images/Export-v14.png differ diff --git a/14/umbraco-forms/editor/images/Export.png b/14/umbraco-forms/editor/images/Export.png new file mode 100644 index 00000000000..9ba199defea Binary files /dev/null and b/14/umbraco-forms/editor/images/Export.png differ diff --git a/14/umbraco-forms/editor/images/ExportAllDialog-v14.png b/14/umbraco-forms/editor/images/ExportAllDialog-v14.png new file mode 100644 index 00000000000..2d7dd5a549f Binary files /dev/null and b/14/umbraco-forms/editor/images/ExportAllDialog-v14.png differ diff --git a/14/umbraco-forms/editor/images/ExportAllDialog.png b/14/umbraco-forms/editor/images/ExportAllDialog.png new file mode 100644 index 00000000000..09bf4519314 Binary files /dev/null and b/14/umbraco-forms/editor/images/ExportAllDialog.png differ diff --git a/14/umbraco-forms/editor/images/Filter.png b/14/umbraco-forms/editor/images/Filter.png new file mode 100644 index 00000000000..36dbbd65dd6 Binary files /dev/null and b/14/umbraco-forms/editor/images/Filter.png differ diff --git a/14/umbraco-forms/editor/images/entry-details-v14.png b/14/umbraco-forms/editor/images/entry-details-v14.png new file mode 100644 index 00000000000..77e47c96500 Binary files /dev/null and b/14/umbraco-forms/editor/images/entry-details-v14.png differ diff --git a/14/umbraco-forms/editor/images/tree-v14.png b/14/umbraco-forms/editor/images/tree-v14.png new file mode 100644 index 00000000000..c472e109511 Binary files /dev/null and b/14/umbraco-forms/editor/images/tree-v14.png differ diff --git a/14/umbraco-forms/editor/images/tree.png b/14/umbraco-forms/editor/images/tree.png new file mode 100644 index 00000000000..37918780188 Binary files /dev/null and b/14/umbraco-forms/editor/images/tree.png differ diff --git a/14/umbraco-forms/editor/viewing-and-exporting-entries.md b/14/umbraco-forms/editor/viewing-and-exporting-entries.md new file mode 100644 index 00000000000..8d873f1548e --- /dev/null +++ b/14/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/14/umbraco-forms/installation/images/Forms_Section_Backoffice.png b/14/umbraco-forms/installation/images/Forms_Section_Backoffice.png new file mode 100644 index 00000000000..9ed7bf7f936 Binary files /dev/null and b/14/umbraco-forms/installation/images/Forms_Section_Backoffice.png differ diff --git a/14/umbraco-forms/installation/images/InstallingForms.gif b/14/umbraco-forms/installation/images/InstallingForms.gif new file mode 100644 index 00000000000..59643bd9c02 Binary files /dev/null and b/14/umbraco-forms/installation/images/InstallingForms.gif differ diff --git a/14/umbraco-forms/installation/images/Manage_packages.png b/14/umbraco-forms/installation/images/Manage_packages.png new file mode 100644 index 00000000000..53774af554b Binary files /dev/null and b/14/umbraco-forms/installation/images/Manage_packages.png differ diff --git a/14/umbraco-forms/installation/images/Manage_packages_v10.png b/14/umbraco-forms/installation/images/Manage_packages_v10.png new file mode 100644 index 00000000000..c47a0ecf652 Binary files /dev/null and b/14/umbraco-forms/installation/images/Manage_packages_v10.png differ diff --git a/14/umbraco-forms/installation/images/Manage_packages_v14.png b/14/umbraco-forms/installation/images/Manage_packages_v14.png new file mode 100644 index 00000000000..dd8f92cf16a Binary files /dev/null and b/14/umbraco-forms/installation/images/Manage_packages_v14.png differ diff --git a/14/umbraco-forms/installation/images/UpgradeAvailable.png b/14/umbraco-forms/installation/images/UpgradeAvailable.png new file mode 100644 index 00000000000..6a24cc30737 Binary files /dev/null and b/14/umbraco-forms/installation/images/UpgradeAvailable.png differ diff --git a/14/umbraco-forms/installation/images/UpgradeNow.png b/14/umbraco-forms/installation/images/UpgradeNow.png new file mode 100644 index 00000000000..92a5d752e00 Binary files /dev/null and b/14/umbraco-forms/installation/images/UpgradeNow.png differ diff --git a/14/umbraco-forms/installation/images/UpgradeProgress.png b/14/umbraco-forms/installation/images/UpgradeProgress.png new file mode 100644 index 00000000000..3d092da8972 Binary files /dev/null and b/14/umbraco-forms/installation/images/UpgradeProgress.png differ diff --git a/14/umbraco-forms/installation/images/buy-license.png b/14/umbraco-forms/installation/images/buy-license.png new file mode 100644 index 00000000000..29655a7bf20 Binary files /dev/null and b/14/umbraco-forms/installation/images/buy-license.png differ diff --git a/14/umbraco-forms/installation/images/image.png b/14/umbraco-forms/installation/images/image.png new file mode 100644 index 00000000000..002dbcbe5c8 Binary files /dev/null and b/14/umbraco-forms/installation/images/image.png differ diff --git a/14/umbraco-forms/installation/images/start-with-forms-v14.png b/14/umbraco-forms/installation/images/start-with-forms-v14.png new file mode 100644 index 00000000000..a17420f6d3d Binary files /dev/null and b/14/umbraco-forms/installation/images/start-with-forms-v14.png differ diff --git a/14/umbraco-forms/installation/images/start-with-forms-v9.png b/14/umbraco-forms/installation/images/start-with-forms-v9.png new file mode 100644 index 00000000000..e8ff764e518 Binary files /dev/null and b/14/umbraco-forms/installation/images/start-with-forms-v9.png differ diff --git a/14/umbraco-forms/installation/images/start-with-forms.png b/14/umbraco-forms/installation/images/start-with-forms.png new file mode 100644 index 00000000000..eafcd021e58 Binary files /dev/null and b/14/umbraco-forms/installation/images/start-with-forms.png differ diff --git a/14/umbraco-forms/installation/install.md b/14/umbraco-forms/installation/install.md new file mode 100644 index 00000000000..3b65659a255 --- /dev/null +++ b/14/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/14/umbraco-forms/installation/the-licensing-model.md b/14/umbraco-forms/installation/the-licensing-model.md new file mode 100644 index 00000000000..5284bc59a67 --- /dev/null +++ b/14/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/14/umbraco-forms/legacy-documentation.md b/14/umbraco-forms/legacy-documentation.md new file mode 100644 index 00000000000..50cadab40d4 --- /dev/null +++ b/14/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/14/umbraco-forms/release-notes.md b/14/umbraco-forms/release-notes.md new file mode 100644 index 00000000000..82994e1ad3e --- /dev/null +++ b/14/umbraco-forms/release-notes.md @@ -0,0 +1,202 @@ +--- +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.md) article. +{% endhint %} + +## Release history + +This section contains the release notes for Umbraco Forms 14 including all changes for this version. + +### [14.2.3](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.3) (December 5th 2024) + +* Fixed regression introduced in 14.2.1 that caused issues for custom field types overriding the `ProcessSubmittedValue` method [#1328](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1328). + +### [14.2.2](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.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. + +### [14.2.1](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.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). + +### [14.2.0](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.0) (November 7th 2024) + +* All items detailed under release candidates for 14.2.0. +* Fixed issue with validation for invalid file extension on form submissions via the API [#1310](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1310). + +### [14.2.0-rc2](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.0) **November 3rd 2024** + +* Updated dependency on Umbraco CMS to 14.3.0. +* Added a replacement for the AngularJS [block list label filter we provide for Forms 13](../../13/umbraco-forms/developer/blocklistfilters.md). The new implementations use [Umbraco Flavored Markdown (UFM)](https://docs.umbraco.com/umbraco-cms/reference/umbraco-flavored-markdown) and are [documented here](./developer/blocklistfilters.md). + +### [14.2.0-rc1](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.2.0) **October 25th 2024** + +#### Multi-step forms + +The 14.2 release of Forms contains features that can improve the user experience of completing multi-page forms. + +We have added the option for [editors to choose to display paging details on the forms](./editor/creating-a-form/form-settings.md#multi-page-forms). This will allow those completing forms to get a better understanding of progress as well as see details of the pages still to be completed. [#281](https://github.com/umbraco/Umbraco.Forms.Issues/issues/281) [#648](https://github.com/umbraco/Umbraco.Forms.Issues/issues/648). + +These options are enabled and configured by editors in the Forms settings section on a per-form basis. We also provide a [configuration-based toggle for the feature as a whole](./developer/configuration/README.md#enablemultipageformsettings). In this way, editors can be given access to use the feature only once the styling or theme is prepared. + +#### Form picker enhancements + +Another improvement is found in the [form picker property editors](./developer/property-editors.md). We now support restriction of which forms can be selected by folder rather than only by individual forms. + +A second "form details picker" is also available, allowing editors the option of selecting the form, theme and redirect via a single property editor. + +#### Ship themes in Razor Class Libraries + +Forms ships it's themes and email templates as part of a razor class library for ease of distribution. With this release we make that feature [available to your own custom themes and templates](./developer/themes.md#shipping-themes-in-a-razor-class-library) (or those created by package developers) [#795](https://github.com/umbraco/Umbraco.Forms.Issues/issues/795). + +#### Date picker field type + +We have made a couple of updates to the Date Picker field type. The format for the field can now be provided in configuration [#1276](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1276). And you can now override and localize the aria label provided for assistive technologies such as screen readers [#1082](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1082). + +#### Umbraco documents prevalue source type + +When creating a prevalue source based on Umbraco documents, you can now select custom properties for the value or caption. Previously you had a choice of the content item's `Id`, `Key` or `Name`. We've extended this to allow the selection of any properties defined on the selected Document Type [#1195](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1195). + +#### Finer grained entries permissions + +To allow finer control over editor permissions, we have introduced a "delete entries" setting for users and user groups. Thus you can now give editors explicit permissions to view, edit, or delete entries [#1303](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1303). + +#### Backoffice localization + +Finally thanks to a kind contribution from [Erik-Jan Westendorp](https://github.com/erikjanwestendorp) the backoffice is now translated into Dutch [#1264](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1264). + +#### Other + +Other bug fixes included in the release: + +* Reverted entry list to display most recent first. +* Fixed issue with display of prevalue captions in the entry list. +* Fixed issue on restoring values of checkbox and radio lists when navigating backward on multi-page forms. +* 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). +* Improved cross-platform check when exporting to Excel. + +### [14.1.5](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.5) (October 3rd 2024) + +* Handled "chunked" authentication cookie in protection of file uploads saved in the media file system [#11](https://github.com/umbraco/Umbraco.Forms.Issues/issues/11#issuecomment-2376788751). +* Ensured field list for condition rules updates as new fields are added to the form [#1301](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1301). +* Resolved issues with requesting management API endpoints for forms from content without access to the Forms section [#1244](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1244). +* Fixed button labels on form copy dialog. +* Fixed localization of SQL prevalue source labels. + +### [14.1.4](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F13.2.4) (September 26th 2024) + +* Fixed regression in 14.1.2 that caused validation to fire on the wrong form when multiple forms are hosted on a single page [#1297](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1297). +* Fixed issue with line breaks in form submissions breaking the entries view [#1296](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1296). + +### [14.1.3](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.3) (September 19th 2024) + +* Fixed regression in 13.2.0 that prevented a form submission from saving if a workflow approved the entry [#1293](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1293). +* Added file name validation to file uploads, rejecting files with invalid colon characters [#1295](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1295). + +### [14.1.2](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.2) (September 12th 2024) + +* Added configurable field level rendering of reCAPTCHA 3 validation result [#1277](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1277). +* Fixed validate and submit script to handle additional markup around submit buttons [#1280](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1280). +* Fixed incorrect concatenation of field CSS classes [#1284](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1284). +* Added server-side validation of configured maximum length for short and long answer fields. +* Restored provision of field values in HTTP headers in Post as XML workflow. +* Fixed issue with recording of form submissions in custom Examine indexes [#1282](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1282). +* Added ability to retrieve "slim" workflow entities from services [#1283](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1283). +* Fixed the following backoffice user interface issues [#1291](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1291), [#1290](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1290), [#1288](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1288), [#1287](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1287), [#1286](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1286), [#1278](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1278) and [#1275](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1275). + +### [14.1.1](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.1) (August 6th 2024) + +* Fixed issues with entries export for Windows installations without access to a component necessary for auto-fit of Excel columns [#1259](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1259). +* Resolved intermittent issues with display of entries list [#1256](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1256). +* Restored access to setting option for sensitive data handling in workflows [#1262](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1262). +* Fixed validation on saving a form without a name [#1263](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1263). +* Fixed fallback of the localized user interface for English (GB) to English (US) [#1267](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1267). +* Fixed issue with form block rendering from rich text content [#1268](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1268). +* Restored the `ValueAsString` extension method on `Record`. + +### [14.1.0](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.0) (July 23rd 2024) + +{% hint style="warning" %} +The 14.1.0 release contains minor changes to the mark-up in the following Razor files shipped with the product: `Form.cshtml`, `FieldType.RadioButtonList.cshtml`, and `FieldType.CheckBoxList.cshtml`. These changes were made to resolve issues [#1220](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1220) and [#1218](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1218). + +Please ensure to check the rendering of these features on website forms after the upgrade. If you need to view the files to compare changes, you can download and view the [latest](https://our.umbraco.com/FileDownload?id=24343) and [previous](https://our.umbraco.com/FileDownload?id=24339) versions. +{% endhint %} + +* All issues from earlier 14.1 release candidates. +* Ensured prevalues can be retrieved outside of an HTTP request context when they depend on a static root node [#1258](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1258). + +### [14.1.0-rc2](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.0) (July 18th 2024) + +* Added configuration option `AllowedFileUploadExtensions` to provide an "allow list" of extensions that will be accepted in file uploads via forms [#1252](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1252). + * Read more about this and related settings [here](developer/configuration/#allowedfileuploadextensions). +* Allowed users without sensitive data permissions to set, but not remove, the sensitive flag on a form field [#1233](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1233). +* Ordered select list of prevalue sources when defining prevalues for a form field. +* Limited the field preview for a field containing prevalues. +* Improved support for editing large, multi-page forms by retaining scroll position between views and adding a "jump to page" option [#1243](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1243). + +### [14.1.0-rc1](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.1.0) (July 9th 2024) + +* Added setting option for single and multiple choice fields to allow for vertical or horizontal display [#1218](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1218) +* Updated themes such that accessibility is improved by having hidden labels remain in markup but be visually hidden [#1220](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1220). +* Added new setting type for multiple text strings [#1217](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1217) +* Added validation to prevent users defining an email workflow that allows the form's sender email to be defined as that entered by the user [#1210](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1210) +* Allowed for the provision of additional data when rendering and submitting forms. 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 and update within workflows. [#578](https://github.com/umbraco/Umbraco.Forms.Issues/issues/578) +* Added details of workflow type to edit workflow dialog [#1183](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1183) +* Allowed for use of prevalue sources that customize based on the current form or field in backoffice editing and preview [#1221](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1221) +* Ensured links to Umbraco pages within rich text fields used for emails are correctly parsed [#1208](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1208). +* Added body rich text field for send email with Razor template workflow [#1198](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1198). +* Fixed console error with blank values in the date picker field [#1241](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1241). +* Ensured placeholders are parsed for accepted entry response from the delivery API [#1238](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1238). +* Resolved issues with intermittent failures of the form entries table display [#1239](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1239). + +### [14.0.2](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.0.2) (June 11th 2024) + +* Fixed issue with upload of text file for the prevalue source based on file contents. + +### [14.0.1](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.0.1) (June 6th 2024) + +* Ensured local links are parsed when HTML fields are returned in the delivery API results for form definitions [#1227](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1227). +* Restored target used to generate local configuration schema information [#1226](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1226). +* Resolved duplicate approval occurring when the record is approved via a workflow [#1223](https://github.com/umbraco/Umbraco.Forms.Issues/issues/1223). +* Added some missing localization keys and translations. +* Fixed description of management API on Swagger UI. +* Fixed display of specific form access list for user and group security. + +### [14.0.0](https://github.com/umbraco/Umbraco.Forms.Issues/issues?q=is%3Aissue+is%3Aclosed+label%3Arelease%2F14.0.0) (May 30th 2024) + +* Compatibility with Umbraco 14 + * See full details of breaking changes under the [Version-specific Upgrade Guide](upgrading/version-specific.md). + +## Umbraco.Forms.Deploy + +### 14.1.1 (October 3rd 2024) + +* Add migrator to add missing Forms editor UI aliases + +### 14.1.0 (August 16th 2024) + +* Add check for keyed services before examining the registered services implementation type (workaround for https://github.com/dotnet/runtime/issues/95789) +* Request tree items for forms-folder entity + +### 14.0.0 (May 30th 2024) + +* Compatibility with Umbraco 14, Forms 14 and Deploy 14. + +## 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-forms/release-notes.md) and [Umbraco Forms Package page](https://our.umbraco.com/packages/developer-tools/umbraco-forms/). diff --git a/14/umbraco-forms/tutorials/creating-a-contact-form.md b/14/umbraco-forms/tutorials/creating-a-contact-form.md new file mode 100644 index 00000000000..d3a5a386a59 --- /dev/null +++ b/14/umbraco-forms/tutorials/creating-a-contact-form.md @@ -0,0 +1,300 @@ +# 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/README.md#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](https://docs.umbraco.com/umbraco-forms/developer/prepping-frontend) 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/14/umbraco-forms/tutorials/creating-a-multipage-form.md b/14/umbraco-forms/tutorials/creating-a-multipage-form.md new file mode 100644 index 00000000000..4bd749367e8 --- /dev/null +++ b/14/umbraco-forms/tutorials/creating-a-multipage-form.md @@ -0,0 +1,187 @@ +# 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](https://docs.umbraco.com/umbraco-forms/developer/prepping-frontend) 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/14/umbraco-forms/tutorials/images/Final-page.png b/14/umbraco-forms/tutorials/images/Final-page.png new file mode 100644 index 00000000000..d418c911578 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/Final-page.png differ diff --git a/14/umbraco-forms/tutorials/images/Form-Content-section.png b/14/umbraco-forms/tutorials/images/Form-Content-section.png new file mode 100644 index 00000000000..5b60689923d Binary files /dev/null and b/14/umbraco-forms/tutorials/images/Form-Content-section.png differ diff --git a/14/umbraco-forms/tutorials/images/company-information.png b/14/umbraco-forms/tutorials/images/company-information.png new file mode 100644 index 00000000000..8208c9af31e Binary files /dev/null and b/14/umbraco-forms/tutorials/images/company-information.png differ diff --git a/14/umbraco-forms/tutorials/images/composition-properties-v14.png b/14/umbraco-forms/tutorials/images/composition-properties-v14.png new file mode 100644 index 00000000000..19ee86be699 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/composition-properties-v14.png differ diff --git a/14/umbraco-forms/tutorials/images/composition-properties.png b/14/umbraco-forms/tutorials/images/composition-properties.png new file mode 100644 index 00000000000..3bf730fba7e Binary files /dev/null and b/14/umbraco-forms/tutorials/images/composition-properties.png differ diff --git a/14/umbraco-forms/tutorials/images/conditional-question-part-1.png b/14/umbraco-forms/tutorials/images/conditional-question-part-1.png new file mode 100644 index 00000000000..ca2b9b83d18 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/conditional-question-part-1.png differ diff --git a/14/umbraco-forms/tutorials/images/conditional-question-part-2.png b/14/umbraco-forms/tutorials/images/conditional-question-part-2.png new file mode 100644 index 00000000000..eabde810d2d Binary files /dev/null and b/14/umbraco-forms/tutorials/images/conditional-question-part-2.png differ diff --git a/14/umbraco-forms/tutorials/images/contact-us-doc-type-properties-v14.png b/14/umbraco-forms/tutorials/images/contact-us-doc-type-properties-v14.png new file mode 100644 index 00000000000..307f0aca971 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/contact-us-doc-type-properties-v14.png differ diff --git a/14/umbraco-forms/tutorials/images/contact-us-doc-type-properties.png b/14/umbraco-forms/tutorials/images/contact-us-doc-type-properties.png new file mode 100644 index 00000000000..efe005b1c57 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/contact-us-doc-type-properties.png differ diff --git a/14/umbraco-forms/tutorials/images/contact-us-form-add-questions-v14.png b/14/umbraco-forms/tutorials/images/contact-us-form-add-questions-v14.png new file mode 100644 index 00000000000..e0d4cf1bd10 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/contact-us-form-add-questions-v14.png differ diff --git a/14/umbraco-forms/tutorials/images/contact-us-form-add-questions.png b/14/umbraco-forms/tutorials/images/contact-us-form-add-questions.png new file mode 100644 index 00000000000..a100b2d4426 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/contact-us-form-add-questions.png differ diff --git a/14/umbraco-forms/tutorials/images/create-form.png b/14/umbraco-forms/tutorials/images/create-form.png new file mode 100644 index 00000000000..b735f9d1e9f Binary files /dev/null and b/14/umbraco-forms/tutorials/images/create-form.png differ diff --git a/14/umbraco-forms/tutorials/images/creating-a-composition.png b/14/umbraco-forms/tutorials/images/creating-a-composition.png new file mode 100644 index 00000000000..c616f49f0b9 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/creating-a-composition.png differ diff --git a/14/umbraco-forms/tutorials/images/fill-contact-us-node-v14.png b/14/umbraco-forms/tutorials/images/fill-contact-us-node-v14.png new file mode 100644 index 00000000000..fc5a30263f1 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/fill-contact-us-node-v14.png differ diff --git a/14/umbraco-forms/tutorials/images/fill-contact-us-node.png b/14/umbraco-forms/tutorials/images/fill-contact-us-node.png new file mode 100644 index 00000000000..5473a8c2589 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/fill-contact-us-node.png differ diff --git a/14/umbraco-forms/tutorials/images/first-page-of-form.png b/14/umbraco-forms/tutorials/images/first-page-of-form.png new file mode 100644 index 00000000000..5e0c6c742bd Binary files /dev/null and b/14/umbraco-forms/tutorials/images/first-page-of-form.png differ diff --git a/14/umbraco-forms/tutorials/images/form-data-entry.png b/14/umbraco-forms/tutorials/images/form-data-entry.png new file mode 100644 index 00000000000..0d66f6f1847 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/form-data-entry.png differ diff --git a/14/umbraco-forms/tutorials/images/multiple-choice.png b/14/umbraco-forms/tutorials/images/multiple-choice.png new file mode 100644 index 00000000000..d4abe0b3ed1 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/multiple-choice.png differ diff --git a/14/umbraco-forms/tutorials/images/page-2-details.png b/14/umbraco-forms/tutorials/images/page-2-details.png new file mode 100644 index 00000000000..4285fc810be Binary files /dev/null and b/14/umbraco-forms/tutorials/images/page-2-details.png differ diff --git a/14/umbraco-forms/tutorials/images/pick-document-type.png b/14/umbraco-forms/tutorials/images/pick-document-type.png new file mode 100644 index 00000000000..6d3f1b2f9be Binary files /dev/null and b/14/umbraco-forms/tutorials/images/pick-document-type.png differ diff --git a/14/umbraco-forms/tutorials/images/prevalue-fields.png b/14/umbraco-forms/tutorials/images/prevalue-fields.png new file mode 100644 index 00000000000..f713a9f6212 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/prevalue-fields.png differ diff --git a/14/umbraco-forms/tutorials/images/select-form-v14.png b/14/umbraco-forms/tutorials/images/select-form-v14.png new file mode 100644 index 00000000000..078eb3b06a9 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/select-form-v14.png differ diff --git a/14/umbraco-forms/tutorials/images/select-form.png b/14/umbraco-forms/tutorials/images/select-form.png new file mode 100644 index 00000000000..888e8f1e48e Binary files /dev/null and b/14/umbraco-forms/tutorials/images/select-form.png differ diff --git a/14/umbraco-forms/tutorials/images/update-doc-type-permissions-v14.png b/14/umbraco-forms/tutorials/images/update-doc-type-permissions-v14.png new file mode 100644 index 00000000000..548a86d93fe Binary files /dev/null and b/14/umbraco-forms/tutorials/images/update-doc-type-permissions-v14.png differ diff --git a/14/umbraco-forms/tutorials/images/update-doc-type-permissions.png b/14/umbraco-forms/tutorials/images/update-doc-type-permissions.png new file mode 100644 index 00000000000..a26f091fc53 Binary files /dev/null and b/14/umbraco-forms/tutorials/images/update-doc-type-permissions.png differ diff --git a/14/umbraco-forms/tutorials/overview.md b/14/umbraco-forms/tutorials/overview.md new file mode 100644 index 00000000000..22071b01561 --- /dev/null +++ b/14/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/14/umbraco-forms/upgrading/manualupgrade.md b/14/umbraco-forms/upgrading/manualupgrade.md new file mode 100644 index 00000000000..dfd3d5c1362 --- /dev/null +++ b/14/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/14/umbraco-forms/upgrading/migration-ids.md b/14/umbraco-forms/upgrading/migration-ids.md new file mode 100644 index 00000000000..49ac005fa33 --- /dev/null +++ b/14/umbraco-forms/upgrading/migration-ids.md @@ -0,0 +1,25 @@ +# 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 | Same as 13.2.0 to allow upgrading 13.2 to 14.1. | +| db5ef50d-51d0-4f93-aae9-bd3df53a3bb1 | 14.2.0 | Same as 13.3.0 to allow upgrading 13.3 to 14.2. | + +You can't upgrade to version 14 from 13.4.0 or later, because active development moved to version 15 at that time. Please upgrade directly to version 15 or later instead. diff --git a/14/umbraco-forms/upgrading/version-specific.md b/14/umbraco-forms/upgrading/version-specific.md new file mode 100644 index 00000000000..a8397b5394a --- /dev/null +++ b/14/umbraco-forms/upgrading/version-specific.md @@ -0,0 +1,52 @@ +--- +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 14. + +{% 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 14 of Umbraco Forms has a minimum dependency on Umbraco CMS core of `14.0.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: + +#### **Behavior** + +* A new management API has been introduced at `umbraco/forms/management/api`. +* The root of the existing delivery API used for headless/AJAX solutions has moved to `umbraco/forms/delivery/api`. +* The HTML helper `RenderUmbracoFormDependencies` no longer renders the promises polyfill, which is not needed in modern browsers. +* Server-side registration of content apps has been removed as this is now a client-side concern. +* Creation of custom fields, workflow, and other provider types remains primarily a server-side task. However, they no longer require the provision of AngularJS views and controllers. Instead, these reference registered client-side manifests. For more information, see the [extending Umbraco Forms](../developer/extending/) article. +* With the removal of node selection by XPath support in Umbraco 14, the "Save as Umbraco node" workflow now uses [dynamic root](https://docs.umbraco.com/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/multinode-treepicker). + +#### **Configuration** + +* The setting `FieldSettings:TitleAndDescription:AllowUnsafeHtmlRendering` has a new default of `false`. +* The setting `PageOptions:TrackRenderedFormsStorageMethod` has a new default of `HttpContextItems`. + +#### **Dependencies** + +* Umbraco CMS dependency was updated to `14.0.0`. + +#### **Code** + +The following updates describe the more significant changes to the codebase and public API: + +* All controllers relating to backoffice trees and editors have been removed and their functionality replaced by the management API. +* The serialization library has been changed from `Newtonsoft.Json` to `System.Text.Json`. Among other updates this involved removing the public class `FormsJsonSerializerSettings` and replacing it with `FormsJsonSerializerOptions`. +* The obsolete methods `GetFieldsNotDisplayed` and `Build` on `FormViewModel` have been removed. +* The unused `RetryWorkflow` class has been 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).