diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a6303468cc..7ab6093623 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -22,7 +22,3 @@ RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/ # https://docs.npmjs.com/cli/v6/using-npm/config#unsafe-perm # Default: false if running as root, true otherwise (we are ROOT) #RUN npm -g config set user vscode && npm -g config set unsafe-perm - -# Generate and trust a local developer certificate for Kestrel -# This is needed for Kestrel to bind on https -RUN dotnet dev-certs https --trust diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4b1f593281..eef2999b8b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,6 +6,7 @@ "service": "app", "workspaceFolder": "/workspace", + // Set *default* container specific settings.json values on container create. "settings": { "omnisharp.defaultLaunchSolution": "umbraco.sln", @@ -13,13 +14,62 @@ "omnisharp.enableRoslynAnalyzers": true }, + "features": { + // Workaround until the image is updated to include the latest version of .NET Core - .NET7 + // https://github.com/devcontainers/templates/issues/38#issuecomment-1310803259 + "ghcr.io/devcontainers/features/dotnet:1": { + "version": "7" + }, + + // Adds SSH support to the container + // Allowing the Github CLI `gh codespace ssh` to work + "ghcr.io/devcontainers/features/sshd:1": { + "version": "latest" + }, + + // Adds SQLite feature from apt install + // Also adds the SQLite VSCode extension + "ghcr.io/warrenbuckley/codespace-features/sqlite:1": {} + }, + // Add the IDs of extensions you want installed when the container is created. "extensions": [ "ms-dotnettools.csharp" ], + + // This is used in the prebuilds - so dotnet build (nuget restore and node stuff) is done + "updateContentCommand": "dotnet build umbraco.sln && dotnet dev-certs https --trust", - // Use 'forwardPorts' to make a list of ports inside the container available locally. - "forwardPorts": [9000, 5000, 25] + // Use 'forwardPorts' to make a list of ports inside the container available locallAdd "forwardPorts": [9000, 5000, 25], + // Port needed to help discover SMTP4Dev + "forwardPorts": [ + 5000 + ], + + "portsAttributes": { + "5000": { + "label": "SMTP4Dev", + "protocol": "http", + "onAutoForward": "notify" + }, + "9000": { + "label": "Umbraco HTTP", + "protocol": "http", + "onAutoForward": "notify" + }, + "44331": { + "label": "Umbraco HTTPS", + "protocol": "https", + "onAutoForward": "notify" + } + }, + "customizations": { + "codespaces": { + "openFiles": [ + ".github/codespaces-readme.md" + ] + } + } // [Optional] To reuse of your local HTTPS dev cert: // diff --git a/.editorconfig b/.editorconfig index faf5c7766a..37eed4ec4f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -248,6 +248,7 @@ csharp_preserve_single_line_blocks = true ########################################## [*.{cs,csx,cake,vb,vbx}] +dotnet_diagnostic.CS1591.severity = suggestion ########################################## # Styles diff --git a/.github/BUILD.md b/.github/BUILD.md index 12b64b287f..fabe3caf67 100644 --- a/.github/BUILD.md +++ b/.github/BUILD.md @@ -1,4 +1,4 @@ -# Umbraco CMS Build +# Umbraco CMS Build ## Are you sure? @@ -99,111 +99,33 @@ When the page eventually loads in your web browser, you can follow the installer Did you read ["Are you sure"](#are-you-sure)? -### Quick! +Do note that this is only required if you want to test out your custom changes in a separate site (not the one in the Umbraco.Web.UI), if you just want to test your changes you can run the included test site using: `dotnet run` from `src/Umbraco.Web.UI/` -To build Umbraco, fire up PowerShell and move to Umbraco's repository root (the directory that contains `src`, `build`, `LICENSE.md`...). There, trigger the build with the following command: +You may want to build a set of NuGet packages with your changes, this can be done using the dotnet pack command. - build/build.ps1 +First enter the root of the project in a command line environment, and then use the following command to build the NuGet packages: -If you only see a build.bat-file, you're probably on the wrong branch. If you switch to the correct branch (v8/contrib) the file will appear and you can build it. +`dotnet pack -c Release -o Build.Out` -You might run into [Powershell quirks](#powershell-quirks). +This will restore and build the project using the release configuration, and put all the outputted files in a folder called `Build.Out` -If it runs without errors; Hooray! Now you can continue with [the next step](CONTRIBUTING.md#how-do-i-begin) and open the solution and build it. +You can then add these as a local NuGet feed using the following command: +`dotnet nuget add source -n MyLocalFeed` -### Build Infrastructure - -The Umbraco Build infrastructure relies on a PowerShell object. The object can be retrieved with: - - $ubuild = build/build.ps1 -get - -The object exposes various properties and methods that can be used to fine-grain build Umbraco. Some, but not all, of them are detailed below. - -#### Properties - -The object exposes the following properties: - -* `SolutionRoot`: the absolute path to the solution root -* `VisualStudio`: a Visual Studio object (see below) -* `NuGet`: the absolute path to the NuGet executable -* `Zip`: the absolute path to the 7Zip executable -* `VsWhere`: the absolute path to the VsWhere executable -* `NodePath`: the absolute path to the Node install -* `NpmPath`: the absolute path to the Npm install - -The Visual Studio object is `null` when Visual Studio has not been detected (eg on VSTS). When not null, the object exposes the following properties: - -* `Path`: Visual Studio installation path (eg some place under `Program Files`) -* `Major`: Visual Studio major version (eg `15` for VS 2017) -* `Minor`: Visual Studio minor version -* `MsBuild`: the absolute path to the MsBuild executable - -#### GetUmbracoVersion - -Gets an object representing the current Umbraco version. Example: - - $v = $ubuild.GetUmbracoVersion() - Write-Host $v.Semver - -The object exposes the following properties: - -* `Semver`: the semver object representing the version -* `Release`: the main part of the version (eg `7.6.33`) -* `Comment`: the pre release part of the version (eg `alpha02`) -* `Build`: the build number part of the version (eg `1234`) - -#### SetUmbracoVersion - -Modifies Umbraco files with the new version. - ->This entirely replaces the legacy `UmbracoVersion.txt` file. Do *not* edit version infos in files. - -The version must be a valid semver version. It can include a *pre release* part (eg `alpha02`) and/or a *build number* (eg `1234`). Examples: - - $ubuild.SetUmbracoVersion("7.6.33") - $ubuild.SetUmbracoVersion("7.6.33-alpha.2") - $ubuild.SetUmbracoVersion("7.6.33+1234") - $ubuild.SetUmbracoVersion("7.6.33-beta.5+5678") - -#### Build - -Builds Umbraco. Temporary files are generated in `build.tmp` while the actual artifacts (zip files, NuGet packages...) are produced in `build.out`. Example: - - $ubuild.Build() - -Some log files, such as MsBuild logs, are produced in `build.tmp` too. The `build` directory should remain clean during a build. - -**Note: web.config** - -Building Umbraco requires a clean `web.config` file in the `Umbraco.Web.UI` project. If a `web.config` file already exists, the `pre-build` task (see below) will save it as `web.config.temp-build` and replace it with a clean copy of `web.Template.config`. The original file is replaced once it is safe to do so, by the `pre-packages` task. - -#### Build-UmbracoDocs - -Builds umbraco documentation. Temporary files are generated in `build.tmp` while the actual artifacts (docs...) are produced in `build.out`. Example: - - Build-UmbracoDocs - -Some log files, such as MsBuild logs, are produced in `build.tmp` too. The `build` directory should remain clean during a build. - -#### Verify-NuGet - -Verifies that projects all require the same version of their dependencies, and that NuSpec files require versions that are consistent with projects. Example: - - Verify-NuGet +This will add a local nuget feed with the name "MyLocalFeed" and you'll now be able to use your custom built NuGet packages. ### Cleaning up Once the solution has been used to run a site, one may want to "reset" the solution in order to run a fresh new site again. -At the very minimum, you want +The easiest way to do this by deleting the following files and folders: +* src/Umbraco.Web.UI/appsettings.json +* src/Umbraco.Web.UI/umbraco/Data - git clean -Xdf src/Umbraco.Web.UI/App_Data - rm src/Umbraco.Web.UI/web.config +You only have to remove the connection strings from the appsettings, but removing the data folder ensures that the sqlite database gets deleted too. -Then, a simple 'Rebuild All' in Visual Studio will recreate a fresh `web.config` but should be quite fast (since it does not really need to rebuild anything). - -The `clean` Git command force (`-f`) removes (`-X`, note the capital X) all files and directories (`-d`) that are ignored by Git. +Next time you run a build the `appsettings.json` file will be re-created in its default state. This will leave media files and views around, but in most cases, it will be enough. @@ -219,65 +141,12 @@ For git documentation see: ## Azure DevOps -Umbraco uses Azure DevOps for continuous integration, nightly builds and release builds. The Umbraco CMS project on DevOps [is available for anonymous users](https://umbraco.visualstudio.com/Umbraco%20Cms). +Umbraco uses Azure DevOps for continuous integration, nightly builds and release builds. The Umbraco CMS project on DevOps [is available for anonymous users](https://umbraco.visualstudio.com/Umbraco%20Cms).. -DevOps uses the `Build-Umbraco` command several times, each time passing a different *target* parameter. The supported targets are: - -* `pre-build`: prepares the build -* `compile-belle`: compiles Belle -* `compile-umbraco`: compiles Umbraco -* `pre-tests`: prepares the tests -* `compile-tests`: compiles the tests -* `pre-packages`: prepares the packages -* `pkg-zip`: creates the zip files -* `pre-nuget`: prepares NuGet packages -* `pkg-nuget`: creates NuGet packages - -All these targets are executed when `Build-Umbraco` is invoked without a parameter (or with the `all` parameter). On VSTS, compilations (of Umbraco and tests) are performed by dedicated DevOps tasks. Similarly, creating the NuGet packages is also performed by dedicated DevOps tasks. - -Finally, the produced artifacts are published in two containers that can be downloaded from DevOps: `zips` contains the zip files while `nuget` contains the NuGet packages. - ->During a DevOps build, some environment `UMBRACO_*` variables are exported by the `pre-build` target and can be reused in other targets *and* in DevOps tasks. The `UMBRACO_TMP` environment variable is used in `Umbraco.Tests` to disable some tests that have issues with DevOps at the moment. +The produced artifacts are published in a container that can be downloaded from DevOps called "nupkg" which contains all the NuGet packages that got built. ## Quirks -### PowerShell Quirks - -There is a good chance that running `build.ps1` ends up in error, with messages such as - ->The file ...\build.ps1 is not digitally signed. You cannot run this script on the current system. For more information about running scripts and setting execution policy, see about_Execution_Policies. - -PowerShell has *Execution Policies* that may prevent the script from running. You can check the current policies with: - - PS> Get-ExecutionPolicy -List - - Scope ExecutionPolicy - ----- --------------- - MachinePolicy Undefined - UserPolicy Undefined - Process Undefined - CurrentUser Undefined - LocalMachine RemoteSigned - -Policies can be `Restricted`, `AllSigned`, `RemoteSigned`, `Unrestricted` and `Bypass`. Scopes can be `MachinePolicy`, `UserPolicy`, `Process`, `CurrentUser`, `LocalMachine`. You need the current policy to be `RemoteSigned`—as long as it is `Undefined`, the script cannot run. You can change the current user policy with: - - PS> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned - -Alternatively, you can do it at machine level, from within an elevated PowerShell session: - - PS> Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned - -And *then* the script should run. It *might* however still complain about executing scripts, with messages such as: - ->Security warning - Run only scripts that you trust. While scripts from the internet can be useful, this script can potentially harm your computer. If you trust this script, use the Unblock-File cmdlet to allow the script to run without this warning message. Do you want to run ...\build.ps1? -[D] Do not run [R] Run once [S] Suspend [?] Help (default is "D"): - -This is usually caused by the scripts being *blocked*. And that usually happens when the source code has been downloaded as a Zip file. When Windows downloads Zip files, they are marked as *blocked* (technically, they have a Zone.Identifier alternate data stream, with a value of "3" to indicate that they were downloaded from the Internet). And when such a Zip file is un-zipped, each and every single file is also marked as blocked. - -The best solution is to unblock the Zip file before un-zipping: right-click the files, open *Properties*, and there should be a *Unblock* checkbox at the bottom of the dialog. If, however, the Zip file has already been un-zipped, it is possible to recursively unblock all files from PowerShell with: - - PS> Get-ChildItem -Recurse *.* | Unblock-File - ### Git Quirks Git might have issues dealing with long file paths during build. You may want/need to enable `core.longpaths` support (see [this page](https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path) for details). diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 28618fb548..3ff37ac79c 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -103,7 +103,7 @@ Great question! The short version goes like this: 1. **Switch to the correct branch** - Switch to the `v10/contrib` branch + Switch to the `v11/contrib` branch 1. **Build** @@ -111,7 +111,7 @@ Great question! The short version goes like this: 1. **Branch** - Create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case issue number `12345`. Don't commit to `v10/contrib`, create a new branch first. + Create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case issue number `12345`. Don't commit to `v11/contrib`, create a new branch first. 1. **Change** @@ -121,7 +121,7 @@ Great question! The short version goes like this: Done? Yay! 🎉 - Remember to commit to your new `temp` branch, and don't commit to `v10/contrib`. Then you can push the changes up to your fork on GitHub. + Remember to commit to your new `temp` branch, and don't commit to `v11/contrib`. Then you can push the changes up to your fork on GitHub. #### Keeping your Umbraco fork in sync with the main repository [sync fork]: #keeping-your-umbraco-fork-in-sync-with-the-main-repository @@ -138,10 +138,10 @@ Then when you want to get the changes from the main repository: ``` git fetch upstream -git rebase upstream/v10/contrib +git rebase upstream/v11/contrib ``` -In this command we're syncing with the `v10/contrib` branch, but you can of course choose another one if needed. +In this command we're syncing with the `v11/contrib` branch, but you can of course choose another one if needed. [More information on how this works can be found on the thoughtbot blog.][sync fork ext] @@ -169,7 +169,7 @@ We recommend you to [sync with our repository][sync fork] before you submit your GitHub will have picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go. ![Create a pull request](img/createpullrequest.png) -We like to use [git flow][git flow] as much as possible, but don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to something, usually `v10/contrib`. If you are working on v9, this is the branch you should be targeting. +We like to use [git flow][git flow] as much as possible, but don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to something, usually `v11/contrib`. If you are working on v9, this is the branch you should be targeting. Please note: we are no longer accepting features for v8 and below but will continue to merge security fixes as and when they arise. diff --git a/.github/README.md b/.github/README.md index 5fa412cae4..7e7d51d712 100644 --- a/.github/README.md +++ b/.github/README.md @@ -1,4 +1,4 @@ -# [Umbraco CMS](https://umbraco.com) · [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](../LICENSE.md) [![Build status](https://umbraco.visualstudio.com/Umbraco%20Cms/_apis/build/status/Cms%208%20Continuous?branchName=v8/contrib)](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md) [![Twitter](https://img.shields.io/twitter/follow/umbraco.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=umbraco) [![Discord](https://img.shields.io/discord/869656431308189746)](https://discord.gg/umbraco) +# [Umbraco CMS](https://umbraco.com) · [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](../LICENSE.md) [![Build status](https://umbraco.visualstudio.com/Umbraco%20Cms/_apis/build/status/Cms%208%20Continuous?branchName=v8/contrib)](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md) [![Twitter](https://img.shields.io/twitter/follow/umbraco.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=umbraco) [![Discord](https://img.shields.io/discord/869656431308189746)](https://discord.gg/umbraco) [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=v11%2Fcontrib&repo=10601208&machine=basicLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=WestEurope) Umbraco is the friendliest, most flexible and fastest growing ASP.NET CMS, and used by more than 500,000 websites worldwide. Our mission is to help you deliver delightful digital experiences by making Umbraco friendly, simpler and social. @@ -25,13 +25,14 @@ If you want to DIY, then you can [download Umbraco]((https://our.umbraco.com/dow ## Documentation -The documentation for Umbraco CMS can be found [on Our Umbraco](https://our.umbraco.com/documentation/). The source for the Umbraco docs is [open source as well](https://github.com/umbraco/UmbracoDocs) and we're happy to look at your documentation contributions. +The documentation for Umbraco CMS can be found [on Our Umbraco](https://docs.umbraco.com/). The source for the Umbraco docs is [open source as well](https://github.com/umbraco/UmbracoDocs) and we're happy to look at your documentation contributions. ## Join the Umbraco community Our friendly community is available 24/7 at the community hub, we call ["Our Umbraco"](https://our.umbraco.com/). Our Umbraco features forums for questions and answers, documentation, downloadable plugins for Umbraco, and a rich collection of community resources. -Besides "Our", we all support each other also via Twitter: [Umbraco HQ](https://twitter.com/umbraco), [Release Updates](https://twitter.com/umbracoproject), [#umbraco](https://twitter.com/hashtag/umbraco) +Besides "Our", we all support each other in our [Community Discord Server](https://discord.gg/umbraco) and on Twitter: [Umbraco HQ](https://twitter.com/umbraco), [Release Updates](https://twitter.com/umbracoproject), [#umbraco](https://twitter.com/hashtag/umbraco) + ## Contributing diff --git a/.github/codespaces-readme.md b/.github/codespaces-readme.md new file mode 100644 index 0000000000..b71a6b5284 --- /dev/null +++ b/.github/codespaces-readme.md @@ -0,0 +1,21 @@ +# GitHub CodeSpaces +Umbraco source code can be edited inside the browser with VSCode and CodeSpaces. + +This development environment comes with all the tools you need to build Umbraco source code. + + +## Debugging and Running +From VSCode browse to the Run and Debug section and then click the green button. This will build the Umbraco source code and attach a debugger and launch the site. + +## Default Umbraco credentials +Username: test@umbraco.com +Password: password1234 + +## Test Email Server + A SMTP4Dev instance for testing email is available on port 5000. + +## SQLite Database +The SQLite extension is preinstalled and allows you to open, query, edit the data inside the Umbraco SQLite database for ease of use. + + + diff --git a/.gitignore b/.gitignore index 9f17b77d05..6a0c21d66f 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,5 @@ preserve.belle /tests/Umbraco.Tests.Integration/appsettings-schema.json /tests/Umbraco.Tests.Integration/appsettings-schema.*.json /src/Umbraco.Cms/appsettings-schema.json +playwright-report +trace.zip diff --git a/.vscode/launch.json b/.vscode/launch.json index 65a3d08583..f40f2a8270 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,7 +8,6 @@ "name": ".NET Core Launch (web)", "type": "coreclr", "request": "launch", - "preLaunchTask": "Dotnet build", "program": "dotnet", "args": ["run"], "cwd": "${workspaceFolder}/src/Umbraco.Web.UI", diff --git a/src/Umbraco.Cms.Api.Management/Umbraco.Cms.Api.Management.csproj b/src/Umbraco.Cms.Api.Management/Umbraco.Cms.Api.Management.csproj index a038f585a5..8ccc1e89b7 100644 --- a/src/Umbraco.Cms.Api.Management/Umbraco.Cms.Api.Management.csproj +++ b/src/Umbraco.Cms.Api.Management/Umbraco.Cms.Api.Management.csproj @@ -12,6 +12,9 @@ + + + diff --git a/src/Umbraco.Cms.Imaging.ImageSharp/Media/ImageSharpImageUrlGenerator.cs b/src/Umbraco.Cms.Imaging.ImageSharp/Media/ImageSharpImageUrlGenerator.cs index b7560853d7..ad76603187 100644 --- a/src/Umbraco.Cms.Imaging.ImageSharp/Media/ImageSharpImageUrlGenerator.cs +++ b/src/Umbraco.Cms.Imaging.ImageSharp/Media/ImageSharpImageUrlGenerator.cs @@ -46,6 +46,7 @@ public sealed class ImageSharpImageUrlGenerator : IImageUrlGenerator } var queryString = new Dictionary(); + Dictionary furtherOptions = QueryHelpers.ParseQuery(options.FurtherOptions); if (options.Crop is not null) { @@ -80,12 +81,17 @@ public sealed class ImageSharpImageUrlGenerator : IImageUrlGenerator queryString.Add(ResizeWebProcessor.Height, options.Height?.ToString(CultureInfo.InvariantCulture)); } + if (furtherOptions.Remove(FormatWebProcessor.Format, out StringValues format)) + { + queryString.Add(FormatWebProcessor.Format, format[0]); + } + if (options.Quality is not null) { queryString.Add(QualityWebProcessor.Quality, options.Quality?.ToString(CultureInfo.InvariantCulture)); } - foreach (KeyValuePair kvp in QueryHelpers.ParseQuery(options.FurtherOptions)) + foreach (KeyValuePair kvp in furtherOptions) { queryString.Add(kvp.Key, kvp.Value); } diff --git a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoInstall/Index.cshtml b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoInstall/Index.cshtml index be1b741535..68049c6c91 100644 --- a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoInstall/Index.cshtml +++ b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoInstall/Index.cshtml @@ -35,7 +35,7 @@

A server error occurred

This is most likely due to an error during application startup

- +
diff --git a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoWebsite/Maintenance.cshtml b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoWebsite/Maintenance.cshtml new file mode 100644 index 0000000000..46739cdef7 --- /dev/null +++ b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoWebsite/Maintenance.cshtml @@ -0,0 +1,69 @@ +@using Microsoft.Extensions.Options +@using Umbraco.Cms.Core.Configuration.Models +@using Umbraco.Cms.Core.Hosting +@using Umbraco.Cms.Core.Routing +@using Umbraco.Extensions +@inject IHostingEnvironment hostingEnvironment +@inject IOptions globalSettings +@{ + var backOfficePath = globalSettings.Value.GetBackOfficePath(hostingEnvironment); +} + + + + + + + + Website is Under Maintainance + + + + + + +
+
+
+

Website is Under Maintenance

+ +
+ +
+
+

This page can be replaced

+

+ Custom error handling might make your site look more on-brand and minimize the impact of errors on user experience - for example, a custom 404 with some helpful links (or a search function) could bring some value to the site. +

+ + Implementing custom error pages → +
+ +
+

Finish the maintenance

+

If you are an administrator, you finish the maintanance by going to backoffice.

+ + Handle the upgrade → +
+
+ +
+
+ +
+ + + diff --git a/src/Umbraco.Core/Actions/ActionAssignDomain.cs b/src/Umbraco.Core/Actions/ActionAssignDomain.cs index 3bd946837f..7ef7b9ca83 100644 --- a/src/Umbraco.Core/Actions/ActionAssignDomain.cs +++ b/src/Umbraco.Core/Actions/ActionAssignDomain.cs @@ -8,17 +8,17 @@ namespace Umbraco.Cms.Core.Actions; /// public class ActionAssignDomain : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'I'; - /// + /// + public const string ActionAlias = "assigndomain"; + + /// public char Letter => ActionLetter; - /// - // This is all lower-case because of case sensitive filesystems, see issue: https://github.com/umbraco/Umbraco-CMS/issues/11670 - public string Alias => "assigndomain"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.AdministrationCategory; diff --git a/src/Umbraco.Core/Actions/ActionBrowse.cs b/src/Umbraco.Core/Actions/ActionBrowse.cs index 2620888a30..ff217ac43a 100644 --- a/src/Umbraco.Core/Actions/ActionBrowse.cs +++ b/src/Umbraco.Core/Actions/ActionBrowse.cs @@ -16,14 +16,18 @@ namespace Umbraco.Cms.Core.Actions; /// public class ActionBrowse : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'F'; - /// + /// + public const string ActionAlias = "browse"; + + /// public char Letter => ActionLetter; + /// + public string Alias => ActionAlias; + /// public bool ShowInNotifier => false; @@ -33,8 +37,6 @@ public class ActionBrowse : IAction /// public string Icon => string.Empty; - /// - public string Alias => "browse"; /// public string Category => Constants.Conventions.PermissionCategories.ContentCategory; diff --git a/src/Umbraco.Core/Actions/ActionCopy.cs b/src/Umbraco.Core/Actions/ActionCopy.cs index f7d9d699a5..f4afb3906c 100644 --- a/src/Umbraco.Core/Actions/ActionCopy.cs +++ b/src/Umbraco.Core/Actions/ActionCopy.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; @@ -8,16 +8,17 @@ namespace Umbraco.Cms.Core.Actions; /// public class ActionCopy : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'O'; - /// + /// + public const string ActionAlias = "copy"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "copy"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.StructureCategory; diff --git a/src/Umbraco.Core/Actions/ActionCreateBlueprintFromContent.cs b/src/Umbraco.Core/Actions/ActionCreateBlueprintFromContent.cs index ee249d9ef8..f23e5cac84 100644 --- a/src/Umbraco.Core/Actions/ActionCreateBlueprintFromContent.cs +++ b/src/Umbraco.Core/Actions/ActionCreateBlueprintFromContent.cs @@ -8,8 +8,17 @@ namespace Umbraco.Cms.Core.Actions; /// public class ActionCreateBlueprintFromContent : IAction { - /// - public char Letter => 'ï'; + /// + public const char ActionLetter = 'ï'; + + /// + public const string ActionAlias = "createblueprint"; + + /// + public char Letter => ActionLetter; + + /// + public string Alias => ActionAlias; /// public bool ShowInNotifier => false; @@ -20,9 +29,6 @@ public class ActionCreateBlueprintFromContent : IAction /// public string Icon => Constants.Icons.Blueprint; - /// - public string Alias => "createblueprint"; - /// public string Category => Constants.Conventions.PermissionCategories.ContentCategory; } diff --git a/src/Umbraco.Core/Actions/ActionDelete.cs b/src/Umbraco.Core/Actions/ActionDelete.cs index 055b2a8f98..ea8517c794 100644 --- a/src/Umbraco.Core/Actions/ActionDelete.cs +++ b/src/Umbraco.Core/Actions/ActionDelete.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; @@ -8,16 +8,12 @@ namespace Umbraco.Cms.Core.Actions; /// public class ActionDelete : IAction { - /// - /// The unique action alias - /// - public const string ActionAlias = "delete"; - - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'D'; + /// + public const string ActionAlias = "delete"; + /// public char Letter => ActionLetter; diff --git a/src/Umbraco.Core/Actions/ActionMove.cs b/src/Umbraco.Core/Actions/ActionMove.cs index c1f6089793..a145e86fab 100644 --- a/src/Umbraco.Core/Actions/ActionMove.cs +++ b/src/Umbraco.Core/Actions/ActionMove.cs @@ -1,23 +1,24 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked upon creation of a document, media, member +/// This action is invoked upon creation of a document, media, member. /// public class ActionMove : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'M'; - /// + /// + public const string ActionAlias = "move"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "move"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.StructureCategory; diff --git a/src/Umbraco.Core/Actions/ActionNew.cs b/src/Umbraco.Core/Actions/ActionNew.cs index bd08a95ac5..25ac603532 100644 --- a/src/Umbraco.Core/Actions/ActionNew.cs +++ b/src/Umbraco.Core/Actions/ActionNew.cs @@ -1,27 +1,23 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked upon creation of a document +/// This action is invoked upon creation of a document. /// public class ActionNew : IAction { - /// - /// The unique action alias - /// - public const string ActionAlias = "create"; - - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'C'; - /// + /// + public const string ActionAlias = "create"; + + /// public char Letter => ActionLetter; - /// + /// public string Alias => ActionAlias; /// diff --git a/src/Umbraco.Core/Actions/ActionNotify.cs b/src/Umbraco.Core/Actions/ActionNotify.cs index 10845b01b9..8ad650a74a 100644 --- a/src/Umbraco.Core/Actions/ActionNotify.cs +++ b/src/Umbraco.Core/Actions/ActionNotify.cs @@ -1,15 +1,24 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked upon modifying the notification of a content +/// This action is invoked upon modifying the notification of a content. /// public class ActionNotify : IAction { - /// - public char Letter => 'N'; + /// + public const char ActionLetter = 'N'; + + /// + public const string ActionAlias = "notify"; + + /// + public char Letter => ActionLetter; + + /// + public string Alias => ActionAlias; /// public bool ShowInNotifier => false; @@ -20,9 +29,6 @@ public class ActionNotify : IAction /// public string Icon => "icon-megaphone"; - /// - public string Alias => "notify"; - /// public string Category => Constants.Conventions.PermissionCategories.ContentCategory; } diff --git a/src/Umbraco.Core/Actions/ActionProtect.cs b/src/Umbraco.Core/Actions/ActionProtect.cs index 7b54a0ec98..21c985961b 100644 --- a/src/Umbraco.Core/Actions/ActionProtect.cs +++ b/src/Umbraco.Core/Actions/ActionProtect.cs @@ -1,23 +1,24 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked when a document is protected or unprotected +/// This action is invoked when a document is protected or unprotected. /// public class ActionProtect : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'P'; - /// + /// + public const string ActionAlias = "protect"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "protect"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.AdministrationCategory; diff --git a/src/Umbraco.Core/Actions/ActionPublish.cs b/src/Umbraco.Core/Actions/ActionPublish.cs index e07b0935bc..09f6c831e9 100644 --- a/src/Umbraco.Core/Actions/ActionPublish.cs +++ b/src/Umbraco.Core/Actions/ActionPublish.cs @@ -4,20 +4,21 @@ namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked when a document is being published +/// This action is invoked when a document is being published. /// public class ActionPublish : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'U'; - /// + /// + public const string ActionAlias = "publish"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "publish"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.ContentCategory; diff --git a/src/Umbraco.Core/Actions/ActionRestore.cs b/src/Umbraco.Core/Actions/ActionRestore.cs index 395c678fe4..dcdfc86521 100644 --- a/src/Umbraco.Core/Actions/ActionRestore.cs +++ b/src/Umbraco.Core/Actions/ActionRestore.cs @@ -1,22 +1,23 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked when the content/media item is to be restored from the recycle bin +/// This action is invoked when the content/media item is to be restored from the recycle bin. /// public class ActionRestore : IAction { - /// - /// The unique action alias - /// + /// + public const char ActionLetter = 'V'; + + /// public const string ActionAlias = "restore"; - /// - public char Letter => 'V'; + /// + public char Letter => ActionLetter; - /// + /// public string Alias => ActionAlias; /// diff --git a/src/Umbraco.Core/Actions/ActionRights.cs b/src/Umbraco.Core/Actions/ActionRights.cs index 4cd8674122..7e493d6c16 100644 --- a/src/Umbraco.Core/Actions/ActionRights.cs +++ b/src/Umbraco.Core/Actions/ActionRights.cs @@ -1,23 +1,24 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked when rights are changed on a document +/// This action is invoked when rights are changed on a document. /// public class ActionRights : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'R'; - /// + /// + public const string ActionAlias = "rights"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "rights"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.ContentCategory; diff --git a/src/Umbraco.Core/Actions/ActionRollback.cs b/src/Umbraco.Core/Actions/ActionRollback.cs index 63021a2ae3..7e1dab6467 100644 --- a/src/Umbraco.Core/Actions/ActionRollback.cs +++ b/src/Umbraco.Core/Actions/ActionRollback.cs @@ -1,23 +1,24 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked when copying a document is being rolled back +/// This action is invoked when copying a document is being rolled back. /// public class ActionRollback : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'K'; - /// + /// + public const string ActionAlias = "rollback"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "rollback"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.AdministrationCategory; diff --git a/src/Umbraco.Core/Actions/ActionSort.cs b/src/Umbraco.Core/Actions/ActionSort.cs index 23e65d7533..4f90e404c8 100644 --- a/src/Umbraco.Core/Actions/ActionSort.cs +++ b/src/Umbraco.Core/Actions/ActionSort.cs @@ -1,23 +1,24 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked when children to a document, media, member is being sorted +/// This action is invoked when children to a document, media, member is being sorted. /// public class ActionSort : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'S'; - /// + /// + public const string ActionAlias = "sort"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "sort"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.StructureCategory; diff --git a/src/Umbraco.Core/Actions/ActionToPublish.cs b/src/Umbraco.Core/Actions/ActionToPublish.cs index 8df53b3e4a..e7af16bc99 100644 --- a/src/Umbraco.Core/Actions/ActionToPublish.cs +++ b/src/Umbraco.Core/Actions/ActionToPublish.cs @@ -1,23 +1,24 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked when children to a document is being sent to published (by an editor without publishrights) +/// This action is invoked when children to a document is being sent to published (by an editor without publishrights). /// public class ActionToPublish : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'H'; - /// + /// + public const string ActionAlias = "sendtopublish"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "sendtopublish"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.ContentCategory; diff --git a/src/Umbraco.Core/Actions/ActionUnpublish.cs b/src/Umbraco.Core/Actions/ActionUnpublish.cs index f8ebb918f9..f10159b403 100644 --- a/src/Umbraco.Core/Actions/ActionUnpublish.cs +++ b/src/Umbraco.Core/Actions/ActionUnpublish.cs @@ -1,23 +1,24 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked when a document is being unpublished +/// This action is invoked when a document is being unpublished. /// public class ActionUnpublish : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'Z'; - /// + /// + public const string ActionAlias = "unpublish"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "unpublish"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.ContentCategory; diff --git a/src/Umbraco.Core/Actions/ActionUpdate.cs b/src/Umbraco.Core/Actions/ActionUpdate.cs index 2d01ef176c..aa6b0e9950 100644 --- a/src/Umbraco.Core/Actions/ActionUpdate.cs +++ b/src/Umbraco.Core/Actions/ActionUpdate.cs @@ -1,23 +1,24 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. namespace Umbraco.Cms.Core.Actions; /// -/// This action is invoked when copying a document or media +/// This action is invoked when copying a document or media. /// public class ActionUpdate : IAction { - /// - /// The unique action letter - /// + /// public const char ActionLetter = 'A'; - /// + /// + public const string ActionAlias = "update"; + + /// public char Letter => ActionLetter; - /// - public string Alias => "update"; + /// + public string Alias => ActionAlias; /// public string Category => Constants.Conventions.PermissionCategories.ContentCategory; diff --git a/src/Umbraco.Core/Actions/IAction.cs b/src/Umbraco.Core/Actions/IAction.cs index f57e697a2e..6afe147e69 100644 --- a/src/Umbraco.Core/Actions/IAction.cs +++ b/src/Umbraco.Core/Actions/IAction.cs @@ -13,8 +13,14 @@ namespace Umbraco.Cms.Core.Actions; /// public interface IAction : IDiscoverable { + /// + const char ActionLetter = default; + + /// + const string ActionAlias = default; + /// - /// Gets the letter used to assign a permission (must be unique) + /// Gets the letter used to assign a permission (must be unique). /// char Letter { get; } @@ -34,7 +40,8 @@ public interface IAction : IDiscoverable string Icon { get; } /// - /// Gets the alias for this action (must be unique) + /// Gets the alias for this action (must be unique). + /// This is all lower-case because of case sensitive filesystems, see issue: https://github.com/umbraco/Umbraco-CMS/issues/11670. /// string Alias { get; } diff --git a/src/Umbraco.Core/Composing/BuilderCollectionBase.cs b/src/Umbraco.Core/Composing/BuilderCollectionBase.cs index ffacd89cff..722a6efca0 100644 --- a/src/Umbraco.Core/Composing/BuilderCollectionBase.cs +++ b/src/Umbraco.Core/Composing/BuilderCollectionBase.cs @@ -10,9 +10,8 @@ public abstract class BuilderCollectionBase : IBuilderCollection { private readonly LazyReadOnlyCollection _items; - /// Initializes a new instance of the - /// - /// with items. + /// + /// Initializes a new instance of the with items. /// /// The items. public BuilderCollectionBase(Func> items) => _items = new LazyReadOnlyCollection(items); diff --git a/src/Umbraco.Core/Configuration/LoggingSettingsExtensions.cs b/src/Umbraco.Core/Configuration/LoggingSettingsExtensions.cs new file mode 100644 index 0000000000..0489a9646d --- /dev/null +++ b/src/Umbraco.Core/Configuration/LoggingSettingsExtensions.cs @@ -0,0 +1,33 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using Microsoft.Extensions.Hosting; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Extensions; + +namespace Umbraco.Extensions; + +/// +/// Extension methods for . +/// +public static class LoggingSettingsExtensions +{ + /// + /// Gets the absolute logging path (maps a virtual path to the applications content root). + /// + /// The logging settings. + /// The host environment. + /// + /// The absolute logging path. + /// + public static string GetAbsoluteLoggingPath(this LoggingSettings loggingSettings, IHostEnvironment hostEnvironment) + { + var dir = loggingSettings.Directory; + if (dir.StartsWith("~/")) + { + return hostEnvironment.MapPathContentRoot(dir); + } + + return dir; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs b/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs index 19b2fb44fb..d3135cc373 100644 --- a/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs @@ -33,6 +33,7 @@ public class GlobalSettings internal const bool StaticSanitizeTinyMce = false; internal const int StaticMainDomReleaseSignalPollingInterval = 2000; private const bool StaticForceCombineUrlPathLeftToRight = true; + private const bool StaticShowMaintenancePageWhenInUpgradeState = true; /// /// Gets or sets a value for the reserved URLs (must end with a comma). @@ -252,4 +253,7 @@ public class GlobalSettings /// [DefaultValue(StaticForceCombineUrlPathLeftToRight)] public bool ForceCombineUrlPathLeftToRight { get; set; } = StaticForceCombineUrlPathLeftToRight; + + [DefaultValue(StaticShowMaintenancePageWhenInUpgradeState)] + public bool ShowMaintenancePageWhenInUpgradeState { get; set; } = StaticShowMaintenancePageWhenInUpgradeState; } diff --git a/src/Umbraco.Core/Configuration/Models/LoggingSettings.cs b/src/Umbraco.Core/Configuration/Models/LoggingSettings.cs index 90498991a4..0489d895b8 100644 --- a/src/Umbraco.Core/Configuration/Models/LoggingSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/LoggingSettings.cs @@ -2,13 +2,11 @@ // See LICENSE for more details. using System.ComponentModel; -using Microsoft.Extensions.Hosting; -using Umbraco.Cms.Core.Extensions; namespace Umbraco.Cms.Core.Configuration.Models; /// -/// Typed configuration options for logging settings. +/// Typed configuration options for logging settings. /// [UmbracoOptions(Constants.Configuration.ConfigLogging)] public class LoggingSettings @@ -17,25 +15,20 @@ public class LoggingSettings internal const string StaticDirectory = Constants.SystemDirectories.LogFiles; /// - /// Gets or sets a value for the maximum age of a log file. + /// Gets or sets a value for the maximum age of a log file. /// + /// + /// The maximum log age. + /// [DefaultValue(StaticMaxLogAge)] public TimeSpan MaxLogAge { get; set; } = TimeSpan.Parse(StaticMaxLogAge); /// - /// Gets or sets the folder to use for log files + /// Gets or sets the folder to use for log files. /// + /// + /// The directory. + /// [DefaultValue(StaticDirectory)] public string Directory { get; set; } = StaticDirectory; - - public string GetAbsoluteLoggingPath(IHostEnvironment hostEnvironment) - { - var dir = Directory; - if (dir.StartsWith("~/")) - { - return hostEnvironment.MapPathContentRoot(dir); - } - - return dir; - } } diff --git a/src/Umbraco.Core/Configuration/Models/SmtpSettings.cs b/src/Umbraco.Core/Configuration/Models/SmtpSettings.cs index 5a9ec1b94f..7d5c126542 100644 --- a/src/Umbraco.Core/Configuration/Models/SmtpSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/SmtpSettings.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.Configuration.Models; /// Matches MailKit.Security.SecureSocketOptions and defined locally to avoid having to take /// a dependency on this external library into Umbraco.Core. /// -/// +/// public enum SecureSocketOptions { /// diff --git a/src/Umbraco.Core/Constants-Telemetry.cs b/src/Umbraco.Core/Constants-Telemetry.cs index 0fc2cb1612..f8a382b0bb 100644 --- a/src/Umbraco.Core/Constants-Telemetry.cs +++ b/src/Umbraco.Core/Constants-Telemetry.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Cms.Core; +namespace Umbraco.Cms.Core; public static partial class Constants { @@ -28,5 +28,6 @@ public static partial class Constants public static string IsDebug = "IsDebug"; public static string DatabaseProvider = "DatabaseProvider"; public static string CurrentServerRole = "CurrentServerRole"; + public static string RuntimeMode = "RuntimeMode"; } } diff --git a/src/Umbraco.Core/Dashboards/AnalyticsDashboard.cs b/src/Umbraco.Core/Dashboards/AnalyticsDashboard.cs index 07688832f6..ca56204f5c 100644 --- a/src/Umbraco.Core/Dashboards/AnalyticsDashboard.cs +++ b/src/Umbraco.Core/Dashboards/AnalyticsDashboard.cs @@ -4,7 +4,7 @@ public class AnalyticsDashboard : IDashboard { public string Alias => "settingsAnalytics"; - public string[] Sections => new[] { "settings" }; + public string[] Sections => new[] { Constants.Applications.Settings }; public string View => "views/dashboard/settings/analytics.html"; diff --git a/src/Umbraco.Core/Dashboards/ContentDashboard.cs b/src/Umbraco.Core/Dashboards/ContentDashboard.cs index ff3a0031b3..fecb23aaba 100644 --- a/src/Umbraco.Core/Dashboards/ContentDashboard.cs +++ b/src/Umbraco.Core/Dashboards/ContentDashboard.cs @@ -7,7 +7,7 @@ public class ContentDashboard : IDashboard { public string Alias => "contentIntro"; - public string[] Sections => new[] { "content" }; + public string[] Sections => new[] { Constants.Applications.Content }; public string View => "views/dashboard/default/startupdashboardintro.html"; diff --git a/src/Umbraco.Core/Dashboards/ExamineDashboard.cs b/src/Umbraco.Core/Dashboards/ExamineDashboard.cs index ddd048c99e..c4a68982a9 100644 --- a/src/Umbraco.Core/Dashboards/ExamineDashboard.cs +++ b/src/Umbraco.Core/Dashboards/ExamineDashboard.cs @@ -7,7 +7,7 @@ public class ExamineDashboard : IDashboard { public string Alias => "settingsExamine"; - public string[] Sections => new[] { "settings" }; + public string[] Sections => new[] { Constants.Applications.Settings }; public string View => "views/dashboard/settings/examinemanagement.html"; diff --git a/src/Umbraco.Core/Dashboards/HealthCheckDashboard.cs b/src/Umbraco.Core/Dashboards/HealthCheckDashboard.cs index 85c2053450..2804372d7f 100644 --- a/src/Umbraco.Core/Dashboards/HealthCheckDashboard.cs +++ b/src/Umbraco.Core/Dashboards/HealthCheckDashboard.cs @@ -7,7 +7,7 @@ public class HealthCheckDashboard : IDashboard { public string Alias => "settingsHealthCheck"; - public string[] Sections => new[] { "settings" }; + public string[] Sections => new[] { Constants.Applications.Settings }; public string View => "views/dashboard/settings/healthcheck.html"; diff --git a/src/Umbraco.Core/Dashboards/MediaDashboard.cs b/src/Umbraco.Core/Dashboards/MediaDashboard.cs index 47e45c4270..122b886b50 100644 --- a/src/Umbraco.Core/Dashboards/MediaDashboard.cs +++ b/src/Umbraco.Core/Dashboards/MediaDashboard.cs @@ -7,7 +7,7 @@ public class MediaDashboard : IDashboard { public string Alias => "mediaFolderBrowser"; - public string[] Sections => new[] { "media" }; + public string[] Sections => new[] { Constants.Applications.Media }; public string View => "views/dashboard/media/mediafolderbrowser.html"; diff --git a/src/Umbraco.Core/Dashboards/MembersDashboard.cs b/src/Umbraco.Core/Dashboards/MembersDashboard.cs index f69d0a1ed0..0394fda4a0 100644 --- a/src/Umbraco.Core/Dashboards/MembersDashboard.cs +++ b/src/Umbraco.Core/Dashboards/MembersDashboard.cs @@ -7,7 +7,7 @@ public class MembersDashboard : IDashboard { public string Alias => "memberIntro"; - public string[] Sections => new[] { "member" }; + public string[] Sections => new[] { Constants.Applications.Members }; public string View => "views/dashboard/members/membersdashboardvideos.html"; diff --git a/src/Umbraco.Core/Dashboards/ModelsBuilderDashboard.cs b/src/Umbraco.Core/Dashboards/ModelsBuilderDashboard.cs index 640f6daf6e..30bcd202c2 100644 --- a/src/Umbraco.Core/Dashboards/ModelsBuilderDashboard.cs +++ b/src/Umbraco.Core/Dashboards/ModelsBuilderDashboard.cs @@ -7,7 +7,7 @@ public class ModelsBuilderDashboard : IDashboard { public string Alias => "settingsModelsBuilder"; - public string[] Sections => new[] { "settings" }; + public string[] Sections => new[] {Constants.Applications.Settings }; public string View => "views/dashboard/settings/modelsbuildermanagement.html"; diff --git a/src/Umbraco.Core/Dashboards/ProfilerDashboard.cs b/src/Umbraco.Core/Dashboards/ProfilerDashboard.cs index b84b1529c3..ef6edd51e7 100644 --- a/src/Umbraco.Core/Dashboards/ProfilerDashboard.cs +++ b/src/Umbraco.Core/Dashboards/ProfilerDashboard.cs @@ -7,7 +7,7 @@ public class ProfilerDashboard : IDashboard { public string Alias => "settingsProfiler"; - public string[] Sections => new[] { "settings" }; + public string[] Sections => new[] { Constants.Applications.Settings }; public string View => "views/dashboard/settings/profiler.html"; diff --git a/src/Umbraco.Core/Dashboards/PublishedStatusDashboard.cs b/src/Umbraco.Core/Dashboards/PublishedStatusDashboard.cs index 49709436ab..c852d79adb 100644 --- a/src/Umbraco.Core/Dashboards/PublishedStatusDashboard.cs +++ b/src/Umbraco.Core/Dashboards/PublishedStatusDashboard.cs @@ -7,7 +7,7 @@ public class PublishedStatusDashboard : IDashboard { public string Alias => "settingsPublishedStatus"; - public string[] Sections => new[] { "settings" }; + public string[] Sections => new[] { Constants.Applications.Settings }; public string View => "views/dashboard/settings/publishedstatus.html"; diff --git a/src/Umbraco.Core/Dashboards/RedirectUrlDashboard.cs b/src/Umbraco.Core/Dashboards/RedirectUrlDashboard.cs index 25b064154b..839494c5d9 100644 --- a/src/Umbraco.Core/Dashboards/RedirectUrlDashboard.cs +++ b/src/Umbraco.Core/Dashboards/RedirectUrlDashboard.cs @@ -7,7 +7,7 @@ public class RedirectUrlDashboard : IDashboard { public string Alias => "contentRedirectManager"; - public string[] Sections => new[] { "content" }; + public string[] Sections => new[] { Constants.Applications.Content }; public string View => "views/dashboard/content/redirecturls.html"; diff --git a/src/Umbraco.Core/Dashboards/SettingsDashboards.cs b/src/Umbraco.Core/Dashboards/SettingsDashboards.cs index b9cb572240..f46c52ba90 100644 --- a/src/Umbraco.Core/Dashboards/SettingsDashboards.cs +++ b/src/Umbraco.Core/Dashboards/SettingsDashboards.cs @@ -7,7 +7,7 @@ public class SettingsDashboard : IDashboard { public string Alias => "settingsWelcome"; - public string[] Sections => new[] { "settings" }; + public string[] Sections => new[] { Constants.Applications.Settings }; public string View => "views/dashboard/settings/settingsdashboardintro.html"; diff --git a/src/Umbraco.Core/DependencyInjection/LegacyStaticServiceProvider.cs b/src/Umbraco.Core/DependencyInjection/LegacyStaticServiceProvider.cs new file mode 100644 index 0000000000..5352996d01 --- /dev/null +++ b/src/Umbraco.Core/DependencyInjection/LegacyStaticServiceProvider.cs @@ -0,0 +1,31 @@ +using System; +using System.ComponentModel; + +namespace Umbraco.Cms.Web.Common.DependencyInjection; + +/// +/// Service locator for internal (umbraco cms) only purposes. Should only be used if no other ways exist. +/// +/// +/// It is created with only two goals in mind +/// 1) Continue to have the same extension methods on IPublishedContent and IPublishedElement as in V8. To make +/// migration easier. +/// 2) To have a tool to avoid breaking changes in minor and patch versions. All methods using this should in theory be +/// obsolete. +/// Keep in mind, every time this is used, the code becomes basically untestable. +/// +[Obsolete("Use Umbraco.Cms.Core.DependencyInjection.StaticServiceProvider directly instead - this is scheduled for removal in v13")] +[EditorBrowsable(EditorBrowsableState.Never)] +public static class StaticServiceProvider +{ + /// + /// The service locator. + /// + [Obsolete("Use Umbraco.Cms.Core.DependencyInjection.StaticServiceProvider directly instead- this is scheduled for removal in v13")] + [EditorBrowsable(EditorBrowsableState.Never)] + public static IServiceProvider Instance + { + get => Core.DependencyInjection.StaticServiceProvider.Instance; + set => Core.DependencyInjection.StaticServiceProvider.Instance = value; + } +} diff --git a/src/Umbraco.Core/DependencyInjection/StaticServiceProvider.cs b/src/Umbraco.Core/DependencyInjection/StaticServiceProvider.cs index 6f8e4a2173..5b0acbfe9b 100644 --- a/src/Umbraco.Core/DependencyInjection/StaticServiceProvider.cs +++ b/src/Umbraco.Core/DependencyInjection/StaticServiceProvider.cs @@ -1,6 +1,6 @@ using System.ComponentModel; -namespace Umbraco.Cms.Web.Common.DependencyInjection; +namespace Umbraco.Cms.Core.DependencyInjection; /// /// Service locator for internal (umbraco cms) only purposes. Should only be used if no other ways exist. @@ -20,6 +20,5 @@ public static class StaticServiceProvider /// The service locator. /// [EditorBrowsable(EditorBrowsableState.Never)] - public static IServiceProvider Instance { get; set; } = - null!; // This is set doing startup and will always exists after that + public static IServiceProvider Instance { get; set; } = null!; // This is set doing startup and will always exists after that } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs index fc78d985f7..86df88f240 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs @@ -1,5 +1,6 @@ using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.Dashboards; +using Umbraco.Cms.Core.Manifest; using Umbraco.Cms.Core.Media; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Routing; @@ -60,6 +61,18 @@ public static partial class UmbracoBuilderExtensions return builder; } + /// + /// Register a manifest filter + /// + /// The type of the manifest filter. + /// The Builder. + public static IUmbracoBuilder AddManifestFilter(this IUmbracoBuilder builder) + where T : class, IManifestFilter + { + builder.ManifestFilters().Append(); + return builder; + } + /// /// Register a media url provider. /// diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs index 280d7ce492..6f735a003c 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs @@ -204,12 +204,20 @@ public static partial class UmbracoBuilderExtensions => builder.WithCollectionBuilder(); /// + /// Gets the partial view snippets collection builder. + /// + /// The builder. public static PartialViewSnippetCollectionBuilder? PartialViewSnippets(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); + /// + /// Gets the partial view macro snippets collection builder. + /// + /// The builder. public static PartialViewMacroSnippetCollectionBuilder? PartialViewMacroSnippets(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); + /// /// Gets the cache refreshers collection builder. /// /// The builder. diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/cs.xml b/src/Umbraco.Core/EmbeddedResources/Lang/cs.xml index 0057d3d9a6..09c679475d 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/cs.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/cs.xml @@ -2,7 +2,7 @@ Umbraco komunita - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Kultura a názvy hostitelů @@ -254,7 +254,7 @@ Podřízené položky Cíl This translates to the following time on the server: - What does this mean?]]> + What does this mean?]]> Are you sure you want to delete this item? Are you sure you want to delete all items? Property %0% uses editor %1% which is not supported by Nested Content. @@ -1956,7 +1956,7 @@ Zkontrolovat skupinu Kontrola vyhodnocuje různé oblasti vašeho webu z hlediska nastavení osvědčených postupů, konfigurace, potenciálních problémů atd. Problémy lze snadno vyřešit stisknutím tlačítka. Můžete přidat své vlastní kontroly, podívejte se na dokumentaci pro více informací o vlastních kontrolách.

+

Kontrola vyhodnocuje různé oblasti vašeho webu z hlediska nastavení osvědčených postupů, konfigurace, potenciálních problémů atd. Problémy lze snadno vyřešit stisknutím tlačítka. Můžete přidat své vlastní kontroly, podívejte se na dokumentaci pro více informací o vlastních kontrolách.

]]>
@@ -2152,7 +2152,7 @@ Zjistit více v sekci Dokumentace v Our Umbraco + Další informace o práci s položkami naleznete v části Nastavení v sekci Dokumentace v Our Umbraco ]]> diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml b/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml index 012a1bc0b9..836d4705b3 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/cy.xml @@ -56,6 +56,8 @@ Datgloi Creu Templed Gynnwys Ail-anfon Gwahoddiad + Golygu cynnwys + Dewiswch ble i fewnforio Cynnwys @@ -83,6 +85,7 @@ Caniatáu hawl i gyfiethu nod Caniatáu hawl i achub nod Caniatáu hawl i greu Templed Cynnwys + Caniatáu mynediad i osod hysbysiadau ar gyfer nodau cynnwys Cynnwys @@ -196,6 +199,10 @@ Tefnu Arferu Hanes (pob amrywiad) + Mae glanhau wedi'i analluogi ar gyfer y fersiwn: %0% + Mae glanhau wedi'i alluogi ar gyfer fersiwn:: %0% + Achub + Achub Methwyd creu ffolder o dan id rhiant %0% @@ -273,7 +280,7 @@ Eitemau blentyn Targed Mae hyn yn trawsnewid at yr amser ganlynol ar y gweinydd: - Beth mae hyn yn golygu?]]> + Beth mae hyn yn golygu?]]> Ydych chi'n sicr eich bod eisiau dileu'r eitem yma? Mae'r priodwedd %0% yn defnyddio'r golygydd %1% sydd ddim yn cyd-fynd â Chynnwys Amnyth. Wyt ti'n siŵr fod ti eisiau dileu pob eitem? @@ -316,6 +323,12 @@ Creu newydd Gludo o'r clipfwrdd Mae'r eitem yma yn y Bin Ailgylchu + Nid yw'r math o elfen a ddewiswyd yn cynnwys unrhyw grwpiau a gefnogir (nid yw tabiau'n cael eu cefnogi gan y golygydd hwn, naill ai eu newid i grwpiau neu ddefnyddio golygydd y Rhestr Bloc). + Ni chaniateir arbed + Ni chaniateir cyhoeddi + Ni chaniateir anfon am gymeradwyaeth + Ni chaniateir amserlennu + Ni chaniateir dad-gyhoeddi Creu Templed Cynnwys newydd o '%0%' @@ -343,11 +356,18 @@ Methwyd ailenwi'r ffolder gyda id %0% Llusgo a gollwng eich ffeil(iau) i mewn i'r ardal Ni chaniateir llwytho i fyny yn y lleoliad hwn. + Ni ellir lanlwytho'r ffeil yma, ni chaniateir y math cyfrwng gydag alias '%0%' yma + Ni ellir lanlwytho'r ffeil yma, nid oes ganddi enw ffeil dilys Creu aelod newydd Pob Aelod Nid oes gan grwpiau aelodau unrhyw eiddo ychwanegol ar gyfer golygu. + Mae aelod gyda'r mewngofnodi hwn yn bodoli yn barod + Mae'r aelod yn y grŵp '%0%' yn barod + Mae gan yr aelod gyfrinair yn barod + Nid yw cloi allan wedi'i alluogi ar gyfer yr aelod hwn + Nid yw'r aelod yn y grŵp '%0%' Wedi methu copïo'r fath cynnwys @@ -549,9 +569,21 @@ %0%.]]> %0% o'r grŵp %1%]]> Ydw, dileu + Dewiswch ieithoedd + Rydych chi'n dileu'r gosodiad + Bydd addasu'r gosodiad yn arwain at golli data ar gyfer unrhyw gynnwys presennol sy'n seiliedig ar y ffurfweddiad hwn. Nid oes unrhyw eitemau geiriadur. + + I fewnforio eitem geiriadur, dewch o hyd i'r ffeil ".udt" ar eich cyfrifiadur trwy glicio + ar y botwm "Mewnforio" (bydd gofyn i chi am gadarnhad ar y sgrin nesaf) + + Nid yw eitem geiriadur yn bodoli. + Nid yw eitem rhiant yn bodoli. + Nid oes unrhyw eitemau geiriadur yn y ffeil hon. + Ni chanfuwyd unrhyw eitemau geiriadur. + Creu eitem geiriadur @@ -664,9 +696,9 @@ Dewiswch y ffolder i symud i'r strwythyr goeden isod wedi symud o dan - %0% yn dileu'r briodweddau a'i data o'r eitemau canlynol]]> Rwy'n deall y weithred hon yn dileu'r holl briodweddau a data sy'n seiliedig ar Fath o Ddata hon + Mae newid golygydd eiddo ar fath o ddata, â gwerthoedd wedi'u storio, wedi'i analluogi. I ganiatáu hyn gallwch newid y gosodiad Umbraco:CMS:DataTypes:CanBeChanged yn appssettings.json. Mae eich data wedi'i achub, ond cyn i chi allu cyhoeddi'r dudalen yma, mae yna wallau yr ydych angen eu gwirio yn gyntaf: @@ -707,6 +739,8 @@ Gwall yn y ffynhonnell XSLT Nid yw'r XSLTwedi'i achub gan ei fod yn cynnwys gwall(au) Mae gwall ffurfwedd gyda'r math o ddata sy'n cael ei ddefnyddio ar gyfer y priodwedd yma, gwiriwch y fath o ddata + Mae methiant anhysbys wedi digwydd + Methiant cydsyniadau optimistaidd, gwrthrych wedi'i addasu Dewisiadau @@ -870,6 +904,17 @@ Clirio Arsefydlu Avatar am + + Cyfryngau + Enw Nôd + Darllen fwy + Dychwelyd + Cyfrannol + Enw Fath + Dilysu + Pennawd + maes system + Diweddarwyd Diwethaf Du @@ -928,9 +973,14 @@ Tudalen + Methu cadw'r ffeil web.config. Addaswch y llinyn cysylltu â llaw os gwelwch yn dda. Ni all y gosodydd gysylltu â'r gronfa ddata. Canfwyd eich cronfa ddata ac mae'n cael ei adnabod fel Ffurfwedd gronfa ddata + Trwy glicio ar y botwm nesaf (neu addasu'r umbracoConfigurationStatus yn web.config), rydych chi'n derbyn y drwydded ar gyfer y feddalwedd hon fel y nodir yn y blwch isod. Sylwch fod y dosbarthiad Umbraco hwn yn cynnwys dwy drwydded wahanol, y drwydded MIT ffynhonnell agored ar gyfer y fframwaith a thrwydded radwedd Umbraco sy'n cwmpasu'r UI. + To finish the installation, you'll need to manually edit the + <strong>/web.config file</strong> a diweddaru'r allwedd AppSetting <strong>UmbracoConfigurationStatus</strong> yn y gwaelod i'r werth <strong>'%0%'</strong>. + gosod i osod y gronfa ddata %0% Umbraco @@ -1182,6 +1232,12 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang ]]> + Un cam olaf + Rydych chi wedi galluogi dilysu 2-ffactor ac mae'n rhaid i chi wirio pwy ydych chi. + Dewiswch ddarparwr 2 ffactor + Cod dilysu + Rhowch y cod dilysu os gwelwch yn dda + Cod annilys wedi'i nodi Dashfwrdd @@ -1411,6 +1467,11 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Cliciwch 'Cwblhau' i orffen y gosodiad ac adnewyddu'r dudalen. Lanlwytho pecyn... Wedi gwirio i weithio ar Umbraco Cloud + Cyfarwyddiadau gosod + Wedi'i hyrwyddo + Rhedeg ymfudiadau pecyn tra'n aros + Mae mudo pecynnau wedi'u cwblhau'n llwyddiannus. + Mae'r holl fudiadau pecyn wedi'u cwblhau'n llwyddiannus. Gludo gyda fformatio llawn (Heb ei argymell) @@ -1502,6 +1563,11 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Dileu pob cyfryngau? Clipfwrdd Ni chaniateir + Agor dewisydd cyfryngau + + + Dewiswch Olygydd Eiddo + Dewiswch Olygydd Eiddo Darparwch ddolen allanol @@ -1529,6 +1595,11 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Rolio yn ôl at Dewis fersiwn Gwedd + + Yn dangos fersiwn %0% i %1% o %2% fersiynau. + Fersiynau + Fersiwn drafft cyfredol + Fersiwn cyhoeddedig cyfredol Golygu ffeil sgript @@ -1559,6 +1630,8 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Y fideos tiwtorial Umbraco gorau Ymweld â our.umbraco.com Ymweld â umbraco.tv + Gwyliwch ein fideos tiwtorial am ddim + ar Ganolfan Ddysgu Umbraco Templed diofyn @@ -1704,6 +1777,20 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Ni all drefnu'r ddogfen i'w chyhoeddi oherwydd mae ganddo'r gofynnol '%0%' ddyddiad cyhoeddi yn hwyrach nag iaith nad yw'n orfodol Ni all y dyddiad terfyn fod yn y gorffennol Ni all y dyddiad terfyn fod cyn y dyddiad rhyddhau + Mae'r ffeil hon yn cael ei lanlwytho fel rhan o ffolder, ond ni chaniateir creu ffolder newydd yma + Ni chaniateir creu ffolder newydd yma + Templed Cynnwys wedi'i gadw + Mae newidiadau wedi'u cadw'n llwyddiannus + Mae Grŵp Aelodau arall gyda'r un enw yn bodoli yn barod + Allforiwyd eitem(au) geiriadur i ffeil + Mae gwall wedi digwydd wrth allforio'r eitem(au) geiriadur + Mae'r eitem(au) geiriadur canlynol wedi ei mewnforio! + Nid yw parthau wedi'u ffurfweddu ar gyfer gwefan amlieithog, cysylltwch â gweinyddwr, gweler y log am ragor o wybodaeth + Nid oes parth wedi ei ffurfweddu ar gyfer %0%, cysylltwch â gweinyddwr, gweler y log am fwy o wybodaeth + Digwyddodd gwall wrth alluogi glanhau fersiwn ar gyfer %0% + Digwyddodd gwall wrth analluogi glanhau fersiwn ar gyfer %0% + Mae gwybodaeth eich system wedi'i chopïo'n llwyddiannus i'r clipfwrdd + Methu â chopïo gwybodaeth eich system i'r clipfwrdd Yn defnyddio cystrawen CSS e.e: h1, .coch, .glas @@ -1813,6 +1900,7 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang esgynnol disgynnol Templed + Nid oes modd golygu cynnwys wrth ddefnyddio modd amser rhedeg <code>Production</code>. Golygydd Testun Gyfoethog @@ -1863,6 +1951,9 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Rhybudd Rydych chi'n dileu'r ffurfwedd rhes Bydd dileu enw ffurfwedd rhes yn arwain at golli data ar gyfer unrhyw gynnwys cynfodol sy'n seiliedig ar ffurfwedd hwn. + <p>Bydd addasu enw cyfluniad rhes yn arwain at golli data ar gyfer unrhyw gynnwys presennol sy'n seiliedig ar y ffurfweddiad hwn.</p> <p><strong>Ni fydd addasu'r label yn unig yn arwain at golli data.</strong></p> + Rydych chi'n dileu'r gosodiad + Bydd addasu cynllun yn arwain at golli data ar gyfer unrhyw gynnwys presennol sy'n seiliedig ar y ffurfweddiad hwn. Cyfansoddiadau @@ -1947,6 +2038,17 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Ychwanegu tab Trawsnewid i dab Llusgwch eiddo yma i'w gosod yn syth ar y tab + Rydych chi'n cael gwared ar y nod plentyn + Bydd tynnu nod plentyn yn cyfyngu ar opsiynau'r golygydd i greu gwahanol fathau o gynnwys o dan nod. + bydd defnyddio'r golygydd hwn yn cael ei ddiweddaru gyda'r gosodiadau newydd. + Glanhau hanes + Caniatáu diystyru'r gosodiadau glanhau hanes byd-eang. + Cadwch bob fersiwn yn fwy newydd na dyddiau + Cadwch y fersiwn diweddaraf y dydd am ddyddiau + Atal glanhau + Galluogi glanhau + <strong>NODYN!</strong> Mae glanhau fersiynau cynnwys hanesyddol wedi'u hanalluogi'n fyd-eang. Ni fydd y gosodiadau hyn yn dod i rym cyn iddo gael ei alluogi. + Mae newid math o ddata gyda gwerthoedd storio wedi'i analluogi. I ganiatáu hyn gallwch newid y gosodiad Umbraco:CMS:DataTypes:CanBeChanged yn appssettings.json. Ychwanegu iaith @@ -1960,6 +2062,12 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Er mwyn caniatáu i gynnwys amlieithog ddisgyn yn ôl i iaith arall os nad yw'n bresennol yn yr iaith y gofynnwyd amdani, dewiswch hi yma. Iaith cwympo yn ôl dim + Cod ISO + <strong>%0%</strong> yn cael ei rannu ar draws ieithoedd a segmentau. + <strong>%0%</strong> yn cael ei rannu ar draws pob iaith. + <strong>%0%</strong> yn cael ei rannu ar draws pob segment. + Wedi'i rannu: Ieithoedd + Wedi'i rannu: Segments Ychwanegu paramedr @@ -2323,6 +2431,26 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Diweddaraf Mewngofnodi diweddaraf No user groups have been added + Mae defnyddiwr gyda'r mewngofnodi hwn eisoes yn bodoli + Rhaid bod gan y cyfrinair o leiaf un digid ('0'-'9') + Rhaid bod gan y cyfrinair o leiaf un llythrennau bach ('a'-'z') + Rhaid i'r cyfrinair gynnwys o leiaf un nod nad yw'n alffaniwmerig + Rhaid i'r cyfrinair ddefnyddio o leiaf %0% o nodau gwahanol + Rhaid bod gan y cyfrinair o leiaf un priflythrennau ('A'-'Z') + Rhaid i'r cyfrinair fod o leiaf %0% nod + Cyfyngu ar yr ieithoedd y mae gan ddefnyddwyr fynediad i olygu + Caniatáu mynediad i bob iaith + Mae gan y defnyddiwr set cyfrinair yn barod + Mae'r defnyddiwr yn y grŵp '%0%' yn barod + Nid yw cloi allan wedi'i alluogi ar gyfer y defnyddiwr hwn + Nid yw'r defnyddiwr yn y grŵp '%0%' + Ffurfweddu Dau-Ffactor + Cymeradwy + Os ydych chi am analluogi'r darparwr dau ffactor hwn, yna rhaid i chi nodi'r cod a ddangosir ar eich dyfais ddilysu: + Mae'r darparwr dau ffactor hwn wedi'i alluogi + Mae'r darparwr dau-ffactor hwn bellach wedi'i analluogi + Aeth rhywbeth o'i le wrth geisio analluogi'r darparwr dau ffactor hwn + Ydych chi am analluogi'r darparwr dau ffactor hwn ar gyfer y defnyddiwr hwn? Dilysiad @@ -2352,6 +2480,15 @@ Er mwyn gweinyddu eich gwefan, agorwch swyddfa gefn Umbraco a dechreuwch ychwang Dilysiad arferu %1% mwy.]]> %1% gormod.]]> + Enw grŵp aelod annilys + Enw grŵp defnyddiwr annilys + Tocyn annilys + Enw defnyddiwr annilys + Mae e-bost '%0%' wedi'i gymryd yn barod + Mae enw grŵp defnyddiwr '%0%' wedi'i gymryd yn barod + Mae enw grŵp aelod '%0%' wedi'i gymryd yn barod + Mae'r enw defnyddiwr '%0%' wedi'i gymryd yn barod + Nid yw'r gofynion maint cynnwys yn cael eu bodloni ar gyfer un maes neu fwy. Inhalt gelöscht Inhalt unveröffentlicht Inhalt unveröffentlicht für Sprache: %0% @@ -162,6 +171,8 @@ Veröffentlichung für Inhalt angefordert Veröffentlichung für Inhalt angefordert in Sprache: %0% Unterknoten wurden sortiert von Benutzer + Versionsbereinigung deaktiviert für Version: %0% + Versionsbereinigung aktiviert für Version: %0% Kopieren Veröffentlichen Veröffentlichen @@ -175,6 +186,8 @@ Veröffentlichung anfordern Veröffentlichung anfordern Sortieren + Speichern + Speichern Verlauf (alle Variationen) @@ -258,7 +271,7 @@ Dies führt zur folgenden Zeit auf dem Server: Was bedeutet dies? + Was bedeutet dies? ]]> Wollen Sie dieses Element wirklich entfernen? diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/en.xml b/src/Umbraco.Core/EmbeddedResources/Lang/en.xml index e7d3649b4f..d568f48102 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/en.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/en.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Culture and Hostnames @@ -90,7 +90,8 @@ Permission denied. - Add new Domain + Add new domain + Add current domain remove Invalid node. One or more domains have an invalid format. @@ -273,7 +274,7 @@ Target This translates to the following time on the server: - What does this mean?]]> + What does this mean?]]> Are you sure you want to delete this item? Property %0% uses editor %1% which is not supported by Nested Content. @@ -603,6 +604,7 @@ The health status of the index and if it can be read Indexers Index info + Content in index Lists the properties of the index Manage Examine's indexes Allows you to view the details of each index and provides some tools for @@ -828,6 +830,7 @@ Retry Permissions Scheduled Publishing + Umbraco info Search Sorry, we can not find what you are looking for. No items have been added @@ -1301,9 +1304,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Install instructions This package has no configuration view No packages have been created yet - You don’t have any packages installed + No packages have been installed - 'Packages' icon in the top right of your screen]]> + 'Packages' icon in the top right of your screen]]> Package Content License Search for packages @@ -1450,6 +1453,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Changes + Created + Current version Red text will be removed in the selected version, green text will be added]]> There are no differences between the current (draft) version and the selected version @@ -2347,6 +2352,12 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Strict-Transport-Security, also known as the HSTS-header, was found.]]> Strict-Transport-Security was not found.]]> + + Strict-Transport-Security, also known as the HSTS-header, was found. This header should not be present on localhost.]]> + + + Strict-Transport-Security was not found. This header should not be present on localhost.]]> + X-XSS-Protection was found.]]> X-XSS-Protection was not found.]]> @@ -2378,7 +2389,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button. - You can add your own health checks, have a look at the documentation for more information about custom health checks.

+ You can add your own health checks, have a look at the documentation for more information about custom health checks.

]]>
@@ -2667,7 +2678,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Find out more in the Documentation section of Our Umbraco + Read more about working with the items in Settings in the Documentation section of Our Umbraco ]]> @@ -2777,29 +2788,29 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Size options Define one or more size options, this enables resizing of the Block Available column spans - Define the different number of columns this block is allowed to span across. This does not prevent Blocks to be placed in Areas of a smaller column span. + Define the different number of columns this block is allowed to span across. This does not prevent Blocks from being placed in Areas with a smaller column span. Available row spans Define the range of layout rows this block is allowed to span across. Allow in root Make this block available in the root of the layout. Allow in areas Make this block available by default within the areas of other Blocks (unless explicit permissions are set for these areas). - When empty all Blocks allowed for Areas can be created. + By default, all block types are allowed in an Area, Use this option to allow only selected types. Areas Grid Columns for Areas Define how many columns that will be available for areas. If not defined, the number of columns defined for the entire layout will be used. Areas - To enable nesting of blocks within this block, define one or more areas for blocks to be nested within. Areas follow their own layout witch is defined by the Grid Columns for Areas. Each Area column span and row span can be adjusted by using the scale-handler in the bottom right corner. + To enable the nesting of blocks within this block, define one or more areas. Areas follow the layout defined by their own grid column configuration. The 'column span' and 'row span' for each area can be adjusted by using the scale-handler box in the bottom right hand corner of the selected area. %0% is not allowed at this spot.]]> Default layout stylesheet Disallowed content was rejected - + Drag to scale Create Button Label - Overwrite the label on the create button of this Area. + Override the label text for adding a new Block to this Area, Example: 'Add Widget' Show resize options Add Block Add group diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml b/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml index 16ccd5c8d1..5acf1b7abe 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Culture and Hostnames @@ -92,7 +92,8 @@ Permission denied. - Add new Domain + Add new domain + Add current domain remove Invalid node. One or more domains have an invalid format. @@ -277,7 +278,7 @@ Target This translates to the following time on the server: - What does this mean?]]> + What does this mean?]]>
Are you sure you want to delete this item? Are you sure you want to delete all items? Property %0% uses editor %1% which is not supported by Nested @@ -619,6 +620,7 @@ The health status of the index and if it can be read Indexers Index info + Content in index Lists the properties of the index Manage Examine's indexes Allows you to view the details of each index and provides some tools for @@ -856,6 +858,7 @@ Retry Permissions Scheduled Publishing + Umbraco info Search Sorry, we can not find what you are looking for. No items have been added @@ -1329,9 +1332,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Install instructions This package has no configuration view No packages have been created yet - You don’t have any packages installed + No packages have been installed - 'Packages' icon in the top right of your screen]]> + 'Packages' icon in the top right of your screen]]> Package Content License Search for packages @@ -1490,7 +1493,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Changes + Created Select a version to compare with the current version + Current version Red text will be removed in the selected version, green text will be added]]> There are no differences between the current (draft) version and the selected version @@ -1503,6 +1508,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont View Versions + Current draft version Current published version @@ -2449,6 +2455,12 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Strict-Transport-Security, also known as the HSTS-header, was found.]]> Strict-Transport-Security was not found.]]> + + Strict-Transport-Security, also known as the HSTS-header, was found. This header should not be present on localhost.]]> + + + Strict-Transport-Security was not found. This header should not be present on localhost.]]> + X-XSS-Protection was found.]]> X-XSS-Protection was not found.]]> @@ -2480,7 +2492,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button. - You can add your own health checks, have a look at the documentation for more information about custom health checks.

+ You can add your own health checks, have a look at the documentation for more information about custom health checks.

]]>
@@ -2769,7 +2781,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Find out more in the Documentation section of Our Umbraco + Read more about working with the items in Settings in the Documentation section of Our Umbraco ]]> @@ -2879,29 +2891,29 @@ To manage your website, simply open the Umbraco backoffice and start adding cont Size options Define one or more size options, this enables resizing of the Block Available column spans - Define the different number of columns this block is allowed to span across. This does not prevent Blocks to be placed in Areas of a smaller column span. + Define the different number of columns this block is allowed to span across. This does not prevent Blocks from being placed in Areas with a smaller column span. Available row spans Define the range of layout rows this block is allowed to span across. Allow in root Make this block available in the root of the layout. Allow in areas Make this block available by default within the areas of other Blocks (unless explicit permissions are set for these areas). - When empty all Blocks allowed for Areas can be created. + By default, all block types are allowed in an Area, Use this option to allow only selected types. Areas Grid Columns for Areas Define how many columns that will be available for areas. If not defined, the number of columns defined for the entire layout will be used. Areas - To enable nesting of blocks within this block, define one or more areas for blocks to be nested within. Areas follow their own layout witch is defined by the Grid Columns for Areas. Each Area column span and row span can be adjusted by using the scale-handler in the bottom right corner. + To enable the nesting of blocks within this block, define one or more areas. Areas follow the layout defined by their own grid column configuration. The 'column span' and 'row span' for each area can be adjusted by using the scale-handler box in the bottom right hand corner of the selected area. %0% is not allowed at this spot.]]> Default layout stylesheet Disallowed content was rejected - + Drag to scale Create Button Label - Overwrite the label on the create button of this Area. + Override the label text for adding a new Block to this Area, Example: 'Add Widget' Show resize options Add Block Add group diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/es.xml b/src/Umbraco.Core/EmbeddedResources/Lang/es.xml index 4a111302b3..b2ab390a2e 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/es.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/es.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Administrar dominios @@ -190,7 +190,7 @@ Nodos hijo Destino Esto se traduce en la siguiente hora en el servidor: - ¿Esto qué significa?]]> + ¿Esto qué significa?]]> ¿Estás seguro que quieres eliminar este elemento? Propiedad %0% utiliza editor %1% que no está soportado por Nested Content. Añadir otra caja de texto diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/fr.xml b/src/Umbraco.Core/EmbeddedResources/Lang/fr.xml index 384981e467..1576cedbe4 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/fr.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/fr.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Culture et noms d'hôte @@ -252,7 +252,7 @@ Eléments enfants Cible Ceci se traduit par l'heure suivante sur le serveur : - Qu'est-ce que cela signifie?]]> + Qu'est-ce que cela signifie?]]> Etes-vous certain(e) de vouloir supprimer cet élément? Etes-vous certain(e) de vouloir supprimer tous les éléments? La propriété %0% utilise l'éditeur %1% qui n'est pas supporté par Nested Content. @@ -2203,7 +2203,7 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à En savoir plus dans la section Documentation de Our Umbraco + Lisez-en plus sur la façon de travailler avec les éléments dans la section Settings dans la section Documentation de Our Umbraco ]]> diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/he.xml b/src/Umbraco.Core/EmbeddedResources/Lang/he.xml index 819e71aec9..f0427bbae1 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/he.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/he.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files נהל שמות מתחם diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/it.xml b/src/Umbraco.Core/EmbeddedResources/Lang/it.xml index c85274b80f..2430542e66 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/it.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/it.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Gestisci hostnames @@ -280,7 +280,7 @@ Target Questo si traduce nella seguente ora sul server: - Cosa significa questo?]]> + Cosa significa questo?]]> Sei sicuro di voler eliminare questo oggetto? Sei sicuro di voler eliminare tutti gli oggetti? @@ -2526,7 +2526,7 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in L'health checker valuta varie aree del tuo sito per le impostazioni delle migliori pratiche, la configurazione, i potenziali problemi, ecc. Puoi facilmente risolvere i problemi premendo un pulsante. - Puoi aggiungere i tuoi health check personalizzati, guarda sulla documentazione per più informazioni riguardo i custom health checks.

+ Puoi aggiungere i tuoi health check personalizzati, guarda sulla documentazione per più informazioni riguardo i custom health checks.

]]>
@@ -2810,7 +2810,7 @@ Per gestire il tuo sito web, è sufficiente aprire il backoffice di Umbraco e in nella documentazione di Our Umbraco + Maggiori informazioni su come lavorare con gli elementi in Impostazioni nella documentazione di Our Umbraco ]]> diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/ja.xml b/src/Umbraco.Core/EmbeddedResources/Lang/ja.xml index 28d512973f..9a94e7d924 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/ja.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/ja.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files ドメインの割り当て diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/ko.xml b/src/Umbraco.Core/EmbeddedResources/Lang/ko.xml index dfe848387c..4aa0d4ad89 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/ko.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/ko.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files 호스트명 관리 diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/nb.xml b/src/Umbraco.Core/EmbeddedResources/Lang/nb.xml index c19aa1df4f..c2784b3a9c 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/nb.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/nb.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Angi domene diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/nl.xml b/src/Umbraco.Core/EmbeddedResources/Lang/nl.xml index 735302e951..dbacedc658 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/nl.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/nl.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Beheer domeinnamen @@ -274,7 +274,7 @@ Doel Dit betekend de volgende tijd op de server: - Wat houd dit in?]]> + Wat houd dit in?]]> Ben je er zeker van dat je dit item wilt verwijderen? Ben je zeker dat je alle items wilt verwijderen? Eigenschap %0% gebruikt editor %1% welke niet wordt ondersteund door @@ -1253,7 +1253,9 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Wijzigingen + Aangemaakt Selecteer een versie om te vergelijken met de huidige versie + Huidige versie Rode tekst wordt niet getoond in de geselecteerde versie, groen betekent toegevoegd]]> Document is teruggezet @@ -1265,6 +1267,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Bekijk Versies + Conceptversie Gepubliceerde versie @@ -2174,7 +2177,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je De health checker evalueert verschillende delen van de website voor best practice instellingen, configuratie, mogelijke problemen, enzovoort. U kunt problemen eenvoudig oplossen met een druk op de knop. - U kunt uw eigen health checks toevoegen, kijk even naar de documentatie voor meer informatie over aangepaste health checks.

+ U kunt uw eigen health checks toevoegen, kijk even naar de documentatie voor meer informatie over aangepaste health checks.

]]>
@@ -2429,7 +2432,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Meer te weten komen in het Documentatiegedeelte van Our Umbraco + Lees meer over het werken met de items in de sectie Instellingen in het Documentatiegedeelte van Our Umbraco ]]> @@ -2543,10 +2546,33 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Blokken Instellingen Maak dit blok standaard beschikbaar binnen de gebieden van andere blokken (behalve wanneer expliciete rechten zijn gezet voor deze gebieden). + Indien leeg kunnen alle blokken toegestaand in gebieden worden toegevoegd. + Grid Kolommen voor Gebieden. + Definiëer hoeveel kolommen beschikbaar zijn in gebiede. Indien niet gedefinieerd wordt het aantal kolommen gedefinieerd voor de gehele lay-out gebruikt. + Gebieden + Om het nesten van blokken binnen-in dit blok toe te staan, definieer een of meer gebieden voor blokken om binnenin te nesten. Gebieden volgen hun eigen lay-out welke gedefinieerd is bij de Grid Kolommen voor Gebieden. Elk Gebied kolombreedte can worden gewijzigd door het gebruik van de schaal in de hoek rechtsonderin + %0% is niet toegestaan op deze locatie.]]> + Standaard lay-out stylesheet + Niet-toegestane content is geweigerd + + + Sleep om te vergroten/verkleinen + Maak Button Label + Overschrijf het label van de create button van dit Gebied. + Toon vergroot/verklein opties + Voeg Blok toe + Voeg groep toep + Selecteer groep of Blok + Zet een minimale vereiste Gebieden Gebieden Geadvanceerd Rechten + Installeer Voorbeeld Configuratie + Installeer + Sorteer mode + Sluit sorteer mode + Dit Gebieds' Alias moet uniek zijn ten opzichte van andere Gebieden in dit Blok. Configureer gebied Verwijder gebied diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/pl.xml b/src/Umbraco.Core/EmbeddedResources/Lang/pl.xml index a4d891fd8f..53aa716792 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/pl.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/pl.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Zarządzanie hostami @@ -184,7 +184,7 @@ Elementy dzieci Cel Oznacza to następującą godzinę na serwerze: - Co to oznacza?]]> + Co to oznacza?]]> Czy na pewno chcesz usunąć ten element? Właściwość %0% używa edytora %1%, który nie jest wspierany przez Nested Content. Dodaj kolejne pole tekstowe diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/pt.xml b/src/Umbraco.Core/EmbeddedResources/Lang/pt.xml index b5fd920365..f6cdb21208 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/pt.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/pt.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Gerenciar hostnames diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/ru.xml b/src/Umbraco.Core/EmbeddedResources/Lang/ru.xml index f83dd5285c..39be7570a3 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/ru.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/ru.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Языки и домены @@ -218,7 +218,7 @@ Очистить дату ВНИМАНИЕ: этот документ опубликован, но его URL вступает в противоречие с документом %0% Это время будет соответствовать следующему времени на сервере: - Что это означает?]]> + Что это означает?]]> Задать дату Порядок сортировки обновлен Для сортировки узлов просто перетаскивайте узлы или нажмите на заголовке столбца. Вы можете выбрать несколько узлов, удерживая клавиши "shift" или "ctrl" при пометке diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/sv.xml b/src/Umbraco.Core/EmbeddedResources/Lang/sv.xml index e2e7cbcd76..3d89a94af1 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/sv.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/sv.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Innehåll @@ -126,6 +126,7 @@ Skapa en ny dokumenttyp Infoga bild Publicera och stäng + Publicera med undersidor Ändra relation Återvänd till lista Spara @@ -149,6 +150,7 @@ (hur skulle du beskriva denna bild för någon över telefon) Alternativa länkar Alternativ text (optionell) + Bildtext (optionell) Underliggande noder Klicka för att redigera detta objekt Skapad av @@ -196,6 +198,11 @@ Uppdaterad av Ta bort fil Länk till dokument + Avpublicerad + Publicerad (osparade ändringar) + Inga undernoder har lagts till + Inga ändringar har gjorts + Ej skapad Var vill du skapa den nya %0% @@ -222,10 +229,10 @@ Installera Umbraco Forms - Stay - Discard changes - You have unsaved changes - Are you sure you want to navigate away from this page? - you have unsaved changes + Stanna + Ignorera ändringar + Du har osparade ändringar + Är du säker på att du vill lämna sidan? - Du har osparade ändringar. Klar @@ -723,6 +730,7 @@ Sortering klar Välj i vilken ordning du vill ha sidorna genom att dra dem upp eller ner i listan. Du kan också klicka på kolumnrubrikerna för att sortera grupper av sidor + Den här noden har inga undernoder att sortera Publiceringen avbröts av ett tredjepartstillägg diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/tr.xml b/src/Umbraco.Core/EmbeddedResources/Lang/tr.xml index 30a38ba6c7..1195378516 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/tr.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/tr.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files Kültür ve Ana Bilgisayar Adları @@ -257,7 +257,7 @@ Alt öğeler Hedef Bu, sunucuda şu zamana çevrilir: - Ne bu ne anlama geliyor? ]]> + Ne bu ne anlama geliyor? ]]> Bu öğeyi silmek istediğinizden emin misiniz? %0% özelliği,%1% düzenleyiciyi kullanıyor ve bu, Yuvalanmış İçerik tarafından desteklenmiyor. Tüm öğeleri silmek istediğinizden emin misiniz? @@ -2085,7 +2085,7 @@ Web sitenizi yönetmek için, Umbraco'nun arka ofisini açın ve içerik eklemey Durum denetleyicisi, sitenizin çeşitli alanlarını en iyi uygulama ayarları, yapılandırma, olası sorunlar vb. için değerlendirir. Sorunları bir düğmeye basarak kolayca düzeltebilirsiniz. - Kendi sağlık kontrollerinizi ekleyebilir, özel durum kontrolleri hakkında daha fazla bilgi için belgeler .

+ Kendi sağlık kontrollerinizi ekleyebilir, özel durum kontrolleri hakkında daha fazla bilgi için belgeler .

]]>
@@ -2314,7 +2314,7 @@ Web sitenizi yönetmek için, Umbraco'nun arka ofisini açın ve içerik eklemey Daha fazla bilgi edinin öğelerle çalışma hakkında daha fazla bilgi edinin Our Umbraco'nun Dokümantasyon bölümünde + Ayarlar öğelerle çalışma hakkında daha fazla bilgi edinin Our Umbraco'nun Dokümantasyon bölümünde ]]> diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/zh.xml b/src/Umbraco.Core/EmbeddedResources/Lang/zh.xml index 199b185ed3..83ea263a97 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/zh.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/zh.xml @@ -2,7 +2,7 @@ 黄仁祥(wanddy@163.com) - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files 管理主机名 @@ -147,7 +147,7 @@ 子项 目标 这将转换到服务器上的以下时间: - 这是什么意思?]]> + 这是什么意思?]]> 点击上传 diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/zh_tw.xml b/src/Umbraco.Core/EmbeddedResources/Lang/zh_tw.xml index d57c1c614d..d334178766 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/zh_tw.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/zh_tw.xml @@ -2,7 +2,7 @@ The Umbraco community - https://our.umbraco.com/documentation/Extending-Umbraco/Language-Files + https://docs.umbraco.com/umbraco-cms/extending/language-files 管理主機名稱 @@ -145,7 +145,7 @@ 子項目 目標 預計發表的時間(伺服器端) - 這是什麼意思?]]> + 這是什麼意思?]]> 點選以便上傳 diff --git a/src/Umbraco.Core/Extensions/StringExtensions.cs b/src/Umbraco.Core/Extensions/StringExtensions.cs index eb1a125c5f..6a76650523 100644 --- a/src/Umbraco.Core/Extensions/StringExtensions.cs +++ b/src/Umbraco.Core/Extensions/StringExtensions.cs @@ -83,18 +83,19 @@ public static class StringExtensions return fileName; } - var lastIndex = fileName.LastIndexOf('.'); + var spanFileName = fileName.AsSpan(); + var lastIndex = spanFileName.LastIndexOf('.'); if (lastIndex > 0) { - var ext = fileName.Substring(lastIndex); + var ext = spanFileName[lastIndex..]; // file extensions cannot contain whitespace - if (ext.Contains(" ")) + if (ext.Contains(' ')) { return fileName; } - return string.Format("{0}", fileName.Substring(0, fileName.IndexOf(ext, StringComparison.Ordinal))); + return new string(spanFileName[..lastIndex]); } return fileName; diff --git a/src/Umbraco.Core/Extensions/UriExtensions.cs b/src/Umbraco.Core/Extensions/UriExtensions.cs index 60ef7b6a7e..3868586e44 100644 --- a/src/Umbraco.Core/Extensions/UriExtensions.cs +++ b/src/Umbraco.Core/Extensions/UriExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System; using System.Net; using System.Web; using Umbraco.Cms.Core; @@ -75,14 +76,14 @@ public static class UriExtensions } // cannot get .AbsolutePath on relative uri (InvalidOperation) - var s = uri.OriginalString; + var s = uri.OriginalString.AsSpan(); // TODO: Shouldn't this just use Uri.GetLeftPart? - var posq = s.IndexOf("?", StringComparison.Ordinal); - var posf = s.IndexOf("#", StringComparison.Ordinal); + var posq = s.IndexOf('?'); + var posf = s.IndexOf('#'); var pos = posq > 0 ? posq : posf > 0 ? posf : 0; - var path = pos > 0 ? s.Substring(0, pos) : s; - return path; + var path = pos > 0 ? s[..pos] : s; + return new string(path); } /// @@ -188,12 +189,12 @@ public static class UriExtensions } // cannot get .Query on relative uri (InvalidOperation) - var s = uri.OriginalString; - var posq = s.IndexOf("?", StringComparison.Ordinal); - var posf = s.IndexOf("#", StringComparison.Ordinal); - var query = posq < 0 ? null : (posf < 0 ? s.Substring(posq) : s.Substring(posq, posf - posq)); + var s = uri.OriginalString.AsSpan(); + var posq = s.IndexOf('?'); + var posf = s.IndexOf('#'); + var query = posq < 0 ? null : (posf < 0 ? s[posq..] : s.Slice(posq, posf - posq)); - return query; + return new string(query); } /// diff --git a/src/Umbraco.Core/HealthChecks/Checks/Security/HstsCheck.cs b/src/Umbraco.Core/HealthChecks/Checks/Security/HstsCheck.cs index 229999472e..0637404045 100644 --- a/src/Umbraco.Core/HealthChecks/Checks/Security/HstsCheck.cs +++ b/src/Umbraco.Core/HealthChecks/Checks/Security/HstsCheck.cs @@ -3,6 +3,7 @@ using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; namespace Umbraco.Cms.Core.HealthChecks.Checks.Security; @@ -16,6 +17,11 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security; Group = "Security")] public class HstsCheck : BaseHttpHeaderCheck { + private const string LocalizationPrefix = "hSTS"; + + private readonly IHostingEnvironment _hostingEnvironment; + private readonly ILocalizedTextService _textService; + /// /// Initializes a new instance of the class. /// @@ -27,10 +33,56 @@ public class HstsCheck : BaseHttpHeaderCheck /// but then you should include subdomains and I wouldn't suggest to do that for Umbraco-sites. /// public HstsCheck(IHostingEnvironment hostingEnvironment, ILocalizedTextService textService) - : base(hostingEnvironment, textService, "Strict-Transport-Security", "hSTS", true) + : base(hostingEnvironment, textService, "Strict-Transport-Security", LocalizationPrefix, true) { + _hostingEnvironment = hostingEnvironment; + _textService = textService; } /// protected override string ReadMoreLink => Constants.HealthChecks.DocumentationLinks.Security.HstsCheck; + + /// + public override async Task> GetStatus() => + new HealthCheckStatus[] { await CheckForHeader() }; + + /// + /// The health check task. + /// + /// A with the result type reversed on localhost. + protected new async Task CheckForHeader() + { + HealthCheckStatus checkHeaderResult = await base.CheckForHeader(); + + var isLocalhost = _hostingEnvironment.ApplicationMainUrl?.Host.ToLowerInvariant() == "localhost"; + + // when not on localhost, the header should exist. + if (!isLocalhost) + { + return checkHeaderResult; + } + + string message; + StatusResultType statusResultType; + + // on localhost the header should not exist, so invert the status. + if (checkHeaderResult.ResultType == StatusResultType.Success) + { + statusResultType = StatusResultType.Error; + + message = _textService.Localize("healthcheck", $"{LocalizationPrefix}CheckHeaderFoundOnLocalhost"); + } + else + { + statusResultType = StatusResultType.Success; + + message = _textService.Localize("healthcheck", $"{LocalizationPrefix}CheckHeaderNotFoundOnLocalhost"); + } + + return new HealthCheckStatus(message) + { + ResultType = statusResultType, + ReadMoreLink = ReadMoreLink, + }; + } } diff --git a/src/Umbraco.Core/IO/ViewHelper.cs b/src/Umbraco.Core/IO/ViewHelper.cs index e68101918a..0d4fcce3dc 100644 --- a/src/Umbraco.Core/IO/ViewHelper.cs +++ b/src/Umbraco.Core/IO/ViewHelper.cs @@ -1,7 +1,7 @@ using System.Text; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.IO; diff --git a/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs b/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs index 17b89d8ec0..8b00a89ba1 100644 --- a/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs +++ b/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs @@ -3,9 +3,9 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Core.Telemetry; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.Install.InstallSteps; diff --git a/src/Umbraco.Core/Models/Blocks/BlockListItem.cs b/src/Umbraco.Core/Models/Blocks/BlockListItem.cs index 0c3f1b55e3..6ccc4080e2 100644 --- a/src/Umbraco.Core/Models/Blocks/BlockListItem.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockListItem.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Core.Models.Blocks; /// /// Represents a layout item for the Block List editor. /// -/// +/// [DataContract(Name = "block", Namespace = "")] public class BlockListItem : IBlockReference { @@ -74,7 +74,7 @@ public class BlockListItem : IBlockReference /// The type of the content. -/// +/// public class BlockListItem : BlockListItem where T : IPublishedElement { @@ -103,7 +103,7 @@ public class BlockListItem : BlockListItem /// /// The type of the content. /// The type of the settings. -/// +/// public class BlockListItem : BlockListItem where TContent : IPublishedElement where TSettings : IPublishedElement diff --git a/src/Umbraco.Core/Models/Mapping/ContentVariantMapper.cs b/src/Umbraco.Core/Models/Mapping/ContentVariantMapper.cs index 91bd8c3589..856f68f9ec 100644 --- a/src/Umbraco.Core/Models/Mapping/ContentVariantMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentVariantMapper.cs @@ -2,13 +2,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Actions; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Extensions; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Models.Mapping; diff --git a/src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs index 9ce3371384..cda8c66e69 100644 --- a/src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs @@ -1,8 +1,8 @@ using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.Models.Mapping; diff --git a/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs index 9174ee7004..34552d0f0b 100644 --- a/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Actions; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Media; @@ -14,7 +15,6 @@ using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Sections; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using UserProfile = Umbraco.Cms.Core.Models.ContentEditing.UserProfile; diff --git a/src/Umbraco.Core/Models/Range.cs b/src/Umbraco.Core/Models/Range.cs index 78d49ad851..5be2d068d4 100644 --- a/src/Umbraco.Core/Models/Range.cs +++ b/src/Umbraco.Core/Models/Range.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Core.Models; /// Represents a range with a minimum and maximum value. /// /// The type of the minimum and maximum values. -/// +/// public class Range : IEquatable> where T : IComparable { diff --git a/src/Umbraco.Core/Models/RelationItem.cs b/src/Umbraco.Core/Models/RelationItem.cs index 111d7e6dfa..a865e7cc2f 100644 --- a/src/Umbraco.Core/Models/RelationItem.cs +++ b/src/Umbraco.Core/Models/RelationItem.cs @@ -1,4 +1,4 @@ -using System.Runtime.Serialization; +using System.Runtime.Serialization; namespace Umbraco.Cms.Core.Models; @@ -20,6 +20,9 @@ public class RelationItem [DataMember(Name = "udi")] public Udi? NodeUdi => NodeType == Constants.UdiEntityType.Unknown ? null : Udi.Create(NodeType, NodeKey); + [DataMember(Name = "published")] + public bool? NodePublished { get; set; } + [DataMember(Name = "icon")] public string? ContentTypeIcon { get; set; } diff --git a/src/Umbraco.Core/Notifications/ContentMovedNotification.cs b/src/Umbraco.Core/Notifications/ContentMovedNotification.cs index 50bd24876d..bfba84db48 100644 --- a/src/Umbraco.Core/Notifications/ContentMovedNotification.cs +++ b/src/Umbraco.Core/Notifications/ContentMovedNotification.cs @@ -6,6 +6,9 @@ using Umbraco.Cms.Core.Models; namespace Umbraco.Cms.Core.Notifications; +/// +/// Called after content has been moved. +/// public sealed class ContentMovedNotification : MovedNotification { public ContentMovedNotification(MoveEventInfo target, EventMessages messages) diff --git a/src/Umbraco.Core/Notifications/ContentMovingNotification.cs b/src/Umbraco.Core/Notifications/ContentMovingNotification.cs index eddc7a13f7..6fd0fc1115 100644 --- a/src/Umbraco.Core/Notifications/ContentMovingNotification.cs +++ b/src/Umbraco.Core/Notifications/ContentMovingNotification.cs @@ -6,6 +6,9 @@ using Umbraco.Cms.Core.Models; namespace Umbraco.Cms.Core.Notifications; +/// +/// Called while content is moving, but before it has been moved. Cancel the operation to prevent the movement. +/// public sealed class ContentMovingNotification : MovingNotification { public ContentMovingNotification(MoveEventInfo target, EventMessages messages) diff --git a/src/Umbraco.Core/Notifications/ContentPublishedNotification.cs b/src/Umbraco.Core/Notifications/ContentPublishedNotification.cs index 0400155d3c..a5929a393f 100644 --- a/src/Umbraco.Core/Notifications/ContentPublishedNotification.cs +++ b/src/Umbraco.Core/Notifications/ContentPublishedNotification.cs @@ -6,6 +6,9 @@ using Umbraco.Cms.Core.Models; namespace Umbraco.Cms.Core.Notifications; +/// +/// Called after content has been published. +/// public sealed class ContentPublishedNotification : EnumerableObjectNotification { public ContentPublishedNotification(IContent target, EventMessages messages) @@ -18,5 +21,8 @@ public sealed class ContentPublishedNotification : EnumerableObjectNotification< { } + /// + /// Gets a enumeration of with the published entities. + /// public IEnumerable PublishedEntities => Target; } diff --git a/src/Umbraco.Core/Notifications/ContentPublishingNotification.cs b/src/Umbraco.Core/Notifications/ContentPublishingNotification.cs index c9a1110089..fd958d2341 100644 --- a/src/Umbraco.Core/Notifications/ContentPublishingNotification.cs +++ b/src/Umbraco.Core/Notifications/ContentPublishingNotification.cs @@ -6,6 +6,9 @@ using Umbraco.Cms.Core.Models; namespace Umbraco.Cms.Core.Notifications; +/// +/// Called while publishing content but before content has been published. Cancel the operation to prevent the publish. +/// public sealed class ContentPublishingNotification : CancelableEnumerableObjectNotification { public ContentPublishingNotification(IContent target, EventMessages messages) @@ -18,5 +21,8 @@ public sealed class ContentPublishingNotification : CancelableEnumerableObjectNo { } + /// + /// Gets a enumeration of which are being published. + /// public IEnumerable PublishedEntities => Target; } diff --git a/src/Umbraco.Core/Notifications/ContentSortedNotification.cs b/src/Umbraco.Core/Notifications/ContentSortedNotification.cs index 8f0d6304ff..3473f816fb 100644 --- a/src/Umbraco.Core/Notifications/ContentSortedNotification.cs +++ b/src/Umbraco.Core/Notifications/ContentSortedNotification.cs @@ -6,6 +6,9 @@ using Umbraco.Cms.Core.Models; namespace Umbraco.Cms.Core.Notifications; +/// +/// Called after content has been sorted. +/// public sealed class ContentSortedNotification : SortedNotification { public ContentSortedNotification(IEnumerable target, EventMessages messages) diff --git a/src/Umbraco.Core/Notifications/ContentSortingNotification.cs b/src/Umbraco.Core/Notifications/ContentSortingNotification.cs index bc3e94a464..4570b68489 100644 --- a/src/Umbraco.Core/Notifications/ContentSortingNotification.cs +++ b/src/Umbraco.Core/Notifications/ContentSortingNotification.cs @@ -6,6 +6,9 @@ using Umbraco.Cms.Core.Models; namespace Umbraco.Cms.Core.Notifications; +/// +/// Called while content is sorting, but before content has been sorted. Cancel the operation to cancel the sorting. +/// public sealed class ContentSortingNotification : SortingNotification { public ContentSortingNotification(IEnumerable target, EventMessages messages) diff --git a/src/Umbraco.Core/Notifications/MovedNotification.cs b/src/Umbraco.Core/Notifications/MovedNotification.cs index f67273a6d4..5aab6c6b7a 100644 --- a/src/Umbraco.Core/Notifications/MovedNotification.cs +++ b/src/Umbraco.Core/Notifications/MovedNotification.cs @@ -17,5 +17,8 @@ public abstract class MovedNotification : ObjectNotification + /// Gets a enumeration of with the moved entities. + ///
public IEnumerable> MoveInfoCollection => Target; } diff --git a/src/Umbraco.Core/Notifications/MovingNotification.cs b/src/Umbraco.Core/Notifications/MovingNotification.cs index 47a2ecf7bf..41f4c1754a 100644 --- a/src/Umbraco.Core/Notifications/MovingNotification.cs +++ b/src/Umbraco.Core/Notifications/MovingNotification.cs @@ -17,5 +17,8 @@ public abstract class MovingNotification : CancelableObjectNotification + /// Gets a enumeration of with the moving entities. + /// public IEnumerable> MoveInfoCollection => Target; } diff --git a/src/Umbraco.Core/PropertyEditors/BlockGridConfiguration.cs b/src/Umbraco.Core/PropertyEditors/BlockGridConfiguration.cs index f635eb6324..1fab493825 100644 --- a/src/Umbraco.Core/PropertyEditors/BlockGridConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/BlockGridConfiguration.cs @@ -10,13 +10,13 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// public class BlockGridConfiguration { - [ConfigurationField("blocks", "Blocks", "views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.html", Description = "Define Blocks based on Element Types.")] + [ConfigurationField("blocks", "Blocks", "views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.html", Description = "Define Blocks based on Element Types. Use Groups to help organise their selection. Example Groups: 'Layout' and 'Content'")] public BlockGridBlockConfiguration[] Blocks { get; set; } = Array.Empty(); [ConfigurationField("blockGroups", "Block Groups", "views/propertyeditors/blockgrid/prevalue/blockgrid.groupconfiguration.html", HideLabel = true)] public BlockGridGroupConfiguration[] BlockGroups { get; set; } = Array.Empty(); - [ConfigurationField("validationLimit", "Amount", "numberrange", Description = "Set a required range of blocks")] + [ConfigurationField("validationLimit", "Amount", "numberrange", Description = "Set the required range for the allowed number of blocks")] public NumberRange ValidationLimit { get; set; } = new NumberRange(); [ConfigurationField("useLiveEditing", "Live editing mode", "boolean", Description = "Live update content when editing in overlay")] @@ -28,10 +28,10 @@ public class BlockGridConfiguration [ConfigurationField("gridColumns", "Grid Columns", "number", Description = "Set the number of columns for the layout. (defaults to 12)")] public int? GridColumns { get; set; } - [ConfigurationField("layoutStylesheet", "Layout Stylesheet", "views/propertyeditors/blockgrid/prevalue/blockgrid.stylesheetpicker.html", Description = "Overwrite default stylesheet for layout.")] + [ConfigurationField("layoutStylesheet", "Layout Stylesheet", "views/propertyeditors/blockgrid/prevalue/blockgrid.stylesheetpicker.html", Description = "Override default stylesheet for backoffice layout.")] public string? LayoutStylesheet { get; set; } - [ConfigurationField("createLabel", "Create Button Label", "textstring", Description = "Overwrite the root create button label")] + [ConfigurationField("createLabel", "Create Button Label", "textstring", Description = "Override the label text for adding a new block, Example 'Add Widget'")] public string? CreateLabel { get; set; } [DataContract] diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs index 6d64bc2d19..f2a3afdbe3 100644 --- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs @@ -4,10 +4,10 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs index 635b590ba4..d6ec338495 100644 --- a/src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs @@ -2,13 +2,13 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Editors; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/DateTimeConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/DateTimeConfigurationEditor.cs index d97f7e2c6d..cb238982e0 100644 --- a/src/Umbraco.Core/PropertyEditors/DateTimeConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DateTimeConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/EmailAddressConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/EmailAddressConfigurationEditor.cs index 2eb5075195..2ecc8deedc 100644 --- a/src/Umbraco.Core/PropertyEditors/EmailAddressConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/EmailAddressConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/EyeDropperColorPickerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/EyeDropperColorPickerPropertyEditor.cs index c9e8545b68..e4e41561cc 100644 --- a/src/Umbraco.Core/PropertyEditors/EyeDropperColorPickerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/EyeDropperColorPickerPropertyEditor.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/FileUploadConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/FileUploadConfigurationEditor.cs index 732e2d795a..f0cb1ccf3b 100644 --- a/src/Umbraco.Core/PropertyEditors/FileUploadConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/FileUploadConfigurationEditor.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/LabelConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/LabelConfigurationEditor.cs index cb5a531f65..477162bca4 100644 --- a/src/Umbraco.Core/PropertyEditors/LabelConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/LabelConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs index eb4c96552f..9ccd0d99af 100644 --- a/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs @@ -2,12 +2,12 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs index 13f423a328..6b44d4ba56 100644 --- a/src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs @@ -54,9 +54,6 @@ public class ListViewConfiguration [ConfigurationField("pageSize", "Page Size", "number", Description = "Number of items per page")] public int PageSize { get; set; } - [ConfigurationField("orderBy", "Order By", "views/propertyeditors/listview/sortby.prevalues.html", Description = "The default sort order for the list")] - public string OrderBy { get; set; } - [ConfigurationField("orderDirection", "Order Direction", "views/propertyeditors/listview/orderDirection.prevalues.html")] public string OrderDirection { get; set; } @@ -67,6 +64,9 @@ public class ListViewConfiguration Description = "The properties that will be displayed for each column")] public Property[] IncludeProperties { get; set; } + [ConfigurationField("orderBy", "Order By", "views/propertyeditors/listview/sortby.prevalues.html", Description = "The default sort order for the list")] + public string OrderBy { get; set; } + [ConfigurationField("layouts", "Layouts", "views/propertyeditors/listview/layouts.prevalues.html")] public Layout[] Layouts { get; set; } diff --git a/src/Umbraco.Core/PropertyEditors/ListViewConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/ListViewConfigurationEditor.cs index 8ecab6d751..4eab700e87 100644 --- a/src/Umbraco.Core/PropertyEditors/ListViewConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ListViewConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/MarkdownPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/MarkdownPropertyEditor.cs index 4bc17c8cfc..8b1b181c8c 100644 --- a/src/Umbraco.Core/PropertyEditors/MarkdownPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MarkdownPropertyEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/MediaPicker3ConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/MediaPicker3ConfigurationEditor.cs index 9ccf64a6f0..ed5a55f99b 100644 --- a/src/Umbraco.Core/PropertyEditors/MediaPicker3ConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MediaPicker3ConfigurationEditor.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/MediaPickerConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/MediaPickerConfigurationEditor.cs index 62e9eac439..e4fa6f5c71 100644 --- a/src/Umbraco.Core/PropertyEditors/MediaPickerConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MediaPickerConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationEditor.cs index a377dae5db..3043bff9cf 100644 --- a/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/MultiUrlPickerConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/MultiUrlPickerConfigurationEditor.cs index f85cafa817..4dfe988a3b 100644 --- a/src/Umbraco.Core/PropertyEditors/MultiUrlPickerConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MultiUrlPickerConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/NestedContentConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/NestedContentConfigurationEditor.cs index 5adb06b42f..cef30f3f4f 100644 --- a/src/Umbraco.Core/PropertyEditors/NestedContentConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/NestedContentConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/RichTextConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/RichTextConfigurationEditor.cs index 4e0b5b557d..d0afbf80d3 100644 --- a/src/Umbraco.Core/PropertyEditors/RichTextConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/RichTextConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/SliderConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/SliderConfigurationEditor.cs index 586e4cd3af..915e92d709 100644 --- a/src/Umbraco.Core/PropertyEditors/SliderConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/SliderConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/TagConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/TagConfigurationEditor.cs index f22f9b74c4..9c2a29d11a 100644 --- a/src/Umbraco.Core/PropertyEditors/TagConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/TagConfigurationEditor.cs @@ -2,11 +2,11 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PropertyEditors.Validators; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/TextAreaConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/TextAreaConfigurationEditor.cs index 7ae52825fb..027010b62e 100644 --- a/src/Umbraco.Core/PropertyEditors/TextAreaConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/TextAreaConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/TextboxConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/TextboxConfigurationEditor.cs index 69d39a44ab..e97717fc88 100644 --- a/src/Umbraco.Core/PropertyEditors/TextboxConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/TextboxConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/PropertyEditors/TrueFalseConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/TrueFalseConfigurationEditor.cs index 72578f7c5e..b85c67453d 100644 --- a/src/Umbraco.Core/PropertyEditors/TrueFalseConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/TrueFalseConfigurationEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs index 6506d29725..173515a001 100644 --- a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs @@ -3,10 +3,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Routing; diff --git a/src/Umbraco.Core/Services/BasicAuthService.cs b/src/Umbraco.Core/Services/BasicAuthService.cs index 02f955bad6..f42b8c7efc 100644 --- a/src/Umbraco.Core/Services/BasicAuthService.cs +++ b/src/Umbraco.Core/Services/BasicAuthService.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Web.Common.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; namespace Umbraco.Cms.Core.Services.Implement; diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 915b92d78d..2faab2922d 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Exceptions; using Umbraco.Cms.Core.Models; @@ -12,7 +13,6 @@ using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services.Changes; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Services; diff --git a/src/Umbraco.Core/Services/CultureImpactFactory.cs b/src/Umbraco.Core/Services/CultureImpactFactory.cs index a05a030d1b..02fb6b900e 100644 --- a/src/Umbraco.Core/Services/CultureImpactFactory.cs +++ b/src/Umbraco.Core/Services/CultureImpactFactory.cs @@ -1,8 +1,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Services; diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index 4fd698236a..1d257a47b1 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Exceptions; using Umbraco.Cms.Core.IO; @@ -12,7 +13,6 @@ using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using static System.Formats.Asn1.AsnWriter; diff --git a/src/Umbraco.Core/Services/ExternalLoginService.cs b/src/Umbraco.Core/Services/ExternalLoginService.cs index 061e0b93aa..be49927b36 100644 --- a/src/Umbraco.Core/Services/ExternalLoginService.cs +++ b/src/Umbraco.Core/Services/ExternalLoginService.cs @@ -1,10 +1,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Services; diff --git a/src/Umbraco.Core/Services/MemberTypeService.cs b/src/Umbraco.Core/Services/MemberTypeService.cs index 67b7f08111..c4b12d9858 100644 --- a/src/Umbraco.Core/Services/MemberTypeService.cs +++ b/src/Umbraco.Core/Services/MemberTypeService.cs @@ -1,12 +1,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services.Changes; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Services; diff --git a/src/Umbraco.Core/Services/MetricsConsentService.cs b/src/Umbraco.Core/Services/MetricsConsentService.cs index a5309d35f1..a3140c4f61 100644 --- a/src/Umbraco.Core/Services/MetricsConsentService.cs +++ b/src/Umbraco.Core/Services/MetricsConsentService.cs @@ -1,9 +1,9 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.Services; diff --git a/src/Umbraco.Core/Services/TwoFactorLoginService.cs b/src/Umbraco.Core/Services/TwoFactorLoginService.cs index acbdded1c9..64da30b991 100644 --- a/src/Umbraco.Core/Services/TwoFactorLoginService.cs +++ b/src/Umbraco.Core/Services/TwoFactorLoginService.cs @@ -2,11 +2,11 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.Services; diff --git a/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs index 1e17b959b6..fb0f8f4f18 100644 --- a/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs +++ b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Web.Common.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; namespace Umbraco.Cms.Core.Configuration { diff --git a/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs b/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs index 647429ebc4..24a21d1cb8 100644 --- a/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs +++ b/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs @@ -99,15 +99,12 @@ public class ContentIndexPopulator : IndexPopulator { content = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out _).ToArray(); - if (content.Length > 0) - { - var valueSets = _contentValueSetBuilder.GetValueSets(content).ToList(); + var valueSets = _contentValueSetBuilder.GetValueSets(content).ToList(); - // ReSharper disable once PossibleMultipleEnumeration - foreach (IIndex index in indexes) - { - index.IndexItems(valueSets); - } + // ReSharper disable once PossibleMultipleEnumeration + foreach (IIndex index in indexes) + { + index.IndexItems(valueSets); } pageIndex++; @@ -127,35 +124,32 @@ public class ContentIndexPopulator : IndexPopulator // note: We will filter for published variants in the validator content = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out _, PublishedQuery, Ordering.By("Path")).ToArray(); - if (content.Length > 0) + var indexableContent = new List(); + + foreach (IContent item in content) { - var indexableContent = new List(); - - foreach (IContent item in content) + if (item.Level == 1) { - if (item.Level == 1) + // first level pages are always published so no need to filter them + indexableContent.Add(item); + publishedPages.Add(item.Id); + } + else + { + if (publishedPages.Contains(item.ParentId)) { - // first level pages are always published so no need to filter them - indexableContent.Add(item); + // only index when parent is published publishedPages.Add(item.Id); - } - else - { - if (publishedPages.Contains(item.ParentId)) - { - // only index when parent is published - publishedPages.Add(item.Id); - indexableContent.Add(item); - } + indexableContent.Add(item); } } + } - var valueSets = _contentValueSetBuilder.GetValueSets(indexableContent.ToArray()).ToList(); + var valueSets = _contentValueSetBuilder.GetValueSets(indexableContent.ToArray()).ToList(); - foreach (IIndex index in indexes) - { - index.IndexItems(valueSets); - } + foreach (IIndex index in indexes) + { + index.IndexItems(valueSets); } pageIndex++; diff --git a/src/Umbraco.Infrastructure/Examine/MediaIndexPopulator.cs b/src/Umbraco.Infrastructure/Examine/MediaIndexPopulator.cs index 19a2a96160..20df2c229e 100644 --- a/src/Umbraco.Infrastructure/Examine/MediaIndexPopulator.cs +++ b/src/Umbraco.Infrastructure/Examine/MediaIndexPopulator.cs @@ -59,13 +59,10 @@ public class MediaIndexPopulator : IndexPopulator { media = _mediaService.GetPagedDescendants(mediaParentId, pageIndex, pageSize, out _).ToArray(); - if (media.Length > 0) + // ReSharper disable once PossibleMultipleEnumeration + foreach (IIndex index in indexes) { - // ReSharper disable once PossibleMultipleEnumeration - foreach (IIndex index in indexes) - { - index.IndexItems(_mediaValueSetBuilder.GetValueSets(media)); - } + index.IndexItems(_mediaValueSetBuilder.GetValueSets(media)); } pageIndex++; diff --git a/src/Umbraco.Infrastructure/Examine/MemberIndexPopulator.cs b/src/Umbraco.Infrastructure/Examine/MemberIndexPopulator.cs index 9dc2102d5e..29f0763e28 100644 --- a/src/Umbraco.Infrastructure/Examine/MemberIndexPopulator.cs +++ b/src/Umbraco.Infrastructure/Examine/MemberIndexPopulator.cs @@ -32,13 +32,10 @@ public class MemberIndexPopulator : IndexPopulator { members = _memberService.GetAll(pageIndex, pageSize, out _).ToArray(); - if (members.Length > 0) + // ReSharper disable once PossibleMultipleEnumeration + foreach (IIndex index in indexes) { - // ReSharper disable once PossibleMultipleEnumeration - foreach (IIndex index in indexes) - { - index.IndexItems(_valueSetBuilder.GetValueSets(members)); - } + index.IndexItems(_valueSetBuilder.GetValueSets(members)); } pageIndex++; diff --git a/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs b/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs index d4a6265052..95997dbbf5 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs @@ -6,10 +6,10 @@ using Newtonsoft.Json; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Telemetry; using Umbraco.Cms.Core.Telemetry.Models; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Infrastructure.HostedServices; diff --git a/src/Umbraco.Infrastructure/Install/InstallHelper.cs b/src/Umbraco.Infrastructure/Install/InstallHelper.cs index 9305c4444e..4686625895 100644 --- a/src/Umbraco.Infrastructure/Install/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Install/InstallHelper.cs @@ -4,13 +4,13 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Core.Net; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Migrations.Install; using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using Umbraco.Cms.Infrastructure.Persistence; using Constants = Umbraco.Cms.Core.Constants; diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs index 386d0ac251..2a1ac11f48 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Membership; @@ -14,7 +15,6 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Migrations.Install; using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using Constants = Umbraco.Cms.Core.Constants; using HttpResponseMessage = System.Net.Http.HttpResponseMessage; diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/SerilogLogViewerSourceBase.cs b/src/Umbraco.Infrastructure/Logging/Viewer/SerilogLogViewerSourceBase.cs index 56efba4ca9..4b41df90f7 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/SerilogLogViewerSourceBase.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/SerilogLogViewerSourceBase.cs @@ -2,8 +2,8 @@ using Microsoft.Extensions.DependencyInjection; using Serilog; using Serilog.Events; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Logging.Viewer; diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs index e2303cf2a2..5f4c024b42 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PropertyEditors; @@ -8,7 +9,6 @@ using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Migrations.PostMigrations; using Umbraco.Cms.Infrastructure.Persistence.Dtos; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0; diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs index dfc713f912..89658914ab 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs @@ -1,12 +1,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Persistence.Dtos; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0; diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs index d3359d09fb..fbb0b49bb0 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PropertyEditors; @@ -8,7 +9,6 @@ using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Migrations.PostMigrations; using Umbraco.Cms.Infrastructure.Persistence.Dtos; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0; diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_17_0/AddPropertyTypeGroupColumns.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_17_0/AddPropertyTypeGroupColumns.cs index 41289c6e4e..4a22607a48 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_17_0/AddPropertyTypeGroupColumns.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_17_0/AddPropertyTypeGroupColumns.cs @@ -56,7 +56,7 @@ public class AddPropertyTypeGroupColumns : MigrationBase AddColumn("alias", out IEnumerable sqls); // Populate non-null alias column - List? dtos = Database.Fetch(); + List? dtos = Database.Query().Where(x => x.Alias == null).ToList(); foreach (PropertyTypeGroupDto dto in PopulateAliases(dtos)) { Database.Update(dto, x => new { x.Alias }); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs index 88f1a6fee9..9431633993 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs @@ -447,6 +447,9 @@ internal class RelationItemDto [Column(Name = "nodeName")] public string? ChildNodeName { get; set; } + [Column(Name = "nodePublished")] + public bool? ChildNodePublished { get; set; } + [Column(Name = "nodeObjectType")] public Guid ChildNodeObjectType { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs index fc62ac861b..c7966daec1 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs @@ -26,11 +26,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement bool filterMustBeIsDependency, out long totalRecords) { Sql innerUnionSql = GetInnerUnionSql(); - var sql = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql().SelectDistinct( + + var sql = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql() + .SelectDistinct( "[x].[id] as nodeId", "[n].[uniqueId] as nodeKey", "[n].[text] as nodeName", "[n].[nodeObjectType] as nodeObjectType", + "[d].[published] as nodePublished", "[ct].[icon] as contentTypeIcon", "[ct].[alias] as contentTypeAlias", "[ctn].[text] as contentTypeName", @@ -41,14 +44,27 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .From("n") .InnerJoinNested(innerUnionSql, "x") .On((n, x) => n.NodeId == x.Id, "n", "x") - .LeftJoin("c").On((left, right) => left.NodeId == right.NodeId, + .LeftJoin("c") + .On( + (left, right) => left.NodeId == right.NodeId, aliasLeft: "n", aliasRight: "c") .LeftJoin("ct") - .On((left, right) => left.ContentTypeId == right.NodeId, aliasLeft: "c", + .On( + (left, right) => left.ContentTypeId == right.NodeId, + aliasLeft: "c", aliasRight: "ct") - .LeftJoin("ctn").On((left, right) => left.NodeId == right.NodeId, - aliasLeft: "ct", aliasRight: "ctn"); + .LeftJoin("ctn") + .On( + (left, right) => left.NodeId == right.NodeId, + aliasLeft: "ct", + aliasRight: "ctn") + .LeftJoin("d") + .On( + (left, right) => left.NodeId == right.NodeId, + aliasLeft: "n", + aliasRight: "d"); + if (ids.Any()) { sql = sql?.Where(x => ids.Contains(x.NodeId), "n"); @@ -78,25 +94,25 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement var innerUnionSqlChild = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select( "[cr].childId as id", "[cr].parentId as otherId", "[rt].[alias]", "[rt].[name]", "[rt].[isDependency]", "[rt].[dual]") - .From("cr").InnerJoin("rt") + .From("cr") + .InnerJoin("rt") .On((cr, rt) => rt.Dual == false && rt.Id == cr.RelationType, "cr", "rt"); var innerUnionSqlDualParent = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select( "[dpr].parentId as id", "[dpr].childId as otherId", "[dprt].[alias]", "[dprt].[name]", "[dprt].[isDependency]", "[dprt].[dual]") - .From("dpr").InnerJoin("dprt") - .On((dpr, dprt) => dprt.Dual == true && dprt.Id == dpr.RelationType, - "dpr", - "dprt"); + .From("dpr") + .InnerJoin("dprt") + .On( + (dpr, dprt) => dprt.Dual == true && dprt.Id == dpr.RelationType, "dpr", "dprt"); var innerUnionSql3 = _scopeAccessor.AmbientScope.Database.SqlContext.Sql().Select( "[dcr].childId as id", "[dcr].parentId as otherId", "[dcrt].[alias]", "[dcrt].[name]", "[dcrt].[isDependency]", "[dcrt].[dual]") - .From("dcr").InnerJoin("dcrt") - .On((dcr, dcrt) => dcrt.Dual == true && dcrt.Id == dcr.RelationType, - "dcr", - "dcrt"); - + .From("dcr") + .InnerJoin("dcrt") + .On( + (dcr, dcrt) => dcrt.Dual == true && dcrt.Id == dcr.RelationType, "dcr", "dcrt"); var innerUnionSql = innerUnionSqlChild.Union(innerUnionSqlDualParent).Union(innerUnionSql3); @@ -124,11 +140,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .WhereLike(x => x.Path, subsubQuery); Sql innerUnionSql = GetInnerUnionSql(); + var sql = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql().SelectDistinct( "[x].[id] as nodeId", "[n].[uniqueId] as nodeKey", "[n].[text] as nodeName", "[n].[nodeObjectType] as nodeObjectType", + "[d].[published] as nodePublished", "[ct].[icon] as contentTypeIcon", "[ct].[alias] as contentTypeAlias", "[ctn].[text] as contentTypeName", @@ -139,16 +157,28 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .From("n") .InnerJoinNested(innerUnionSql, "x") .On((n, x) => n.NodeId == x.Id, "n", "x") - .LeftJoin("c").On((left, right) => left.NodeId == right.NodeId, + .LeftJoin("c") + .On( + (left, right) => left.NodeId == right.NodeId, aliasLeft: "n", aliasRight: "c") .LeftJoin("ct") - .On((left, right) => left.ContentTypeId == right.NodeId, aliasLeft: "c", + .On( + (left, right) => left.ContentTypeId == right.NodeId, + aliasLeft: "c", aliasRight: "ct") - .LeftJoin("ctn").On((left, right) => left.NodeId == right.NodeId, - aliasLeft: "ct", aliasRight: "ctn"); - sql = sql?.WhereIn((System.Linq.Expressions.Expression>)(x => x.NodeId), subQuery, - "n"); + .LeftJoin("ctn") + .On( + (left, right) => left.NodeId == right.NodeId, + aliasLeft: "ct", + aliasRight: "ctn") + .LeftJoin("d") + .On( + (left, right) => left.NodeId == right.NodeId, + aliasLeft: "n", + aliasRight: "d"); + + sql = sql?.WhereIn((System.Linq.Expressions.Expression>)(x => x.NodeId), subQuery, "n"); if (filterMustBeIsDependency) { @@ -178,6 +208,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement "[n].[uniqueId] as nodeKey", "[n].[text] as nodeName", "[n].[nodeObjectType] as nodeObjectType", + "[d].[published] as nodePublished", "[ct].[icon] as contentTypeIcon", "[ct].[alias] as contentTypeAlias", "[ctn].[text] as contentTypeName", @@ -188,14 +219,26 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement .From("n") .InnerJoinNested(innerUnionSql, "x") .On((n, x) => n.NodeId == x.OtherId, "n", "x") - .LeftJoin("c").On((left, right) => left.NodeId == right.NodeId, + .LeftJoin("c") + .On( + (left, right) => left.NodeId == right.NodeId, aliasLeft: "n", aliasRight: "c") .LeftJoin("ct") - .On((left, right) => left.ContentTypeId == right.NodeId, aliasLeft: "c", + .On( + (left, right) => left.ContentTypeId == right.NodeId, + aliasLeft: "c", aliasRight: "ct") - .LeftJoin("ctn").On((left, right) => left.NodeId == right.NodeId, - aliasLeft: "ct", aliasRight: "ctn") + .LeftJoin("ctn") + .On( + (left, right) => left.NodeId == right.NodeId, + aliasLeft: "ct", + aliasRight: "ctn") + .LeftJoin("d") + .On( + (left, right) => left.NodeId == right.NodeId, + aliasLeft: "n", + aliasRight: "d") .Where(x => x.Id == id, "x"); if (filterMustBeIsDependency) @@ -400,6 +443,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement NodeKey = dto.ChildNodeKey, NodeType = ObjectTypes.GetUdiType(dto.ChildNodeObjectType), NodeName = dto.ChildNodeName, + NodePublished = dto.ChildNodePublished, RelationTypeName = dto.RelationTypeName, RelationTypeIsBidirectional = dto.RelationTypeIsBidirectional, RelationTypeIsDependency = dto.RelationTypeIsDependency, diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs index f36d7b67ff..b014c7d8c0 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs index e64a7fe16c..a257be0c26 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs @@ -2,10 +2,10 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs index 1ce8ae4930..1ef03bb5ab 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs @@ -2,10 +2,10 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs index e4fedf37ea..23fd9d11d7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs @@ -2,11 +2,11 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PropertyEditors.Validators; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs index 831f858fb8..6d523ae612 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs @@ -2,10 +2,10 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs index a2cf5ef6e9..580209c48f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs @@ -5,13 +5,13 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Media; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/GridConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/GridConfigurationEditor.cs index ef4ed16c22..aadd25273d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/GridConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/GridConfigurationEditor.cs @@ -4,9 +4,9 @@ using System.ComponentModel.DataAnnotations; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs index 7119dd50ff..ed8ef423cf 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Media; using Umbraco.Cms.Core.Models; @@ -13,7 +14,6 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Core.Templates; using Umbraco.Cms.Infrastructure.Templates; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs index c3390b3fc5..e21d040dbd 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs @@ -7,13 +7,13 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Media; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs index b1b7c5c034..1dc07119d3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs index 09eb6a1f47..f6198135c0 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Editors; @@ -11,7 +11,6 @@ using Umbraco.Cms.Core.PropertyEditors.ValueConverters; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs index 5cbc8e91a0..6a037cda11 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs @@ -2,13 +2,13 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Editors; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs index 1e20d8cfec..809fff69f2 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs @@ -2,13 +2,13 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Editors; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs index 7387ab7808..6077849891 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs @@ -2,10 +2,10 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs index 4f25a54162..5bfe7fbdd3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json.Linq; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Exceptions; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; @@ -12,7 +13,6 @@ using Umbraco.Cms.Core.PropertyEditors.Validators; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; @@ -68,6 +68,9 @@ public class MultipleTextStringPropertyEditor : DataEditor /// internal class MultipleTextStringPropertyValueEditor : DataValueEditor { + private static readonly string NewLine = "\n"; + private static readonly string[] NewLineDelimiters = { "\r\n", "\r", "\n" }; + private readonly ILocalizedTextService _localizedTextService; public MultipleTextStringPropertyValueEditor( @@ -119,10 +122,10 @@ public class MultipleTextStringPropertyEditor : DataEditor // only allow the max if over 0 if (max > 0) { - return string.Join(Environment.NewLine, array.Take(max)); + return string.Join(NewLine, array.Take(max)); } - return string.Join(Environment.NewLine, array); + return string.Join(NewLine, array); } /// @@ -131,7 +134,6 @@ public class MultipleTextStringPropertyEditor : DataEditor /// cannot have 2 way binding, so to get around that each item in the array needs to be an object with a string. /// /// - /// /// /// /// @@ -141,8 +143,9 @@ public class MultipleTextStringPropertyEditor : DataEditor public override object ToEditor(IProperty property, string? culture = null, string? segment = null) { var val = property.GetValue(culture, segment); - return val?.ToString()?.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) - .Select(x => JObject.FromObject(new { value = x })) ?? new JObject[] { }; + + return val?.ToString()?.Split(NewLineDelimiters, StringSplitOptions.None).Select(x => JObject.FromObject(new { value = x })) + ?? Array.Empty(); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs index 29a3f57a92..aabe11592a 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs @@ -5,13 +5,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Editors; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs index f121e665fe..81efcc835d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs index 8525de17b6..3e0bf324a6 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Media; using Umbraco.Cms.Core.Models; @@ -14,7 +15,6 @@ using Umbraco.Cms.Core.Templates; using Umbraco.Cms.Infrastructure.Examine; using Umbraco.Cms.Infrastructure.Macros; using Umbraco.Cms.Infrastructure.Templates; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs index 4ac27824ba..e2c07f6760 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs index ff646a039d..0a6a40a539 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs @@ -5,13 +5,13 @@ using System.ComponentModel.DataAnnotations; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Editors; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs index acc33a233b..70046fa835 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs @@ -2,10 +2,10 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs index bc340b58ba..fb5d9e68bc 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs @@ -2,10 +2,10 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs index 0a96a3dcee..3dc0b468b8 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs @@ -2,9 +2,9 @@ // See LICENSE for more details. using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueListConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueListConfigurationEditor.cs index d361cb0779..d3d1fdb2ea 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueListConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueListConfigurationEditor.cs @@ -3,9 +3,9 @@ using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json.Linq; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs b/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs index 1213e0af38..0e4ad2e9c6 100644 --- a/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs +++ b/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs @@ -5,13 +5,13 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Routing; diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index 86eba639ce..5bc005fc6d 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Exceptions; using Umbraco.Cms.Core.Hosting; @@ -12,7 +13,6 @@ using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Runtime; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using ComponentCollection = Umbraco.Cms.Core.Composing.ComponentCollection; using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs index 74b00d3644..0b4beec003 100644 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs @@ -4,13 +4,13 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Exceptions; using Umbraco.Cms.Core.Packaging; using Umbraco.Cms.Core.Semver; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Migrations.Upgrade; using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Infrastructure.Runtime; diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index 31249daa67..2468a7f80e 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs @@ -3,12 +3,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.DistributedLocking; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Infrastructure.Persistence; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using CoreDebugSettings = Umbraco.Cms.Core.Configuration.Models.CoreDebugSettings; diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs index 1908a3fbfc..0d2767dd25 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs @@ -5,12 +5,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Security; diff --git a/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs b/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs index 04c0f7c257..034014663d 100644 --- a/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs +++ b/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs @@ -5,8 +5,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Serialization; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Security; diff --git a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs index bd52d43d8b..934cefb0b8 100644 --- a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs @@ -2,13 +2,13 @@ using System.Data; using System.Globalization; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Security; diff --git a/src/Umbraco.Infrastructure/Telemetry/Providers/SystemInformationTelemetryProvider.cs b/src/Umbraco.Infrastructure/Telemetry/Providers/SystemInformationTelemetryProvider.cs index 0a5881528e..4847b4cc25 100644 --- a/src/Umbraco.Infrastructure/Telemetry/Providers/SystemInformationTelemetryProvider.cs +++ b/src/Umbraco.Infrastructure/Telemetry/Providers/SystemInformationTelemetryProvider.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Runtime.InteropServices; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; @@ -23,6 +23,7 @@ internal class SystemInformationTelemetryProvider : IDetailedTelemetryProvider, private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory; private readonly IUmbracoVersion _version; private readonly IServerRoleAccessor _serverRoleAccessor; + private readonly RuntimeSettings _runtimeSettings; [Obsolete($"Use the constructor that does not take an IOptionsMonitor parameter, scheduled for removal in V12")] public SystemInformationTelemetryProvider( @@ -33,8 +34,9 @@ internal class SystemInformationTelemetryProvider : IDetailedTelemetryProvider, IOptionsMonitor globalSettings, IHostEnvironment hostEnvironment, IUmbracoDatabaseFactory umbracoDatabaseFactory, - IServerRoleAccessor serverRoleAccessor) - : this(version, localizationService, modelsBuilderSettings, hostingSettings, hostEnvironment, umbracoDatabaseFactory, serverRoleAccessor) + IServerRoleAccessor serverRoleAccessor, + IOptionsMonitor runtimeSettings) + : this(version, localizationService, modelsBuilderSettings, hostingSettings, hostEnvironment, umbracoDatabaseFactory, serverRoleAccessor, runtimeSettings) { } @@ -45,24 +47,27 @@ internal class SystemInformationTelemetryProvider : IDetailedTelemetryProvider, IOptionsMonitor hostingSettings, IHostEnvironment hostEnvironment, IUmbracoDatabaseFactory umbracoDatabaseFactory, - IServerRoleAccessor serverRoleAccessor) + IServerRoleAccessor serverRoleAccessor, + IOptionsMonitor runtimeSettings) { _version = version; _localizationService = localizationService; _hostEnvironment = hostEnvironment; _umbracoDatabaseFactory = umbracoDatabaseFactory; _serverRoleAccessor = serverRoleAccessor; - + _runtimeSettings = runtimeSettings.CurrentValue; _hostingSettings = hostingSettings.CurrentValue; _modelsBuilderSettings = modelsBuilderSettings.CurrentValue; } - private string CurrentWebServer => IsRunningInProcessIIS() ? "IIS" : "Kestrel"; + private string CurrentWebServer => GetWebServerName(); private string ServerFramework => RuntimeInformation.FrameworkDescription; private string ModelsBuilderMode => _modelsBuilderSettings.ModelsMode.ToString(); + private string RuntimeMode => _runtimeSettings.Mode.ToString(); + private string CurrentCulture => Thread.CurrentThread.CurrentCulture.ToString(); private bool IsDebug => _hostingSettings.Debug; @@ -82,6 +87,7 @@ internal class SystemInformationTelemetryProvider : IDetailedTelemetryProvider, new(Constants.Telemetry.OsLanguage, CurrentCulture), new(Constants.Telemetry.WebServer, CurrentWebServer), new(Constants.Telemetry.ModelsBuilderMode, ModelsBuilderMode), + new(Constants.Telemetry.RuntimeMode, RuntimeMode), new(Constants.Telemetry.AspEnvironment, AspEnvironment), new(Constants.Telemetry.IsDebug, IsDebug), new(Constants.Telemetry.DatabaseProvider, DatabaseProvider), new(Constants.Telemetry.CurrentServerRole, CurrentServerRole), @@ -95,19 +101,28 @@ internal class SystemInformationTelemetryProvider : IDetailedTelemetryProvider, new("Umbraco Version", _version.SemanticVersion.ToSemanticStringWithoutBuild()), new("Current Culture", CurrentCulture), new("Current UI Culture", Thread.CurrentThread.CurrentUICulture.ToString()), - new("Current Webserver", CurrentWebServer), new("Models Builder Mode", ModelsBuilderMode), - new("Debug Mode", IsDebug.ToString()), new("Database Provider", DatabaseProvider), + new("Current Webserver", CurrentWebServer), + new("Models Builder Mode", ModelsBuilderMode), + new("Runtime Mode", RuntimeMode), + new("Debug Mode", IsDebug.ToString()), + new("Database Provider", DatabaseProvider), new("Current Server Role", CurrentServerRole), }; - private bool IsRunningInProcessIIS() + private string GetWebServerName() { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + var processName = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName); + + if (processName.Contains("w3wp")) { - return false; + return "IIS"; } - var processName = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName); - return processName.Contains("w3wp") || processName.Contains("iisexpress"); + if (processName.Contains("iisexpress")) + { + return "IIS Express"; + } + + return "Kestrel"; } } diff --git a/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs b/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs index cb4439f2ae..cb2feb55c3 100644 --- a/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs +++ b/src/Umbraco.PublishedCache.NuCache/Persistence/NuCacheContentRepository.cs @@ -486,7 +486,7 @@ WHERE cmsContentNu.nodeId IN ( Guid mediaObjectType = Constants.ObjectTypes.Media; // remove all - if anything fails the transaction will rollback - if (contentTypeIds == null || contentTypeIds.Count == 0) + if (contentTypeIds is null || contentTypeIds.Count == 0) { // must support SQL-CE Database.Execute( @@ -513,7 +513,7 @@ WHERE cmsContentNu.nodeId IN ( // insert back - if anything fails the transaction will rollback IQuery query = SqlContext.Query(); - if (contentTypeIds != null && contentTypeIds.Count > 0) + if (contentTypeIds is not null && contentTypeIds.Count > 0) { query = query.WhereIn(x => x.ContentTypeId, contentTypeIds); // assume number of ctypes won't blow IN(...) } @@ -526,9 +526,9 @@ WHERE cmsContentNu.nodeId IN ( // the tree is locked, counting and comparing to total is safe IEnumerable descendants = _mediaRepository.GetPage(query, pageIndex++, groupSize, out total, null, Ordering.By("Path")); - var items = descendants.Select(m => GetDto(m, false, serializer)).ToList(); + var items = descendants.Select(m => GetDto(m, false, serializer)).ToArray(); Database.BulkInsertRecords(items); - processed += items.Count; + processed += items.Length; } while (processed < total); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index ae0b9c961f..bd63b51711 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -120,6 +121,13 @@ public class BackOfficeController : UmbracoController // Check if we not are in an run state, if so we need to redirect if (_runtimeState.Level != RuntimeLevel.Run) { + if (_runtimeState.Level == RuntimeLevel.Upgrade) + { + return RedirectToAction(nameof(AuthorizeUpgrade), routeValues: new RouteValueDictionary() + { + ["redir"] = _globalSettings.GetBackOfficePath(_hostingEnvironment), + }); + } return Redirect("/"); } @@ -255,7 +263,7 @@ public class BackOfficeController : UmbracoController [AllowAnonymous] public async Task>> LocalizedText(string? culture = null) { - CultureInfo? cultureInfo; + CultureInfo? cultureInfo = null; if (string.IsNullOrWhiteSpace(culture)) { // Force authentication to occur since this is not an authorized endpoint, we need this to get a user. @@ -264,9 +272,12 @@ public class BackOfficeController : UmbracoController // It's entirely likely for a user to have a different culture in the backoffice, than their system. IIdentity? user = authenticationResult.Principal?.Identity; - cultureInfo = authenticationResult.Succeeded && user is not null - ? user.GetCulture() - : CultureInfo.GetCultureInfo(_globalSettings.DefaultUILanguage); + if (authenticationResult.Succeeded && user is not null) + { + cultureInfo = user.GetCulture(); + } + + cultureInfo ??= CultureInfo.GetCultureInfo(_globalSettings.DefaultUILanguage); } else { diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs index 6d44fcd15f..6dbd5f1e79 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Features; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Mail; @@ -25,7 +26,6 @@ using Umbraco.Cms.Web.BackOffice.Routing; using Umbraco.Cms.Web.BackOffice.Security; using Umbraco.Cms.Web.BackOffice.Trees; using Umbraco.Cms.Web.Common.Attributes; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Cms.Web.Common.Models; using Umbraco.Extensions; diff --git a/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs index 26643da9f0..28a6012901 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Mapping; @@ -22,7 +23,6 @@ using Umbraco.Cms.Web.BackOffice.Trees; using Umbraco.Cms.Web.Common.ActionsResults; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using Stylesheet = Umbraco.Cms.Core.Models.Stylesheet; using StylesheetRule = Umbraco.Cms.Core.Models.ContentEditing.StylesheetRule; diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs index c9bc07457a..99a4ea262d 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Actions; using Umbraco.Cms.Core.ContentApps; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Dictionary; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Mapping; @@ -30,7 +31,6 @@ using Umbraco.Cms.Web.BackOffice.Filters; using Umbraco.Cms.Web.BackOffice.ModelBinders; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Web.BackOffice.Controllers; diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index 87f881ff69..fb1666e522 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs @@ -10,6 +10,7 @@ using Newtonsoft.Json; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Mapping; @@ -23,7 +24,6 @@ using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Web.BackOffice.Filters; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Cms.Web.Common.Security; using Umbraco.Extensions; diff --git a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs index 376d6af3fa..6e559a7c68 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Options; using NPoco; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.ContentEditing; @@ -21,7 +22,6 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Web.BackOffice.Filters; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using Constants = Umbraco.Cms.Core.Constants; diff --git a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs index 8b25275508..2b55ea5155 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.ContentEditing; @@ -21,7 +22,6 @@ using Umbraco.Cms.Infrastructure.Packaging; using System.Xml.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Web.BackOffice.Controllers; diff --git a/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs b/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs index 8dd599be46..65662d8ca5 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs @@ -6,8 +6,8 @@ using Microsoft.Extensions.Options; using Newtonsoft.Json; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Web.Common.Attributes; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Web.BackOffice.Controllers; diff --git a/src/Umbraco.Web.BackOffice/Controllers/LogViewerController.cs b/src/Umbraco.Web.BackOffice/Controllers/LogViewerController.cs index 7389af5112..57ffac3f2f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/LogViewerController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/LogViewerController.cs @@ -4,11 +4,11 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Serilog.Events; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Logging.Viewer; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Web.BackOffice.Controllers; diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index b81d120295..26b776ddde 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -49,6 +49,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers; [ParameterSwapControllerActionSelector(nameof(GetChildren), "id", typeof(int), typeof(Guid), typeof(Udi))] public class MediaController : ContentControllerBase { + private static readonly Semaphore _postAddFileSemaphore = new(1, 1); private readonly AppCaches _appCaches; private readonly IAuthorizationService _authorizationService; private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor; @@ -574,6 +575,7 @@ public class MediaController : ContentControllerBase public async Task PostAddFile([FromForm] string path, [FromForm] string currentFolder, [FromForm] string contentTypeAlias, List file) { + await _postAddFileSemaphore.WaitOneAsync(); var root = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempFileUploads); //ensure it exists Directory.CreateDirectory(root); @@ -581,6 +583,7 @@ public class MediaController : ContentControllerBase //must have a file if (file.Count == 0) { + _postAddFileSemaphore.Release(); return NotFound(); } @@ -588,12 +591,14 @@ public class MediaController : ContentControllerBase ActionResult? parentIdResult = await GetParentIdAsIntAsync(currentFolder, true); if (!(parentIdResult?.Result is null)) { + _postAddFileSemaphore.Release(); return parentIdResult.Result; } var parentId = parentIdResult?.Value; if (!parentId.HasValue) { + _postAddFileSemaphore.Release(); return NotFound("The passed id doesn't exist"); } @@ -605,6 +610,7 @@ public class MediaController : ContentControllerBase if (!IsFolderCreationAllowedHere(parentId.Value)) { AddCancelMessage(tempFiles, _localizedTextService.Localize("speechBubbles", "folderUploadNotAllowed")); + _postAddFileSemaphore.Release(); return Ok(tempFiles); } @@ -638,6 +644,7 @@ public class MediaController : ContentControllerBase //if the media root is null, something went wrong, we'll abort if (mediaRoot == null) { + _postAddFileSemaphore.Release(); return Problem( "The folder: " + folderName + " could not be used for storing images, its ID: " + parentId + " returned null"); @@ -808,10 +815,12 @@ public class MediaController : ContentControllerBase KeyValuePair origin = HttpContext.Request.Query.First(x => x.Key == "origin"); if (origin.Value == "blueimp") { + _postAddFileSemaphore.Release(); return new JsonResult(tempFiles); //Don't output the angular xsrf stuff, blue imp doesn't like that } } + _postAddFileSemaphore.Release(); return Ok(tempFiles); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs index 6a4e7ca236..2a5669f698 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; @@ -10,7 +11,6 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Web.BackOffice.Controllers; diff --git a/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs index 3121e654af..592a5e61ec 100644 --- a/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.Dashboards; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models.ContentEditing; @@ -10,7 +11,6 @@ using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Web.BackOffice.Filters; diff --git a/src/Umbraco.Web.BackOffice/Install/InstallAreaRoutes.cs b/src/Umbraco.Web.BackOffice/Install/InstallAreaRoutes.cs index 0ea55d861d..4e65aaef0f 100644 --- a/src/Umbraco.Web.BackOffice/Install/InstallAreaRoutes.cs +++ b/src/Umbraco.Web.BackOffice/Install/InstallAreaRoutes.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Hosting; @@ -28,23 +29,12 @@ public class InstallAreaRoutes : IAreaRoutes switch (_runtime.Level) { - case var _ when _runtime.EnableInstaller(): + case RuntimeLevel.Install: + case RuntimeLevel.Upgrade: + case RuntimeLevel.Run: + endpoints.MapUmbracoRoute(installPathSegment, Constants.Web.Mvc.InstallArea, "api", includeControllerNameInRoute: false); endpoints.MapUmbracoRoute(installPathSegment, Constants.Web.Mvc.InstallArea, string.Empty, includeControllerNameInRoute: false); - - // register catch all because if we are in install/upgrade mode then we'll catch everything - endpoints.MapFallbackToAreaController(nameof(InstallController.Index), ControllerExtensions.GetControllerName(), Constants.Web.Mvc.InstallArea); - - break; - case RuntimeLevel.Run: - // when we are in run mode redirect to the back office if the installer endpoint is hit - endpoints.MapGet($"{installPathSegment}/{{controller?}}/{{action?}}", context => - { - // redirect to umbraco - context.Response.Redirect(_linkGenerator.GetBackOfficeUrl(_hostingEnvironment)!, false); - return Task.CompletedTask; - }); - break; case RuntimeLevel.BootFailed: case RuntimeLevel.Unknown: diff --git a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs index d64d3d297e..a310944a6d 100644 --- a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs +++ b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs @@ -130,6 +130,11 @@ internal class ContentMapDefinition : IMapDefinition // Umbraco.Code.MapAll private void Map(ContentItemDisplay source, ContentItemDisplayWithSchedule target, MapperContext context) { + foreach (KeyValuePair additionalData in source.AdditionalData) + { + target.AdditionalData.Add(additionalData); + } + target.AllowedActions = source.AllowedActions; target.AllowedTemplates = source.AllowedTemplates; target.AllowPreview = source.AllowPreview; @@ -198,6 +203,11 @@ internal class ContentMapDefinition : IMapDefinition // Umbraco.Code.MapAll private static void Map(ContentItemDisplayWithSchedule source, ContentItemDisplay target, MapperContext context) { + foreach (KeyValuePair additionalData in source.AdditionalData) + { + target.AdditionalData.Add(additionalData); + } + target.AllowedActions = source.AllowedActions; target.AllowedTemplates = source.AllowedTemplates; target.AllowPreview = source.AllowPreview; diff --git a/src/Umbraco.Web.BackOffice/Security/BackOfficeSignInManager.cs b/src/Umbraco.Web.BackOffice/Security/BackOfficeSignInManager.cs index 19a231cf52..81fe5b5aa0 100644 --- a/src/Umbraco.Web.BackOffice/Security/BackOfficeSignInManager.cs +++ b/src/Umbraco.Web.BackOffice/Security/BackOfficeSignInManager.cs @@ -7,10 +7,10 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Cms.Web.Common.Security; using Umbraco.Extensions; diff --git a/src/Umbraco.Web.BackOffice/Services/IconService.cs b/src/Umbraco.Web.BackOffice/Services/IconService.cs index 068db52be6..2870808151 100644 --- a/src/Umbraco.Web.BackOffice/Services/IconService.cs +++ b/src/Umbraco.Web.BackOffice/Services/IconService.cs @@ -5,9 +5,9 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using File = System.IO.File; using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs index 4728ebbca8..8823b62131 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs @@ -109,6 +109,11 @@ public class ContentTreeController : ContentTreeControllerBase, ISearchableTreeW { var culture = queryStrings?["culture"].ToString(); + if(culture.IsNullOrWhiteSpace()) + { + culture = _localizationService.GetDefaultLanguageIsoCode(); + } + IEnumerable allowedUserOptions = GetAllowedUserMenuItemsForNode(entity); if (CanUserAccessNode(entity, allowedUserOptions, culture)) { diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs index 275e28d9aa..8d457169d2 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs @@ -3,12 +3,12 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Trees; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Web.BackOffice.Trees; diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberTypeAndGroupTreeControllerBase.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTypeAndGroupTreeControllerBase.cs index 8b8a885fd5..977205e893 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberTypeAndGroupTreeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberTypeAndGroupTreeControllerBase.cs @@ -3,13 +3,13 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Actions; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Trees; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Trees; using Umbraco.Cms.Web.Common.Attributes; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Web.BackOffice.Trees; diff --git a/src/Umbraco.Web.Common/ActionsResults/MaintenanceResult.cs b/src/Umbraco.Web.Common/ActionsResults/MaintenanceResult.cs new file mode 100644 index 0000000000..6e27321f00 --- /dev/null +++ b/src/Umbraco.Web.Common/ActionsResults/MaintenanceResult.cs @@ -0,0 +1,27 @@ +using System.Net; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Web; + +namespace Umbraco.Cms.Web.Common.ActionsResults; + +/// +/// Returns the Umbraco maintenance result +/// +public class MaintenanceResult : IActionResult +{ + /// + public async Task ExecuteResultAsync(ActionContext context) + { + HttpResponse response = context.HttpContext.Response; + + response.Clear(); + + response.StatusCode = StatusCodes.Status503ServiceUnavailable; + + var viewResult = new ViewResult { ViewName = "~/umbraco/UmbracoWebsite/Maintenance.cshtml" }; + + await viewResult.ExecuteResultAsync(context); + } +} diff --git a/src/Umbraco.Web.Common/ApplicationModels/UmbracoJsonModelBinderConvention.cs b/src/Umbraco.Web.Common/ApplicationModels/UmbracoJsonModelBinderConvention.cs index 236cb39ce3..8298820e07 100644 --- a/src/Umbraco.Web.Common/ApplicationModels/UmbracoJsonModelBinderConvention.cs +++ b/src/Umbraco.Web.Common/ApplicationModels/UmbracoJsonModelBinderConvention.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.DependencyInjection; -using Umbraco.Cms.Web.Common.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Web.Common.ModelBinders; namespace Umbraco.Cms.Web.Common.ApplicationModels; diff --git a/src/Umbraco.Web.Common/Authorization/FeatureAuthorizeHandler.cs b/src/Umbraco.Web.Common/Authorization/FeatureAuthorizeHandler.cs index 485208064d..596cba7f3d 100644 --- a/src/Umbraco.Web.Common/Authorization/FeatureAuthorizeHandler.cs +++ b/src/Umbraco.Web.Common/Authorization/FeatureAuthorizeHandler.cs @@ -3,7 +3,11 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core; using Umbraco.Cms.Core.Features; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Web.Common.Authorization; @@ -13,8 +17,20 @@ namespace Umbraco.Cms.Web.Common.Authorization; public class FeatureAuthorizeHandler : AuthorizationHandler { private readonly UmbracoFeatures _umbracoFeatures; + private readonly IRuntimeState _runtimeState; - public FeatureAuthorizeHandler(UmbracoFeatures umbracoFeatures) => _umbracoFeatures = umbracoFeatures; + public FeatureAuthorizeHandler(UmbracoFeatures umbracoFeatures, IRuntimeState runtimeState) + { + _umbracoFeatures = umbracoFeatures; + _runtimeState = runtimeState; + } + + [Obsolete("Use ctor that is not obsolete. This will be removed in v13.")] + public FeatureAuthorizeHandler(UmbracoFeatures umbracoFeatures) + :this(umbracoFeatures, StaticServiceProvider.Instance.GetRequiredService()) + { + + } protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, @@ -35,6 +51,11 @@ public class FeatureAuthorizeHandler : AuthorizationHandler _globalSettings; + + public MaintenanceModeActionFilter(IRuntimeState runtimeState, IOptionsMonitor globalSettings) + { + _runtimeState = runtimeState; + _globalSettings = globalSettings; + } + + public void OnActionExecuting(ActionExecutingContext context) + { + if (_runtimeState.Level == RuntimeLevel.Upgrade && _globalSettings.CurrentValue.ShowMaintenancePageWhenInUpgradeState) + { + context.Result = new MaintenanceResult(); + } + + } + + public void OnActionExecuted(ActionExecutedContext context) + { + + } + } +} diff --git a/src/Umbraco.Web.Common/Controllers/RenderController.cs b/src/Umbraco.Web.Common/Controllers/RenderController.cs index a9771c0ab8..dad8d8a84b 100644 --- a/src/Umbraco.Web.Common/Controllers/RenderController.cs +++ b/src/Umbraco.Web.Common/Controllers/RenderController.cs @@ -16,6 +16,7 @@ namespace Umbraco.Cms.Web.Common.Controllers; /// [ModelBindingException] [PublishedRequestFilter] +[MaintenanceModeActionFilter] public class RenderController : UmbracoPageController, IRenderController { private readonly ILogger _logger; diff --git a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs index 5951c6e009..e5b4063435 100644 --- a/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/BlockGridTemplateExtensions.cs @@ -30,7 +30,7 @@ public static class BlockGridTemplateExtensions /// The partial views are found in "/src/Umbraco.Cms.StaticAssets/Views/Partials/blockgrid/" on GitHub and should /// be copied to "Views/Partials/BlockGrid/" on your local disk. /// - /// + /// public static async Task GetBlockGridHtmlAsync(this IHtmlHelper html, BlockGridModel? model, string template = DefaultTemplate) { if (model?.Count == 0) diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyImageCropperTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyImageCropperTemplateExtensions.cs index e4481f7f28..aac4023c51 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyImageCropperTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyImageCropperTemplateExtensions.cs @@ -1,11 +1,11 @@ using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Media; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PropertyEditors.ValueConverters; using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Extensions; diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs index 4b7d02bf7a..9bd6f8c599 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs @@ -4,12 +4,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Extensions; diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs index 61761475c5..636e8c3d46 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs @@ -1,7 +1,7 @@ using System.Linq.Expressions; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models.PublishedContent; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Extensions; diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyUrlHelperExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyUrlHelperExtensions.cs index a9da209ba3..cb10291ba6 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyUrlHelperExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyUrlHelperExtensions.cs @@ -1,8 +1,8 @@ using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Extensions; diff --git a/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs index a5e30f9011..62ede3ce18 100644 --- a/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs @@ -97,11 +97,18 @@ public static class ServiceCollectionExtensions // Bootstrap logger setup /////////////////////////////////////////////// - LoggerConfiguration serilogConfig = new LoggerConfiguration() + Func serilogConfig = cfg => cfg .MinimalConfiguration(hostEnvironment, loggingConfig, umbracoFileConfiguration) .ReadFrom.Configuration(configuration); - Log.Logger = serilogConfig.CreateBootstrapLogger(); + if (Log.Logger is ReloadableLogger reloadableLogger) + { + reloadableLogger.Reload(serilogConfig); + } + else + { + Log.Logger = serilogConfig(new LoggerConfiguration()).CreateBootstrapLogger(); + } /////////////////////////////////////////////// // Runtime logger setup diff --git a/src/Umbraco.Web.Common/Hosting/HostBuilderExtensions.cs b/src/Umbraco.Web.Common/Hosting/HostBuilderExtensions.cs index e06dc4bec6..7d80f53980 100644 --- a/src/Umbraco.Web.Common/Hosting/HostBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Hosting/HostBuilderExtensions.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Umbraco.Cms.Web.Common.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Web.Common.Hosting; // ReSharper disable once CheckNamespace diff --git a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs index 77eee873da..9ff69bcb7a 100644 --- a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Extensions; using Umbraco.Cms.Core.Logging; @@ -16,7 +17,6 @@ using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; diff --git a/src/Umbraco.Web.Common/Middleware/BootFailedMiddleware.cs b/src/Umbraco.Web.Common/Middleware/BootFailedMiddleware.cs index 11abf725c2..649e12aa21 100644 --- a/src/Umbraco.Web.Common/Middleware/BootFailedMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/BootFailedMiddleware.cs @@ -1,12 +1,13 @@ +using System.Net.Mime; using System.Text; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Exceptions; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Web.Common.DependencyInjection; using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; namespace Umbraco.Cms.Web.Common.Middleware; @@ -51,6 +52,7 @@ public class BootFailedMiddleware : IMiddleware // Print a nice error page context.Response.Clear(); context.Response.StatusCode = 500; + context.Response.ContentType = MediaTypeNames.Text.Html; IFileInfo? fileInfo = GetBootErrorFileInfo(); if (fileInfo is not null) diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index 74339bac43..9b93ad890c 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Options; using Smidge.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Logging; @@ -17,7 +18,6 @@ using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.WebAssets; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Cms.Web.Common.Profiler; using Umbraco.Cms.Web.Common.Routing; using Umbraco.Extensions; @@ -181,7 +181,8 @@ public class UmbracoRequestMiddleware : IMiddleware if (_umbracoRequestPaths.IsBackOfficeRequest(absPath) || (absPath.Value?.InvariantStartsWith($"/{_smidgeOptions.UrlOptions.CompositeFilePath}") ?? false) - || (absPath.Value?.InvariantStartsWith($"/{_smidgeOptions.UrlOptions.BundleFilePath}") ?? false)) + || (absPath.Value?.InvariantStartsWith($"/{_smidgeOptions.UrlOptions.BundleFilePath}") ?? false) + || _runtimeState.EnableInstaller()) { LazyInitializer.EnsureInitialized(ref s_firstBackOfficeRequest, ref s_firstBackOfficeReqestFlag, ref s_firstBackOfficeRequestLocker, () => diff --git a/src/Umbraco.Web.Common/Security/MemberSignInManager.cs b/src/Umbraco.Web.Common/Security/MemberSignInManager.cs index a746e79e60..7a54911735 100644 --- a/src/Umbraco.Web.Common/Security/MemberSignInManager.cs +++ b/src/Umbraco.Web.Common/Security/MemberSignInManager.cs @@ -5,10 +5,10 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Security; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Web.Common.Security; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbappheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbappheader.directive.js index dd83f6546b..a184967ca2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbappheader.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbappheader.directive.js @@ -97,6 +97,8 @@ if(anchorLink) { anchorLink.focus(); } + const anchorButton = element[0].querySelector('#umbraco-logo-mark'); + anchorButton.classList.add("active"); }); }; scope.keepLogoModal = function() { @@ -108,6 +110,8 @@ scope.logoModal.timer = $timeout(function () { scope.logoModal.show = false; }, 100); + const anchorButton = element[0].querySelector('#umbraco-logo-mark'); + anchorButton.classList.remove("active"); } }; scope.stopClickEvent = function($event) { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js index 6f0e03cc5a..7a5eb9fc29 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbtoggle.directive.js @@ -82,7 +82,7 @@ // Must wait until the current digest cycle is finished before we emit this event on init, // otherwise other property editors might not yet be ready to receive the event $timeout(function () { - eventsService.emit("toggleValue", { value: scope.checked }); + eventsService.emit("toggleValue", { value: scope.checked, inputId: scope.inputId }); }, 100); } @@ -122,7 +122,7 @@ } if (scope.onClick) { - eventsService.emit("toggleValue", { value: !scope.checked }); + eventsService.emit("toggleValue", { value: !scope.checked, inputId: scope.inputId }); scope.onClick(); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js index 364190cf72..94d35cb04b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js @@ -206,6 +206,7 @@ Use this directive to construct a header inside the main editor window. @param {boolean=} hideDescription Set to true to hide description. @param {boolean=} setpagetitle If true the page title will be set to reflect the type of data the header is working with @param {string=} editorfor The localization to use to aid accessibility on the edit and create screen +@param {boolean=} loading Whether a loading indicator should be shown as part of the header. **/ (function () { @@ -217,8 +218,8 @@ Use this directive to construct a header inside the main editor window. scope.vm = {}; scope.vm.dropdownOpen = false; - scope.vm.currentVariant = ""; - scope.loading = true; + scope.vm.currentVariant = ""; + scope.initializing = true; scope.accessibility = {}; scope.accessibility.a11yMessage = ""; scope.accessibility.a11yName = ""; @@ -237,12 +238,12 @@ Use this directive to construct a header inside the main editor window. // to do make it work for user group create/ edit // to make it work for language edit/create setAccessibilityForEditorState(); - scope.loading = false; + scope.initializing = false; } else if (scope.name) { setAccessibilityForName(); - scope.loading = false; + scope.initializing = false; } else { - scope.loading = false; + scope.initializing = false; } scope.goBack = function () { if (scope.onBack) { @@ -402,7 +403,8 @@ Use this directive to construct a header inside the main editor window. onBack: "&?", showBackButton: "' + - '' + + '' + '
' + '', controller: umbDateTimePickerCtrl, @@ -88,7 +88,8 @@ Use this directive to render a date time picker onYearChange: '&?', onReady: '&?', onValueUpdate: '&?', - onDayCreate: '&?' + onDayCreate: '&?', + label: '@' } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js index 98f02b7e06..1841548426 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js @@ -19,239 +19,267 @@ TODO */ angular.module("umbraco.directives") - .directive('umbFileDropzone', - function ($timeout, Upload, localizationService, umbRequestHelper, overlayService, mediaHelper, mediaTypeHelper) { - return { - restrict: 'E', - replace: true, - templateUrl: 'views/components/upload/umb-file-dropzone.html', - scope: { - parentId: '@', - contentTypeAlias: '@', - propertyAlias: '@', - accept: '@', - maxFileSize: '@', - - compact: '@', - hideDropzone: '@', - acceptedMediatypes: '=', + .directive('umbFileDropzone', + function ($timeout, Upload, localizationService, umbRequestHelper, overlayService, mediaHelper, mediaTypeHelper) { + return { + restrict: 'E', + replace: true, + templateUrl: 'views/components/upload/umb-file-dropzone.html', + scope: { + parentId: '@', + contentTypeAlias: '@', + propertyAlias: '@', + accept: '@', + maxFileSize: '@', - filesQueued: '=', - handleFile: '=', - filesUploaded: '=' - }, - link: function(scope, element, attrs) { - scope.queue = []; - scope.totalQueued = 0; - scope.currentFile = undefined; - scope.processed = []; - scope.totalMessages = 0; + compact: '@', + hideDropzone: '@', + acceptedMediatypes: '=', - function _filterFile(file) { - var ignoreFileNames = ['Thumbs.db']; - var ignoreFileTypes = ['directory']; + filesQueued: '=', + handleFile: '=', + filesUploaded: '=' + }, + link: function (scope, element, attrs) { + scope.queue = []; + scope.totalQueued = 0; + scope.processing = []; + scope.processed = []; + scope.totalMessages = 0; + // TODO - Make configurable in appsettings + scope.batchSize = 10; + scope.processingCount = 0; - // ignore files with names from the list - // ignore files with types from the list - // ignore files which starts with "." - if (ignoreFileNames.indexOf(file.name) === -1 && - ignoreFileTypes.indexOf(file.type) === -1 && - file.name.indexOf(".") !== 0) { - return true; - } else { - return false; - } - } + function _filterFile(file) { + var ignoreFileNames = ['Thumbs.db']; + var ignoreFileTypes = ['directory']; - function _filesQueued(files, event) { - //Push into the queue - Utilities.forEach(files, file => { - if (_filterFile(file) === true) { - file.messages = []; - scope.queue.push(file); - } - }); + // ignore files with names from the list + // ignore files with types from the list + // ignore files which starts with "." + if (ignoreFileNames.indexOf(file.name) === -1 && + ignoreFileTypes.indexOf(file.type) === -1 && + file.name.indexOf(".") !== 0) { + return true; + } else { + return false; + } + } - // Upload not allowed - if (!scope.acceptedMediatypes || !scope.acceptedMediatypes.length) { - files.map(file => { - file.messages.push({message: "File type is not allowed here", type: "Error"}); - }); - } + function _filesQueued(files, event) { + //Push into the queue + Utilities.forEach(files, file => { + if (_filterFile(file) === true) { + file.messages = []; + scope.queue.push(file); + } + }); - // If we have Accepted Media Types, we will ask to choose Media Type, if Choose Media Type returns false, it only had one choice and therefor no reason to - if (scope.acceptedMediatypes && _requestChooseMediaTypeDialog() === false) { - scope.contentTypeAlias = "umbracoAutoSelect"; - } + // Upload not allowed + if (!scope.acceptedMediatypes || !scope.acceptedMediatypes.length) { + files.map(file => { + file.messages.push({ message: "File type is not allowed here", type: "Error" }); + }); + } - // Add the processed length, as we might be uploading in stages - scope.totalQueued = scope.queue.length + scope.processed.length; + // If we have Accepted Media Types, we will ask to choose Media Type, if + // Choose Media Type returns false, it only had one choice and therefor no reason to + if (scope.acceptedMediatypes && _requestChooseMediaTypeDialog() === false) { + scope.contentTypeAlias = "umbracoAutoSelect"; + } - _processQueueItems(); - } + // Add all of the processing and processed files to account for uploading + // files in stages (dragging files X at a time into the dropzone). + scope.totalQueued = scope.queue.length + scope.processingCount + scope.processed.length; - function _processQueueItems() { - // if we have processed all files, either by successful - // upload, or attending to all messages, we deem the - // action complete, else continue processing files - scope.totalMessages = scope.processed.filter(e => e.messages.length > 0).length; - if (scope.totalQueued === scope.processed.length) { - if (scope.totalMessages === 0) { - if (scope.filesUploaded) { - //queue is empty, trigger the done action - scope.filesUploaded(scope.done); - } - //auto-clear the done queue after 3 secs - var currentLength = scope.processed.length; - $timeout(function() { - scope.processed.splice(0, currentLength); - }, 3000); - } - } else { - scope.currentFile = scope.queue.shift(); - _upload(scope.currentFile); - } - } + _processQueueItems(); + } - function _upload(file) { + function _processQueueItems() { - scope.propertyAlias = scope.propertyAlias ? scope.propertyAlias : "umbracoFile"; - scope.contentTypeAlias = scope.contentTypeAlias ? scope.contentTypeAlias : "Image"; + if (scope.processingCount === scope.batchSize) { + return; + } - Upload.upload({ - url: umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostAddFile"), - fields: { - 'currentFolder': scope.parentId, - 'contentTypeAlias': scope.contentTypeAlias, - 'propertyAlias': scope.propertyAlias, - 'path': file.path - }, - file: file - }) - .progress(function(evt) { - if (file.uploadStat !== "done" && file.uploadStat !== "error") { - // calculate progress in percentage - var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10); - // set percentage property on file - file.uploadProgress = progressPercentage; - } - }) - .success(function (data, status, headers, config) { - // Set server messages - file.messages = data.notifications; - scope.processed.push(file); - //after processing, test if everything is done - scope.currentFile = undefined; - _processQueueItems(); - }) - .error(function(evt, status, headers, config) { - //if the service returns a detailed error - if (evt.InnerException) { - file.messages.push({ message: evt.InnerException.ExceptionMessage, type: "Error" }); - //Check if its the common "too large file" exception - if (evt.InnerException.StackTrace && - evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) { - file.messages.push({ message: "File too large to upload", type: "Error" }); - } - } else if (evt.Message) { - file.messages.push({message: evt.Message, type: "Error"}); - } else if (evt && typeof evt === "string") { - file.messages.push({message: evt, type: "Error"}); - } - // If file not found, server will return a 404 and display this message - if (status === 404) { - file.messages.push({message: "File not found", type: "Error"}); - } - scope.currentFile = undefined; - _processQueueItems(); - }); - } + // if we have processed all files, either by successful + // upload, or attending to all messages, we deem the + // action complete, else continue processing files + scope.totalMessages = scope.processed.filter(e => e.messages.length > 0).length; - function _requestChooseMediaTypeDialog() { - - if (scope.queue.length === 0) { - // if queue has no items so there is nothing to choose a type for - return false; - } - - if (scope.acceptedMediatypes.length === 1) { - // if only one accepted type, then we wont ask to choose. - return false; - } - - var uploadFileExtensions = scope.queue.map(file => mediaHelper.getFileExtension(file.name)); - - var filteredMediaTypes = mediaTypeHelper.getTypeAcceptingFileExtensions(scope.acceptedMediatypes, uploadFileExtensions); - - var mediaTypesNotFile = filteredMediaTypes.filter(mediaType => mediaType.alias !== "File"); - - if (mediaTypesNotFile.length <= 1) { - // if only one or less accepted types when we have filtered type 'file' out, then we wont ask to choose. - return false; - } - - - localizationService.localizeMany(["defaultdialogs_selectMediaType", "mediaType_autoPickMediaType"]).then(function (translations) { - - filteredMediaTypes.push({ - alias: "umbracoAutoSelect", - name: translations[1], - icon: "icon-wand" - }); - - const dialog = { - view: "itempicker", - filter: filteredMediaTypes.length > 8, - availableItems: filteredMediaTypes, - submit: function (model) { - scope.contentTypeAlias = model.selectedItem.alias; - _processQueueItems(); - - overlayService.close(); - }, - close: function () { - - scope.queue.map(function (file) { - file.messages.push({message:"No files uploaded, no mediatype selected", type: "Error"}); - }); - scope.queue = []; - - overlayService.close(); - } - }; - - dialog.title = translations[0]; - overlayService.open(dialog); - }); - - return true; // yes, we did open the choose-media dialog, therefore we return true. - } - - scope.dismissMessages = function (file) { - file.messages = []; - _processQueueItems(); - } - - scope.dismissAllMessages = function () { - Utilities.forEach(scope.processed, file => { - file.messages = []; - }); - _processQueueItems(); - } - - scope.handleFiles = function(files, event, invalidFiles) { - const allFiles = [...files, ...invalidFiles]; - - // add unique key for each files to use in ng-repeats - Utilities.forEach(allFiles, file => { - file.key = String.CreateGuid(); - }); - - if (scope.filesQueued) { - scope.filesQueued(allFiles, event); - } - _filesQueued(allFiles, event); - }; + if (scope.totalQueued === scope.processed.length) { + if (scope.totalMessages === 0) { + if (scope.filesUploaded) { + //queue is empty, trigger the done action + scope.filesUploaded(scope.done); } - }; - }); + + //auto-clear the done queue after 3 secs + var currentLength = scope.processed.length; + $timeout(function () { + scope.processed.splice(0, currentLength); + }, 3000); + } + } else if (scope.queue.length) { + + var file = scope.queue.shift(); + scope.processing.push(file); + _upload(file); + + // If we still have items to process + // do so right away for parallel uploads + if (scope.queue.length > 0) { + _processQueueItems(); + } + } + } + + function _upload(file) { + + scope.propertyAlias = scope.propertyAlias ? scope.propertyAlias : "umbracoFile"; + scope.contentTypeAlias = scope.contentTypeAlias ? scope.contentTypeAlias : "Image"; + + scope.processingCount++; + + Upload.upload({ + url: umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostAddFile"), + fields: { + 'currentFolder': scope.parentId, + 'contentTypeAlias': scope.contentTypeAlias, + 'propertyAlias': scope.propertyAlias, + 'path': file.path + }, + file: file + }) + .progress(function (evt) { + if (file.uploadStat !== "done" && file.uploadStat !== "error") { + // calculate progress in percentage + var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10); + // set percentage property on file + file.uploadProgress = progressPercentage; + } + }) + .success(function (data, status, headers, config) { + // Set server messages + file.messages = data.notifications; + file.done = true; + scope.processed.push(file); + scope.processingCount--; + _processQueueItems(); + }) + .error(function (evt, status, headers, config) { + //if the service returns a detailed error + if (evt.InnerException) { + file.messages.push({ message: evt.InnerException.ExceptionMessage, type: "Error" }); + //Check if its the common "too large file" exception + if (evt.InnerException.StackTrace && + evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) { + file.messages.push({ message: "File too large to upload", type: "Error", header: "Error" }); + } + } else if (status === 413) { + file.messages.push({ message: "File too large to upload", type: "Error", header: "Error" }); + } else if (evt.Message) { + file.messages.push({ message: evt.Message, type: "Error", header: "Error" }); + } else if (evt && typeof evt === "string") { + file.messages.push({ message: evt, type: "Error", header: "Error" }); + } else if (status === 404) { + // If file not found, server will return a 404 and display this message + file.messages.push({ message: "File not found", type: "Error" }); + } else if (status !== 200) { + file.messages.push({ message: "An unknown error occurred", type: "Error", header: "Error" }); + } + + file.done = true; + scope.processed.push(file); + scope.processingCount--; + _processQueueItems(); + }); + } + + function _requestChooseMediaTypeDialog() { + + if (scope.queue.length === 0) { + // if queue has no items so there is nothing to choose a type for + return false; + } + + if (scope.acceptedMediatypes.length === 1) { + // if only one accepted type, then we wont ask to choose. + return false; + } + + var uploadFileExtensions = scope.queue.map(file => mediaHelper.getFileExtension(file.name)); + + var filteredMediaTypes = mediaTypeHelper.getTypeAcceptingFileExtensions(scope.acceptedMediatypes, uploadFileExtensions); + + var mediaTypesNotFile = filteredMediaTypes.filter(mediaType => mediaType.alias !== "File"); + + if (mediaTypesNotFile.length <= 1) { + // if only one or less accepted types when we have filtered type 'file' out, then we wont ask to choose. + return false; + } + + + localizationService.localizeMany(["defaultdialogs_selectMediaType", "mediaType_autoPickMediaType"]).then(function (translations) { + + filteredMediaTypes.push({ + alias: "umbracoAutoSelect", + name: translations[1], + icon: "icon-wand" + }); + + const dialog = { + view: "itempicker", + filter: filteredMediaTypes.length > 8, + availableItems: filteredMediaTypes, + submit: function (model) { + scope.contentTypeAlias = model.selectedItem.alias; + _processQueueItems(); + + overlayService.close(); + }, + close: function () { + + scope.queue.map(function (file) { + file.messages.push({ message: "No files uploaded, no mediatype selected", type: "Error" }); + }); + scope.queue = []; + + overlayService.close(); + } + }; + + dialog.title = translations[0]; + overlayService.open(dialog); + }); + + return true; // yes, we did open the choose-media dialog, therefore we return true. + } + + scope.dismissMessages = function (file) { + file.messages = []; + _processQueueItems(); + } + + scope.dismissAllMessages = function () { + Utilities.forEach(scope.processed, file => { + file.messages = []; + }); + _processQueueItems(); + } + + scope.handleFiles = function (files, event, invalidFiles) { + const allFiles = [...files, ...invalidFiles]; + + // add unique key for each files to use in ng-repeats + Utilities.forEach(allFiles, file => { + file.key = String.CreateGuid(); + }); + + if (scope.filesQueued) { + scope.filesQueued(allFiles, event); + } + _filesQueued(allFiles, event); + }; + } + }; + }); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/usershelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/usershelper.service.js index e6450798fb..65296d6d84 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/usershelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/usershelper.service.js @@ -8,7 +8,7 @@ { "value": 0, "name": "Active", "key": "Active", "color": "success" }, { "value": 1, "name": "Disabled", "key": "Disabled", "color": "danger" }, { "value": 2, "name": "Locked out", "key": "LockedOut", "color": "danger" }, - { "value": 3, "name": "Invited", "key": "Invited", "color": "warning" }, + { "value": 3, "name": "Invited", "key": "Invited", "color": "primary" }, { "value": 4, "name": "Inactive", "key": "Inactive", "color": "warning" } ]; diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/database.controller.js b/src/Umbraco.Web.UI.Client/src/installer/steps/database.controller.js index 69acd3a3a6..af25608ef7 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/steps/database.controller.js +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/database.controller.js @@ -29,7 +29,7 @@ angular.module("umbraco.install").controller("Umbraco.Installer.DataBaseControll $scope.validateAndForward = function() { - if (!$scope.checking && this.myForm.$valid) + if (!$scope.checking && this.installerForm.$valid) { $scope.checking = true; $scope.invalidDbDns = false; diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/database.html b/src/Umbraco.Web.UI.Client/src/installer/steps/database.html index e75a82f9df..4282770e75 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/steps/database.html +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/database.html @@ -6,7 +6,7 @@

Go back diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/permissionsreport.html b/src/Umbraco.Web.UI.Client/src/installer/steps/permissionsreport.html index 366f8b9d19..f3067e8fb6 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/steps/permissionsreport.html +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/permissionsreport.html @@ -3,7 +3,7 @@

In order to run Umbraco, you'll need to update your permission settings. Detailed information about the correct file and folder permissions for Umbraco can be found - here. + here.

The following report list the permissions that are currently failing. Once the permissions are fixed press the 'Go back' button to restart the installation. diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/user.controller.js b/src/Umbraco.Web.UI.Client/src/installer/steps/user.controller.js index 6654fe447c..28a781a8ec 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/steps/user.controller.js +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/user.controller.js @@ -81,7 +81,7 @@ angular.module("umbraco.install").controller("Umbraco.Install.UserController", f }; $scope.validateAndForward = function () { - if (this.myForm.$valid) { + if (this.installerForm.$valid) { installerService.forward(); } }; diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/user.html b/src/Umbraco.Web.UI.Client/src/installer/steps/user.html index 7e37c57328..20c406aefe 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/steps/user.html +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/user.html @@ -8,7 +8,7 @@ @@ -137,7 +137,7 @@

-
+
Change Database -
@@ -159,7 +159,7 @@
- -
+
+ +
-
+ + +
+
+ + +
    + + +
  • +
    + +
    +
  • - -
      +
    • +
      +
      + {{ file.name }} + + {{message.header}}: {{message.message}} + + "{{maxFileSize}}" + +
      -
    • -
      - - -
      -
    • + + + + -
    • + + +
+ -
-
- {{ file.name }} - - {{message.header}}: {{message.message}} - - "{{maxFileSize}}" - -
+ +
  • +
    {{file.name}} {{file.uploadProgress + '%'}}
    +
    + +
    +
  • - - - - +
  • +
    {{ file.name }}
    +
  • - - -
    - - -
  • -
    {{currentFile.name}} {{currentFile.uploadProgress + '%'}}
    -
    - -
    -
  • - -
  • -
    {{ file.name }}
    -
  • - - - + +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html b/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html index 1625552955..b8287eb6fd 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/assigndomain.html @@ -83,6 +83,13 @@ button-style="info"> + + +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.assigndomain.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.assigndomain.controller.js index daa3ed21cb..2cec5fb17a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.assigndomain.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.assigndomain.controller.js @@ -1,11 +1,12 @@ (function () { "use strict"; - function AssignDomainController($scope, localizationService, languageResource, contentResource, navigationService, notificationsService) { + function AssignDomainController($scope, localizationService, languageResource, contentResource, navigationService, notificationsService, $location) { var vm = this; vm.closeDialog = closeDialog; vm.addDomain = addDomain; + vm.addCurrentDomain = addCurrentDomain; vm.removeDomain = removeDomain; vm.save = save; vm.languages = []; @@ -82,6 +83,18 @@ }); } + function addCurrentDomain() { + var domainToAdd = $location.host(); + var port = $location.port(); + if (port != 80 && port != 443) { + domainToAdd += ":" + port; + } + vm.domains.push({ + name: domainToAdd, + lang: vm.defaultLanguage + }); + } + function removeDomain(index) { vm.domains.splice(index, 1); } diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js index e08451f261..b7c07f48a7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js @@ -48,7 +48,7 @@ function startUpDynamicContentController($q, $timeout, $scope, dashboardResource { title: "Documentation", description: "Find the answers to your Umbraco questions", - url: "https://our.umbraco.com/documentation/?utm_source=core&utm_medium=dashboard&utm_content=text&utm_campaign=documentation/" + url: "https://docs.umbraco.com/?utm_source=core&utm_medium=dashboard&utm_content=text&utm_campaign=documentation/" }, { title: "Community", diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.html index 29a9b2efdd..63ef3d9279 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/examinemanagement.html @@ -321,8 +321,8 @@ {{ ::result.values[field] | umbCmsJoinArray:', ' }} - @@ -370,7 +370,7 @@
    - + diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/healthcheck.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/healthcheck.html index 0b60cd2433..15ac3111f6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/healthcheck.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/healthcheck.html @@ -7,13 +7,14 @@

    The health checker evaluates various areas of your site for best practice settings, configuration, potential problems, etc. You can easily fix problems by pressing a button. - You can add your own health checks, have a look at the documentation for more information about custom health checks.

    + You can add your own health checks, have a look at the documentation for more information about custom health checks.

    diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardintro.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardintro.html index b33444177a..93fe6c0cbd 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardintro.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardintro.html @@ -11,7 +11,7 @@
    • - Read more about working with the items in Settings in the Documentation section of Our Umbraco + Read more about working with the items in Settings in the Umbraco Documentation.
    • Ask a question in the Community Forum diff --git a/src/Umbraco.Web.UI.Client/src/views/logViewer/overview.html b/src/Umbraco.Web.UI.Client/src/views/logViewer/overview.html index eb018db541..b312d0b789 100644 --- a/src/Umbraco.Web.UI.Client/src/views/logViewer/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/logViewer/overview.html @@ -83,12 +83,13 @@ - + + on-close="vm.dateRangeChange(selectedDates, dateStr, instance)" + label="timePeriod"> diff --git a/src/Umbraco.Web.UI.Client/src/views/logViewer/search.html b/src/Umbraco.Web.UI.Client/src/views/logViewer/search.html index f506ab11ae..2b79474355 100644 --- a/src/Umbraco.Web.UI.Client/src/views/logViewer/search.html +++ b/src/Umbraco.Web.UI.Client/src/views/logViewer/search.html @@ -203,7 +203,12 @@ {{val.Value}} - {{val.Value}} + + + {{val.Value}} + +
      {{val | json}}
      +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/media/delete.html b/src/Umbraco.Web.UI.Client/src/views/media/delete.html index 894cf5ef77..3296b01749 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/delete.html +++ b/src/Umbraco.Web.UI.Client/src/views/media/delete.html @@ -14,7 +14,14 @@ Are you sure you want to delete{{currentNode.name}}?

    - + +
    {{warningText}} diff --git a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html index 13e3809b0b..248e926c98 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html +++ b/src/Umbraco.Web.UI.Client/src/views/packages/views/installed.html @@ -52,8 +52,8 @@ -

    You don’t have any packages installed.

    -

    You don’t have any packages installed. Either install a local package by selecting it from your machine, or browse through available packages using the "Packages" icon in the top right of your screen.

    +

    No packages have been installed.

    +

    Browse through the available packages using the 'Packages' icon in the top right of your screen.

    diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.area.overlay.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.area.overlay.html index a4ba0db72e..650ca29629 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.area.overlay.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.area.overlay.html @@ -29,7 +29,7 @@ * - The alias will be printed by GetBlockGridHTML(), use the alias to target the Element representing this area. Ex. .umb-block-grid__area[data-area-alias="MyAreaAlias"] { ... } + When using GetBlockGridHTML() to render the Block Grid, the alias will be rendered in the markup as a 'data-area-alias' attribute. Use the alias attribute to target the element for the area. Example. .umb-block-grid__area[data-area-alias="MyAreaAlias"] { ... }
    @@ -48,7 +48,7 @@
    - Overwrite the label on the create button of this Area. + Override the label text for adding a new Block to this Area, Example: 'Add Widget'
    diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.controller.js index 85c31dfc6b..f24520dda6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.controller.js @@ -41,9 +41,8 @@ function BlockConfigurationController($scope, $element, $http, elementTypeResource, overlayService, localizationService, editorService, eventsService, udiService, dataTypeResource, umbRequestHelper) { var unsubscribe = []; - + const vm = this; - vm.openBlock = null; vm.showSampleDataCTA = false; @@ -57,7 +56,6 @@ if (blockGroupModel.value == null) { blockGroupModel.value = []; } - vm.blockGroups = blockGroupModel.value; if (!$scope.model.value) { @@ -89,7 +87,6 @@ } } } - unsubscribe.push(eventsService.on("editors.documentType.saved", updateUsedElementTypes)); function removeReferencesToElementTypeKey(contentElementTypeKey) { @@ -267,7 +264,7 @@ vm.openBlockOverlay = function (block, openAreas) { var elementType = vm.getElementTypeByKey(block.contentElementTypeKey); - + if (elementType) { localizationService.localize("blockEditor_blockConfigurationOverlayTitle", [elementType.name]).then(function (data) { @@ -359,7 +356,6 @@ }); } } - dataTypeResource.getAll().then(function(dataTypes) { if (dataTypes.filter(x => x.alias === "Umbraco.BlockGrid").length === 0) { vm.showSampleDataCTA = true; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.overlay.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.overlay.html index cecc3caab9..d042fbd6e8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.overlay.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/blockgrid.blockconfiguration.overlay.html @@ -211,7 +211,7 @@
    - To enable nesting of blocks within this block, define one or more areas for blocks to be nested within. Areas follow their own layout witch is defined by the Area Layout Columns. Each Areas column and row span can be adjusted by using the scale-handler in the bottom right. + To enable the nesting of blocks within this block, define one or more areas. Areas follow the layout defined by their own grid column configuration. The 'column span' and 'row span' for each area can be adjusted by using the scale-handler box in the bottom right hand corner of the selected area.
    diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-allowance-editor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-allowance-editor.html index 55ceb941bb..f6d22780d7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-allowance-editor.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/prevalue/umb-block-grid-area-allowance-editor.html @@ -57,7 +57,7 @@
    - When empty all Blocks allowed for Areas can be created. + By default, all block types are allowed in an Area, Use this option to allow only selected types.
    diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout-flexbox.css b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout-flexbox.css index be009846f9..3f921c0470 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout-flexbox.css +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout-flexbox.css @@ -22,6 +22,9 @@ } .umb-block-grid__area { position: relative; + height: 100%; + display: flex; + flex-direction: column; --umb-block-grid__area-calc: calc(var(--umb-block-grid--area-column-span) / var(--umb-block-grid--area-grid-columns, 1)); width: calc(var(--umb-block-grid__area-calc) * 100% - (1 - var(--umb-block-grid__area-calc)) * var(--umb-block-grid--areas-column-gap, 0px)); } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout.css b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout.css index 60e0c4e96a..8a4f567cac 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout.css +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbraco-blockgridlayout.css @@ -28,8 +28,11 @@ } .umb-block-grid__area { position: relative; + height: 100%; + display: flex; + flex-direction: column; /* For small devices we scale columnSpan by three, to make everything bigger than 1/3 take full width: */ - grid-column-end: span min(calc(var(--umb-block-grid--area-column-span, 1) * 3), var(--umb-block-grid--grid-columns)); + grid-column-end: span min(calc(var(--umb-block-grid--area-column-span, 1) * 3), var(--umb-block-grid--area-grid-columns)); grid-row: span var(--umb-block-grid--area-row-span, 1); } @@ -38,6 +41,6 @@ grid-column-end: span min(var(--umb-block-grid--item-column-span, 1), var(--umb-block-grid--grid-columns)); } .umb-block-grid__area { - grid-column-end: span var(--umb-block-grid--area-column-span, 1); + grid-column-end: span min(var(--umb-block-grid--area-column-span, 1), var(--umb-block-grid--area-grid-columns)); } } \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js index c81df25c76..c69fc60a82 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/multicolorpicker.controller.js @@ -1,7 +1,7 @@ -angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiColorPickerController", +angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiColorPickerController", function ($scope, angularHelper, $element, eventsService) { - var vm = this; + const vm = this; vm.add = add; vm.remove = remove; @@ -15,10 +15,10 @@ vm.labelEnabled = false; vm.editItem = null; - //NOTE: We need to make each color an object, not just a string because you cannot 2-way bind to a primitive. - var defaultColor = "000000"; - var defaultLabel = null; - + // NOTE: We need to make each color an object, not just a string because you cannot 2-way bind to a primitive. + const defaultColor = "000000"; + const defaultLabel = null; + $scope.newColor = defaultColor; $scope.newLabel = defaultLabel; $scope.hasError = false; @@ -48,15 +48,20 @@ } }); } + var evts = []; evts.push(eventsService.on("toggleValue", function (e, args) { - vm.labelEnabled = args.value; + if (args.inputId === "useLabel") { + vm.labelEnabled = args.value; + } })); + $scope.$on('$destroy', function () { for (var e in evts) { eventsService.unsubscribe(evts[e]); } }); + if (!Utilities.isArray($scope.model.value)) { //make an array from the dictionary var items = []; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index c36f0cb891..bdbfd926f7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -143,26 +143,29 @@ function dateTimePickerController($scope, angularHelper, dateHelper, validationM } function updateModelValue(momentDate) { - if ($scope.hasDatetimePickerValue) { - if ($scope.model.config.pickTime) { - //check if we are supposed to offset the time - if ($scope.model.value && Object.toBoolean($scope.model.config.offsetTime) && Umbraco.Sys.ServerVariables.application.serverTimeOffset !== undefined) { - $scope.model.value = dateHelper.convertToServerStringTime(momentDate, Umbraco.Sys.ServerVariables.application.serverTimeOffset); - $scope.serverTime = dateHelper.convertToServerStringTime(momentDate, Umbraco.Sys.ServerVariables.application.serverTimeOffset, "YYYY-MM-DD HH:mm:ss Z"); - } - else { - $scope.model.value = momentDate.format("YYYY-MM-DD HH:mm:ss"); - } - } - else { - $scope.model.value = momentDate.format("YYYY-MM-DD"); - } + var curMoment = moment($scope.model.value); + if ($scope.hasDatetimePickerValue) { + if ($scope.model.config.pickTime) { + //check if we are supposed to offset the time + if ($scope.model.value && Object.toBoolean($scope.model.config.offsetTime) && Umbraco.Sys.ServerVariables.application.serverTimeOffset !== undefined) { + $scope.model.value = dateHelper.convertToServerStringTime(momentDate, Umbraco.Sys.ServerVariables.application.serverTimeOffset); + $scope.serverTime = dateHelper.convertToServerStringTime(momentDate, Umbraco.Sys.ServerVariables.application.serverTimeOffset, "YYYY-MM-DD HH:mm:ss Z"); + } + else { + $scope.model.value = momentDate.format("YYYY-MM-DD HH:mm:ss"); + } } else { - $scope.model.value = null; + $scope.model.value = momentDate.format("YYYY-MM-DD"); } + } + else { + $scope.model.value = null; + } + if (!curMoment.isSame(momentDate)) { setDirty(); + } } function setDirty() { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 9745fd52b1..45614f6d2c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -682,9 +682,18 @@ function listViewController($scope, $interpolate, $routeParams, $injector, $time } if (e.nameExp) { - var newValue = e.nameExp({ value }); - if (newValue && (newValue = newValue.trim())) { - value = newValue; + if (/{{.*\s*\w+\s*\|\s*\w+\s*.*}}/.test(e.nameTemplate)) { //check whether the name template has a filter + value = { + value, + expression: e.nameExp + }; + } + else { + var newValue = e.nameExp({ value }); + + if (newValue && (newValue = newValue.trim())) { + value = newValue; + } } } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker3/umbMediaPicker3PropertyEditor.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker3/umbMediaPicker3PropertyEditor.component.js index e052e7c1c6..0e61b4b5fa 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker3/umbMediaPicker3PropertyEditor.component.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker3/umbMediaPicker3PropertyEditor.component.js @@ -302,6 +302,8 @@ if (onSuccess) { onSuccess(); } + + setDirty(); }, close: function () { editorService.close(); @@ -350,12 +352,15 @@ if (index !== -1) { vm.model.value.splice(index, 1); } + + setDirty(); } function deleteAllMedias() { if (!vm.allowRemoveMedia) return; vm.model.value = []; + setDirty(); } function setActiveMedia(mediaEntryOrNull) { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/codeeditor.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/codeeditor.html index 11d77d4dd4..2bccd039db 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/codeeditor.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/codeeditor.html @@ -25,6 +25,7 @@ type="button" button-style="link" label-key="general_close" + shortcut="esc" action="vm.close()"> -
    \ No newline at end of file +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js index f9d48d95e9..1df0827ace 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/user.controller.js @@ -109,22 +109,15 @@ }); }); } - + + /** + * @ngdoc function + * @function + * + * @deprecated + */ function getLocalDate(date, culture, format) { - if (date) { - var dateVal; - var serverOffset = Umbraco.Sys.ServerVariables.application.serverTimeOffset; - var localOffset = new Date().getTimezoneOffset(); - var serverTimeNeedsOffsetting = (-serverOffset !== localOffset); - - if (serverTimeNeedsOffsetting) { - dateVal = dateHelper.convertToLocalMomentTime(date, serverOffset); - } else { - dateVal = moment(date, "YYYY-MM-DD HH:mm:ss"); - } - - return dateVal.locale(culture).format(format); - } + return dateHelper.getLocaleDate(date, culture, format); } function toggleChangePassword() { @@ -571,11 +564,11 @@ userService.getCurrentUser().then(function (currentUser) { currentLoggedInUser = currentUser; - user.formattedLastLogin = getLocalDate(user.lastLoginDate, currentUser.locale, "LLL"); - user.formattedLastLockoutDate = getLocalDate(user.lastLockoutDate, currentUser.locale, "LLL"); - user.formattedCreateDate = getLocalDate(user.createDate, currentUser.locale, "LLL"); - user.formattedUpdateDate = getLocalDate(user.updateDate, currentUser.locale, "LLL"); - user.formattedLastPasswordChangeDate = getLocalDate(user.lastPasswordChangeDate, currentUser.locale, "LLL"); + user.formattedLastLogin = dateHelper.getLocalDate(user.lastLoginDate, currentUser.locale, "LLL"); + user.formattedLastLockoutDate = dateHelper.getLocalDate(user.lastLockoutDate, currentUser.locale, "LLL"); + user.formattedCreateDate = dateHelper.getLocalDate(user.createDate, currentUser.locale, "LLL"); + user.formattedUpdateDate = dateHelper.getLocalDate(user.updateDate, currentUser.locale, "LLL"); + user.formattedLastPasswordChangeDate = dateHelper.getLocalDate(user.lastPasswordChangeDate, currentUser.locale, "LLL"); }); } diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js index 79edd32319..99cbe31f66 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.controller.js @@ -187,7 +187,23 @@ } function initUserStateSelections() { - initUsersOptionsFilterSelections(vm.userStatesFilter, vm.usersOptions.userStates, "key"); + if (!vm.usersOptions.userStates && vm.userStatesFilter) { + // create a new empty userStates array + vm.usersOptions.userStates = []; + + // add selected userStatesFilters to usersOptions.userStates array + for (var i = 0; i < vm.userStatesFilter.length; i++) { + if (vm.userStatesFilter[i].selected) { + vm.usersOptions.userStates.push(vm.userStatesFilter[i].key); + } + } + + // If there are any selected userStates, update location and change pagenumber + if (vm.usersOptions.userStates.length > 0) { + updateLocation("userStates", vm.usersOptions.userStates.join(",")); + changePageNumber(1); + } + } } function initUserGroupSelections() { diff --git a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html index 9afd0b0823..acf86263e3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/views/users/users.html @@ -309,9 +309,9 @@

    -

    +

    Create user -

    +

    Create new users to give them access to Umbraco. When a new user is created a password will be generated that you can share with the user.

    @@ -319,7 +319,7 @@
    - Required @@ -329,7 +329,7 @@ - Required @@ -339,7 +339,7 @@ - Required diff --git a/src/Umbraco.Web.Website/Controllers/RenderNoContentController.cs b/src/Umbraco.Web.Website/Controllers/RenderNoContentController.cs index 9704549e4e..06b6d4a818 100644 --- a/src/Umbraco.Web.Website/Controllers/RenderNoContentController.cs +++ b/src/Umbraco.Web.Website/Controllers/RenderNoContentController.cs @@ -2,11 +2,11 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Cms.Web.Website.Models; using Umbraco.Extensions; diff --git a/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs b/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs index c195b52409..2ed0babf3d 100644 --- a/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs +++ b/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Security; @@ -8,7 +9,6 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Web.Common.ActionsResults; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Cms.Web.Common.Filters; using Umbraco.Cms.Web.Common.Models; using Umbraco.Cms.Web.Common.Security; diff --git a/src/Umbraco.Web.Website/Middleware/BasicAuthenticationMiddleware.cs b/src/Umbraco.Web.Website/Middleware/BasicAuthenticationMiddleware.cs index e2f4b2b09a..2fe02ddccd 100644 --- a/src/Umbraco.Web.Website/Middleware/BasicAuthenticationMiddleware.cs +++ b/src/Umbraco.Web.Website/Middleware/BasicAuthenticationMiddleware.cs @@ -7,10 +7,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Web.BackOffice.Security; -using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Web.Common.Middleware; diff --git a/src/Umbraco.Web.Website/Routing/FrontEndRoutes.cs b/src/Umbraco.Web.Website/Routing/FrontEndRoutes.cs index 6ebf77727a..8c0e36a40f 100644 --- a/src/Umbraco.Web.Website/Routing/FrontEndRoutes.cs +++ b/src/Umbraco.Web.Website/Routing/FrontEndRoutes.cs @@ -41,13 +41,22 @@ public sealed class FrontEndRoutes : IAreaRoutes /// public void CreateRoutes(IEndpointRouteBuilder endpoints) { - if (_runtimeState.Level != RuntimeLevel.Run) + switch (_runtimeState.Level) { - return; + case RuntimeLevel.Install: + case RuntimeLevel.Upgrade: + case RuntimeLevel.Run: + + AutoRouteSurfaceControllers(endpoints); + AutoRouteFrontEndApiControllers(endpoints); + break; + case RuntimeLevel.BootFailed: + case RuntimeLevel.Unknown: + case RuntimeLevel.Boot: + break; } - AutoRouteSurfaceControllers(endpoints); - AutoRouteFrontEndApiControllers(endpoints); + } /// diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs index c1cc360500..5617797ec7 100644 --- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs +++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs @@ -117,9 +117,20 @@ public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer public override async ValueTask TransformAsync( HttpContext httpContext, RouteValueDictionary values) { - // If we aren't running, then we have nothing to route - if (_runtime.Level != RuntimeLevel.Run) + // If we aren't running, then we have nothing to route. We allow the frontend to continue while in upgrade mode. + if (_runtime.Level != RuntimeLevel.Run && _runtime.Level != RuntimeLevel.Upgrade) { + if (_runtime.Level == RuntimeLevel.Install) + { + return new RouteValueDictionary() + { + //TODO figure out constants + [ControllerToken] = "Install", + [ActionToken] = "Index", + [AreaToken] = Constants.Web.Mvc.InstallArea, + }; + } + return null!; } @@ -184,6 +195,7 @@ public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer // our default 404 page but we cannot return route values now because // it's possible that a developer is handling dynamic routes too. // Our 404 page will be handled with the NotFoundSelectorPolicy + return null!; } diff --git a/tests/Umbraco.Tests.AcceptanceTest/README.md b/tests/Umbraco.Tests.AcceptanceTest/README.md index 0823a31246..66586cd0cc 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/README.md +++ b/tests/Umbraco.Tests.AcceptanceTest/README.md @@ -1,5 +1,7 @@ # Umbraco Acceptance Tests +You can watch a video following these instructions [here](https://www.youtube.com/watch?v=N4hBKB0U-d8) and a longer UmbraCollab recording [here](https://www.youtube.com/watch?v=hvoI28s_fDI). Make sure to use the latest recommended contribution branch rather than v10 that's mentioned in the video. Alternatively, follow along the instructions below. + ### Prerequisites - NodeJS 16+ - A running installed Umbraco on url: [https://localhost:44331](https://localhost:44331) (Default development port) @@ -20,6 +22,16 @@ There are two npm scripts that can be used to execute the test: In case of errors it is recommended to use `await page.pause()` so you can step through your test. +### Executing single tests + +If you wish to run a single test, which may be helpful when writing tests you can use the following command. As before, you need to run these tests in the 'tests/Umbraco.Tests.AcceptanceTest' folder. + + npx playwright test + +For example to run the Login Test, + + npx playwright test tests/DefaultConfig/Login/Login.spec.ts + ### Environment Configuration The environment configuration is begin setup by the npm installation script. @@ -33,3 +45,7 @@ UMBRACO_USER_PASSWORD=password for superadmin URL=https://localhost:44331 ``` You can change this if you like or run the config script to reset the values, type "npm run config" in your terminal. + +### Documentation + +For further documentation on Playwright, see the [Playwright documentation](https://playwright.dev/docs/intro). \ No newline at end of file diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts index 8fa3c1337a..60d6c97f20 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/content.spec.ts @@ -14,7 +14,18 @@ test.describe('Content tests', () => { await umbracoApi.report.report(testInfo); await umbracoApi.login(); }); - + + const rootDocTypeName = "Test document type"; + const childDocTypeName = "Child test document type"; + const firstRootNodeName = "1) Home"; + const secondRootNodeName = "2) Home"; + const firstChildNodeName = "1) Child"; + const secondChildNodeName = "2) Child"; + const saveNode = "saveNew"; + const defaultContentAlias = "alias"; + const homeNodeName = "Home"; + const aliasText = "text"; + async function createSimpleMacro(name, umbracoApi: ApiHelpers){ const insertMacro = new PartialViewMacroBuilder() .withName(name) @@ -33,11 +44,6 @@ test.describe('Content tests', () => { } test('Copy content', async ({ page, umbracoApi, umbracoUi }) => { - const rootDocTypeName = "Test document type"; - const childDocTypeName = "Child test document type"; - const firstRootNodeName = "1) Home"; - const childNodeName = "1) Child"; - const secondRootNodeName = "2) Home"; await umbracoApi.content.deleteAllContent(); await umbracoApi.documentTypes.ensureNameNotExists(rootDocTypeName); @@ -57,10 +63,9 @@ test.describe('Content tests', () => { const createdRootDocType = await umbracoApi.documentTypes.save(rootDocType); - // TODO: Make some constants for actions. const rootContentNode = new ContentBuilder() .withContentTypeAlias(createdRootDocType.alias) - .withAction("saveNew") + .withAction(saveNode) .addVariant() .withName(firstRootNodeName) .withSave(true) // We should probably just default to true... @@ -71,7 +76,7 @@ test.describe('Content tests', () => { const secondRootNode = new ContentBuilder() .withContentTypeAlias(createdRootDocType.alias) - .withAction("saveNew") + .withAction(saveNode) .addVariant() .withName(secondRootNodeName) .withSave(true) @@ -82,10 +87,10 @@ test.describe('Content tests', () => { const childContentNode = new ContentBuilder() .withContentTypeAlias(createdChildDocType.alias) - .withAction("saveNew") + .withAction(saveNode) .withParent(savedRootNode.id) .addVariant() - .withName(childNodeName) + .withName(firstChildNodeName) .withSave(true) .done() .build(); @@ -94,7 +99,7 @@ test.describe('Content tests', () => { await umbracoUi.refreshContentTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [firstRootNodeName, childNodeName]), {button: "right", force: true}) + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [firstRootNodeName, firstChildNodeName]), {button: "right", force: true}) await umbracoUi.clickElement(umbracoUi.getContextMenuAction(ConstantHelper.actions.copy)) await page.locator('.umb-pane [data-element="tree-item-' + secondRootNodeName + '"]').click(); await page.locator('.umb-dialog-footer > .btn-primary').click(); @@ -105,11 +110,6 @@ test.describe('Content tests', () => { }); test('Move content', async ({ page, umbracoApi, umbracoUi }) => { - const rootDocTypeName = "Test document type"; - const childDocTypeName = "Child test document type"; - const firstRootNodeName = "1) Home"; - const childNodeName = "1) Child"; - const secondRootNodeName = "2) Home"; await umbracoApi.content.deleteAllContent(); await umbracoApi.documentTypes.ensureNameNotExists(rootDocTypeName); @@ -131,7 +131,7 @@ test.describe('Content tests', () => { const rootContentNode = new ContentBuilder() .withContentTypeAlias(createdRootDocType.alias) - .withAction("saveNew") + .withAction(saveNode) .addVariant() .withName(firstRootNodeName) .withSave(true) // We should probably just default to true... @@ -142,7 +142,7 @@ test.describe('Content tests', () => { const secondRootNode = new ContentBuilder() .withContentTypeAlias(createdRootDocType.alias) - .withAction("saveNew") + .withAction(saveNode) .addVariant() .withName(secondRootNodeName) .withSave(true) @@ -153,10 +153,10 @@ test.describe('Content tests', () => { const childContentNode = new ContentBuilder() .withContentTypeAlias(createdChildDocType.alias) - .withAction("saveNew") + .withAction(saveNode) .withParent(savedRootNode.id) .addVariant() - .withName(childNodeName) + .withName(firstChildNodeName) .withSave(true) .done() .build(); @@ -165,7 +165,7 @@ test.describe('Content tests', () => { await umbracoUi.refreshContentTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [firstRootNodeName, childNodeName]), { button: "right", force: true }); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [firstRootNodeName, firstChildNodeName]), { button: "right", force: true }); await umbracoUi.clickElement(umbracoUi.getContextMenuAction(ConstantHelper.actions.move)) await page.locator('.umb-pane [data-element="tree-item-' + secondRootNodeName + '"]').click() await page.locator('[key="actions_move"]').click(); @@ -177,11 +177,6 @@ test.describe('Content tests', () => { }); test('Sort content', async ({ page, umbracoApi, umbracoUi }) => { - const rootDocTypeName = "Test document type"; - const childDocTypeName = "Child test document type"; - const rootNodeName = "1) Home"; - const firstChildNodeName = "1) Child"; - const secondChildNodeName = "2) Child"; await umbracoApi.content.deleteAllContent(); await umbracoApi.documentTypes.ensureNameNotExists(rootDocTypeName); @@ -201,9 +196,9 @@ test.describe('Content tests', () => { const rootContentNode = new ContentBuilder() .withContentTypeAlias(createdRootDocType.alias) - .withAction("saveNew") + .withAction(saveNode) .addVariant() - .withName(rootNodeName) + .withName(firstRootNodeName) .withSave(true) .done() .build(); @@ -212,7 +207,7 @@ test.describe('Content tests', () => { // Add an item under root node const firstChildContentNode = new ContentBuilder() .withContentTypeAlias(createdChildDocType.alias) - .withAction("saveNew") + .withAction(saveNode) .withParent(createdRootContentNode.id) .addVariant() .withName(firstChildNodeName) @@ -224,7 +219,7 @@ test.describe('Content tests', () => { // Add a second item under root node const secondChildContentNode = new ContentBuilder() .withContentTypeAlias(createdChildDocType.alias) - .withAction("saveNew") + .withAction(saveNode) .withParent(createdRootContentNode.id) .addVariant() .withName(secondChildNodeName) @@ -234,7 +229,7 @@ test.describe('Content tests', () => { await umbracoApi.content.save(secondChildContentNode); await umbracoUi.refreshContentTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [rootNodeName]), { button: "right", force: true }); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [firstRootNodeName]), { button: "right", force: true }); await umbracoUi.clickElement(umbracoUi.getContextMenuAction(ConstantHelper.actions.sort)); // Drag'n'drop second child to be the first one. await page.locator('.ui-sortable-handle >> text=' + secondChildNodeName).hover(); @@ -254,9 +249,8 @@ test.describe('Content tests', () => { }); test('Rollback content', async ({ page, umbracoApi, umbracoUi }) => { - const rootDocTypeName = "Test document type"; + const initialNodeName = "Home node"; - const newNodeName = "Home"; await umbracoApi.content.deleteAllContent(); await umbracoApi.documentTypes.ensureNameNotExists(rootDocTypeName); @@ -278,7 +272,7 @@ test.describe('Content tests', () => { await umbracoApi.content.save(rootContentNode); await umbracoUi.refreshContentTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [initialNodeName])); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [initialNodeName])); const header = await page.locator('#headerName') // Sadly playwright doesn't have a clear method for inputs :( @@ -286,7 +280,7 @@ test.describe('Content tests', () => { await header.click({ clickCount: 3 }) await page.keyboard.press('Backspace'); - await umbracoUi.setEditorHeaderName(newNodeName); + await umbracoUi.setEditorHeaderName(homeNodeName); await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save)); await umbracoUi.isSuccessNotificationVisible(); await page.locator('span:has-text("×")').click(); @@ -302,13 +296,12 @@ test.describe('Content tests', () => { await umbracoUi.refreshContentTree(); await expect(page.locator('.umb-badge >> text=Save')).toHaveCount(2); await expect(page.locator('.umb-badge >> text=RollBack')).toBeVisible(); - const node = await umbracoUi.getTreeItem("content", [initialNodeName]) + const node = await umbracoUi.getTreeItem(ConstantHelper.sections.content, [initialNodeName]) await expect(node).toBeVisible(); }); test('View audit trail', async ({ page, umbracoApi, umbracoUi }) => { - const rootDocTypeName = "Test document type"; - const nodeName = "Home"; + const labelName = "Name"; await umbracoApi.documentTypes.ensureNameNotExists(rootDocTypeName); @@ -327,9 +320,9 @@ test.describe('Content tests', () => { const generatedRootDocType = await umbracoApi.documentTypes.save(rootDocType) const rootContentNode = new ContentBuilder() - .withContentTypeAlias(generatedRootDocType["alias"]) + .withContentTypeAlias(generatedRootDocType[defaultContentAlias]) .addVariant() - .withName(nodeName) + .withName(homeNodeName) .withSave(true) .done() .build(); @@ -340,7 +333,7 @@ test.describe('Content tests', () => { await umbracoUi.refreshContentTree(); // Access node - await umbracoUi.clickElement(umbracoUi.getTreeItem('content', [nodeName])); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [homeNodeName])); // Navigate to Info app await page.locator(ConstantHelper.contentApps.info).click(); @@ -353,8 +346,7 @@ test.describe('Content tests', () => { }); test('Save draft', async ({ page, umbracoApi, umbracoUi }) => { - const rootDocTypeName = "Test document type"; - const nodeName = "Home"; + const expected = "Unpublished"; await umbracoApi.content.deleteAllContent(); @@ -368,10 +360,10 @@ test.describe('Content tests', () => { const generatedRootDocType = await umbracoApi.documentTypes.save(rootDocType); const rootContentNode = new ContentBuilder() - .withContentTypeAlias(generatedRootDocType["alias"]) - .withAction("saveNew") + .withContentTypeAlias(generatedRootDocType[defaultContentAlias]) + .withAction(saveNode) .addVariant() - .withName(nodeName) + .withName(homeNodeName) .withSave(true) .done() .build(); @@ -382,7 +374,7 @@ test.describe('Content tests', () => { await umbracoUi.refreshContentTree(); // Access node - await umbracoUi.clickElement(umbracoUi.getTreeItem('content', [nodeName])); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [homeNodeName])); // Assert await expect(page.locator('[data-element="node-info-status"]').locator('.umb-badge')).toContainText(expected); @@ -392,8 +384,8 @@ test.describe('Content tests', () => { }); test('Preview draft', async ({ page, umbracoApi, umbracoUi }) => { - const rootDocTypeName = "Test document type"; - const nodeName = "Home"; + + await umbracoApi.content.deleteAllContent(); await umbracoApi.documentTypes.ensureNameNotExists(rootDocTypeName); @@ -406,10 +398,10 @@ test.describe('Content tests', () => { const generatedRootDocType = await umbracoApi.documentTypes.save(rootDocType); const rootContentNode = new ContentBuilder() - .withContentTypeAlias(generatedRootDocType["alias"]) - .withAction("saveNew") + .withContentTypeAlias(generatedRootDocType[defaultContentAlias]) + .withAction(saveNode) .addVariant() - .withName(nodeName) + .withName(homeNodeName) .withSave(true) .done() .build(); @@ -420,7 +412,7 @@ test.describe('Content tests', () => { await umbracoUi.refreshContentTree(); // Access node - await umbracoUi.clickElement(umbracoUi.getTreeItem('content', [nodeName])); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [homeNodeName])); // Assert await expect(page.locator('[alias="preview"]')).toBeVisible(); @@ -432,8 +424,7 @@ test.describe('Content tests', () => { }); test('Publish draft', async ({ page, umbracoApi, umbracoUi }) => { - const rootDocTypeName = "Test document type"; - const nodeName = "Home"; + const expected = "Published"; await umbracoApi.content.deleteAllContent(); @@ -447,9 +438,9 @@ test.describe('Content tests', () => { const generatedRootDocType = await umbracoApi.documentTypes.save(rootDocType); const rootContentNode = new ContentBuilder() - .withContentTypeAlias(generatedRootDocType["alias"]) + .withContentTypeAlias(generatedRootDocType[defaultContentAlias]) .addVariant() - .withName(nodeName) + .withName(homeNodeName) .withSave(true) .done() .build(); @@ -460,7 +451,7 @@ test.describe('Content tests', () => { await umbracoUi.refreshContentTree(); // Access node - await umbracoUi.clickElement(umbracoUi.getTreeItem('content', [nodeName])); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [homeNodeName])); // Assert await expect(page.locator('[data-element="node-info-status"]').locator('.umb-badge')).toContainText(expected); @@ -475,6 +466,7 @@ test.describe('Content tests', () => { const pickedDocTypeName = 'Picked content document type'; const pickedDocTypeAlias = AliasHelper.toAlias(pickedDocTypeName); + await umbracoApi.content.deleteAllContent(); await umbracoApi.documentTypes.ensureNameNotExists(pickerDocTypeName); await umbracoApi.templates.ensureNameNotExists(pickerDocTypeName); @@ -487,21 +479,21 @@ test.describe('Content tests', () => { .withAllowAsRoot(true) .addGroup() .addTextBoxProperty() - .withAlias('text') + .withAlias(aliasText) .done() .done() .build(); const generatedType = await umbracoApi.documentTypes.save(pickedDocType) const pickedContentNode = new ContentBuilder() - .withContentTypeAlias(generatedType["alias"]) + .withContentTypeAlias(generatedType[defaultContentAlias]) .withAction("publishNew") .addVariant() .withName('Content to pick') .withSave(true) .withPublish(true) .addProperty() - .withAlias('text') + .withAlias(aliasText) .withValue('Acceptance test') .done() .withSave(true) @@ -590,7 +582,7 @@ test.describe('Content tests', () => { .withDefaultTemplate(alias) .addGroup() .addRichTextProperty() - .withAlias('text') + .withAlias(aliasText) .done() .done() .build(); @@ -598,8 +590,8 @@ test.describe('Content tests', () => { const generatedDocType = await umbracoApi.documentTypes.save(docType) // Might as wel initally create the content here, the less GUI work during the test the better const contentNode = new ContentBuilder() - .withContentTypeAlias(generatedDocType["alias"]) - .withAction('saveNew') + .withContentTypeAlias(generatedDocType[defaultContentAlias]) + .withAction(saveNode) .addVariant() .withName(viewMacroName) .withSave(true) @@ -624,7 +616,7 @@ test.describe('Content tests', () => { // Enter content await umbracoUi.refreshContentTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [viewMacroName])); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [viewMacroName])); // Insert macro await page.locator('[title="Insert macro"]').click(); @@ -685,7 +677,7 @@ test.describe('Content tests', () => { const generatedDocType = await umbracoApi.documentTypes.save(docType); const contentNode = new ContentBuilder() - .withContentTypeAlias(generatedDocType["alias"]) + .withContentTypeAlias(generatedDocType[defaultContentAlias]) .addVariant() .withName(name) .withSave(true) @@ -707,7 +699,7 @@ test.describe('Content tests', () => { // Act // Enter content await umbracoUi.refreshContentTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem("content", [name])); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.content, [name])); // Click add await page.locator(':nth-child(2) > .preview-row > .preview-col > .preview-cell').click(); // Choose 1 column layout. diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/HelpPanel/systemInformation.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/HelpPanel/systemInformation.spec.ts index 9bdc85b37d..a202a60053 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/HelpPanel/systemInformation.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/HelpPanel/systemInformation.spec.ts @@ -25,7 +25,7 @@ test.describe('System Information', () => { test('Check System Info Displays', async ({page, umbracoApi, umbracoUi}) => { await openSystemInformation(page, umbracoUi); - await expect(page.locator('.table').locator('tr')).toHaveCount(14); + await expect(page.locator('.table').locator('tr')).toHaveCount(15); await expect(await page.locator("tr", {hasText: "Current Culture"})).toContainText(enCulture); await expect(await page.locator("tr", {hasText: "Current UI Culture"})).toContainText(enCulture); }); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Media/mediaFiles.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Media/mediaFiles.spec.ts index e6c7faa0e6..4805cc5af0 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Media/mediaFiles.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Media/mediaFiles.spec.ts @@ -1,4 +1,4 @@ -import {expect} from "@playwright/test"; +import {expect} from "@playwright/test"; import {ConstantHelper, test} from '@umbraco/playwright-testhelpers'; test.describe('media File Types', () => { @@ -147,7 +147,7 @@ test.describe('media File Types', () => { // Action await umbracoApi.media.createDefaultFolder(parentName); await umbracoUi.refreshMediaTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem('media', [parentName]), { + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.media, [parentName]), { button: "right", force: true }); @@ -173,7 +173,7 @@ test.describe('media File Types', () => { // Action await umbracoApi.media.createDefaultFolder(parentName); await umbracoUi.refreshMediaTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem('media', [parentName]), { + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.media, [parentName]), { button: "right", force: true }); @@ -200,7 +200,7 @@ test.describe('media File Types', () => { // Action await umbracoApi.media.createDefaultFolder(parentName); await umbracoUi.refreshMediaTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem('media', [parentName]), { + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.media, [parentName]), { button: "right", force: true }); @@ -227,7 +227,7 @@ test.describe('media File Types', () => { await umbracoApi.media.createDefaultFolder(parentName); await umbracoUi.refreshMediaTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem('media', [parentName]), { + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.media, [parentName]), { button: "right", force: true }); @@ -254,7 +254,7 @@ test.describe('media File Types', () => { // Action await umbracoApi.media.createDefaultFolder(parentName); await umbracoUi.refreshMediaTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem('media', [parentName]), { + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.media, [parentName]), { button: "right", force: true }); @@ -281,7 +281,7 @@ test.describe('media File Types', () => { // Action await umbracoApi.media.createDefaultFolder(parentName); await umbracoUi.refreshMediaTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem('media', [parentName]), { + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.media, [parentName]), { button: "right", force: true }); @@ -308,7 +308,7 @@ test.describe('media File Types', () => { // Action await umbracoApi.media.createDefaultFolder(parentName); await umbracoUi.refreshMediaTree(); - await umbracoUi.clickElement(umbracoUi.getTreeItem('media', [parentName]), { + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.media, [parentName]), { button: "right", force: true }); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Members/memberGroups.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Members/memberGroups.spec.ts index 11b2062d9d..e547036f05 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Members/memberGroups.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Members/memberGroups.spec.ts @@ -7,12 +7,13 @@ test.describe('Packages', () => { await umbracoApi.login(); }); + test('Create member group', async ({page, umbracoApi, umbracoUi}) => { const name = "Test Group"; await umbracoApi.memberGroups.ensureNameNotExists(name); await umbracoUi.goToSection(ConstantHelper.sections.member); - await umbracoUi.clickElement(umbracoUi.getTreeItem("member", ["Member Groups"]), { button: "right"}); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.member, ["Member Groups"]), { button: "right"}); await umbracoUi.clickElement(umbracoUi.getContextMenuAction(ConstantHelper.actions.create)); await umbracoUi.setEditorHeaderName(name) await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save)); @@ -23,4 +24,4 @@ test.describe('Packages', () => { // Clean up await umbracoApi.memberGroups.ensureNameNotExists(name); }); -}); \ No newline at end of file +}); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Members/members.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Members/members.spec.ts index 7fdd55d9f5..506f879614 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Members/members.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Members/members.spec.ts @@ -14,7 +14,7 @@ test.describe('Packages', () => { const passwordTimeout = 20000; await umbracoApi.members.ensureEmailNotExists(email); await umbracoUi.goToSection(ConstantHelper.sections.member); - await umbracoUi.clickElement(umbracoUi.getTreeItem("member", ["Members"]), { button: "right"}); + await umbracoUi.clickElement(umbracoUi.getTreeItem(ConstantHelper.sections.member, ["Members"]), { button: "right"}); await umbracoUi.clickElement(umbracoUi.getContextMenuAction(ConstantHelper.actions.create)); await umbracoUi.clickElement(page.locator('.menu-label').first()); diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/healthChecks.disabled.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/healthChecks.disabled.ts new file mode 100644 index 0000000000..5d38e41a38 --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/healthChecks.disabled.ts @@ -0,0 +1,26 @@ +import { test, ApiHelpers, UiHelpers, ConstantHelper } from '@umbraco/playwright-testhelpers'; +import { expect } from "@playwright/test"; + +test.describe('Health Checks', () => { + test.beforeEach(async ({ page, umbracoApi }) => { + await umbracoApi.login(); + }); + + test('Can check all groups', async ({ page, umbracoApi, umbracoUi }) => { + + await umbracoUi.goToSection("settings"); + + await page.locator('[data-element="tab-settingsHealthCheck"]').click(); + + await page.waitForSelector('.umb-panel-group__details-status-actions > umb-button > div > button'); + await page.click('.umb-panel-group__details-status-actions > umb-button > div > button'); + + await expect(await page.locator('text=Configuration 2 failed')).toBeVisible(); + await expect(await page.locator('text=Data Integrity 2 passed')).toBeVisible(); + await expect(await page.locator('text=Live Environment 1 failed')).toBeVisible(); + await expect(await page.locator('text=Permissions 4 passed')).toBeVisible(); + await expect(await page.locator('text=Security 2 passed 2 warning 5 failed')).toBeVisible(); + await expect(await page.locator('text=Services 1 failed')).toBeVisible(); + + }); +}); diff --git a/tests/Umbraco.Tests.Benchmarks/CollectionBenchmarks.cs b/tests/Umbraco.Tests.Benchmarks/CollectionBenchmarks.cs new file mode 100644 index 0000000000..7944e7bbe3 --- /dev/null +++ b/tests/Umbraco.Tests.Benchmarks/CollectionBenchmarks.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Linq; +using BenchmarkDotNet.Attributes; + +namespace Umbraco.Tests.Benchmarks +{ + [MemoryDiagnoser] + public class CollectionBenchmarks + { + private static readonly IEnumerable _enumerable = Enumerable.Range(0, 1000); + private static readonly int[] _array = _enumerable.ToArray(); + private static readonly List _list = _enumerable.ToList(); + + [Benchmark] + public int[] ToArray() + { + return _enumerable.ToArray(); + } + + [Benchmark] + public List ToList() + { + return _enumerable.ToList(); + } + + [Benchmark] + public void IterateArray() + { + foreach (int item in _array) + { + + } + } + + [Benchmark] + public void IterateList() + { + foreach (int item in _list) + { + } + } + + //BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19044.2006 (21H2) + //Intel Core i9-10885H CPU 2.40GHz, 1 CPU, 16 logical and 8 physical cores + //.NET SDK= 6.0.401 + // [Host] : .NET 6.0.9 (6.0.922.41905), X64 RyuJIT + // DefaultJob : .NET 6.0.9 (6.0.922.41905), X64 RyuJIT + // + // + //| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Allocated | + //|------------- |-----------:|---------:|---------:|-------:|-------:|----------:| + //| ToArray | 503.8 ns | 5.11 ns | 4.53 ns | 0.4807 | 0.0067 | 4,024 B | + //| ToList | 1,369.0 ns | 25.38 ns | 49.50 ns | 0.4845 | 0.0134 | 4,056 B | + //| IterateArray | 244.9 ns | 3.29 ns | 2.75 ns | - | - | - | + //| IterateList | 620.5 ns | 4.45 ns | 3.95 ns | - | - | - | + } +} diff --git a/tests/Umbraco.Tests.Benchmarks/StringFileExtensionBenchmark.cs b/tests/Umbraco.Tests.Benchmarks/StringFileExtensionBenchmark.cs new file mode 100644 index 0000000000..0c9af70db9 --- /dev/null +++ b/tests/Umbraco.Tests.Benchmarks/StringFileExtensionBenchmark.cs @@ -0,0 +1,80 @@ +using System; +using BenchmarkDotNet.Attributes; +using Umbraco.Tests.Benchmarks.Config; + +namespace Umbraco.Tests.Benchmarks +{ + [QuickRunWithMemoryDiagnoserConfig] + public class StringFileExtensionBenchmark + { + [Arguments("smallText.txt")] + [Arguments("aVeryLongTextThatContainsALotOfCharacters.txt")] + [Arguments("NotEvenAFile")] + [Benchmark(Baseline = true)] + public string StringStrip(string fileName) + { + // filenames cannot contain line breaks + if (fileName.Contains(Environment.NewLine) || fileName.Contains("\r") || fileName.Contains("\n")) + { + return fileName; + } + + var lastIndex = fileName.LastIndexOf('.'); + if (lastIndex > 0) + { + var ext = fileName.Substring(lastIndex); + + // file extensions cannot contain whitespace + if (ext.Contains(" ")) + { + return fileName; + } + + return string.Format("{0}", fileName.Substring(0, fileName.IndexOf(ext, StringComparison.Ordinal))); + } + + return fileName; + } + + [Arguments("smallText.txt")] + [Arguments("aVeryLongTextThatContainsALotOfCharacters.txt")] + [Arguments("NotEvenAFile")] + [Benchmark] + public string SpanStrip(string fileName) + { + // filenames cannot contain line breaks + if (fileName.Contains(Environment.NewLine) || fileName.Contains("\r") || fileName.Contains("\n")) + { + return fileName; + } + + var spanFileName = fileName.AsSpan(); + var lastIndex = spanFileName.LastIndexOf('.'); + if (lastIndex > 0) + { + var ext = spanFileName[lastIndex..]; + + // file extensions cannot contain whitespace + if (ext.Contains(' ')) + { + return fileName; + } + + return new string(spanFileName[..lastIndex]); + } + + return fileName; + } + } + + //| Method | fileName | Mean | Error | StdDev | Ratio | Gen 0 | Allocated | + //|------------ |--------------------- |----------:|----------:|---------:|------:|-------:|----------:| + //| StringStrip | NotEvenAFile | 45.08 ns | 1.277 ns | 0.070 ns | 1.00 | - | - | + //| SpanStrip | NotEvenAFile | 45.13 ns | 6.131 ns | 0.336 ns | 1.00 | - | - | + //| | | | | | | | | + //| StringStrip | aVery(...)s.txt[45] | 234.10 ns | 28.303 ns | 1.551 ns | 1.00 | 0.0751 | 240 B | + //| SpanStrip | aVery(...)s.txt[45] | 98.37 ns | 14.839 ns | 0.813 ns | 0.42 | 0.0331 | 104 B | + //| | | | | | | | | + //| StringStrip | smallText.txt | 187.79 ns | 35.672 ns | 1.955 ns | 1.00 | 0.0348 | 112 B | + //| SpanStrip | smallText.txt | 62.46 ns | 13.795 ns | 0.756 ns | 0.33 | 0.0124 | 40 B | +} diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Core/Telemetry/TelemetryServiceTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Core/Telemetry/TelemetryServiceTests.cs index 2acb31a5a0..bc4b68b508 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Core/Telemetry/TelemetryServiceTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Core/Telemetry/TelemetryServiceTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; @@ -49,7 +49,8 @@ public class TelemetryServiceTests : UmbracoIntegrationTest Constants.Telemetry.AspEnvironment, Constants.Telemetry.IsDebug, Constants.Telemetry.DatabaseProvider, - Constants.Telemetry.CurrentServerRole + Constants.Telemetry.CurrentServerRole, + Constants.Telemetry.RuntimeMode, }; MetricsConsentService.SetConsentLevel(TelemetryLevel.Detailed); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs index 9179b6cd69..ebf161072d 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs @@ -392,6 +392,9 @@ public class ContentServiceTagsTests : UmbracoIntegrationTest [Test] public void TagsCanBecomeInvariantByPropertyTypeAndBackToVariant() { + var frValue = new string[] { "hello", "world", "some", "tags", "plus" }; + var enValue = new string[] { "hello", "world", "another", "one" }; + var language = new LanguageBuilder() .WithCultureInfo("fr-FR") .Build(); @@ -409,9 +412,9 @@ public class ContentServiceTagsTests : UmbracoIntegrationTest content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", - new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + frValue, culture: "fr-FR"); content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", - new[] { "hello", "world", "another", "one" }, culture: "en-US"); + enValue, culture: "en-US"); ContentService.SaveAndPublish(content1); propertyType.Variations = ContentVariation.Nothing; @@ -421,7 +424,8 @@ public class ContentServiceTagsTests : UmbracoIntegrationTest propertyType.Variations = ContentVariation.Culture; ContentTypeService.Save(contentType); - // TODO: Assert results + Assert.AreEqual(frValue, Serializer.Deserialize(content1.GetValue("tags", "fr-FR"))); + Assert.AreEqual(enValue, Serializer.Deserialize(content1.GetValue("tags", "en-US"))); } [Test] @@ -847,7 +851,7 @@ public class ContentServiceTagsTests : UmbracoIntegrationTest IContent content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content"); content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", - new[] { "hello,world,tags", "new"}); + new[] { "hello,world,tags", "new" }); ContentService.SaveAndPublish(content); @@ -882,7 +886,7 @@ public class ContentServiceTagsTests : UmbracoIntegrationTest IContent content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content"); content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", - new[] { "hello,world,tags", "new"}); + new[] { "hello,world,tags", "new" }); ContentService.SaveAndPublish(content); diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/UserDataServiceTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/UserDataServiceTests.cs index a33d9a3680..67ba80a570 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/UserDataServiceTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/UserDataServiceTests.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; @@ -108,6 +108,20 @@ public class UserDataServiceTests Assert.AreEqual(modelsMode.ToString(), actual.Data); } + [Test] + [TestCase(RuntimeMode.BackofficeDevelopment)] + [TestCase(RuntimeMode.Development)] + [TestCase(RuntimeMode.Production)] + public void ReportsRuntimeModeCorrectly(RuntimeMode runtimeMode) + { + var userDataService = CreateUserDataService(runtimeMode: runtimeMode); + var userData = userDataService.GetUserData().ToArray(); + + var actual = userData.FirstOrDefault(x => x.Name == "Runtime Mode"); + Assert.IsNotNull(actual?.Data); + Assert.AreEqual(runtimeMode.ToString(), actual.Data); + } + [Test] [TestCase(true)] [TestCase(false)] @@ -124,7 +138,8 @@ public class UserDataServiceTests private SystemInformationTelemetryProvider CreateUserDataService( string culture = "", ModelsMode modelsMode = ModelsMode.InMemoryAuto, - bool isDebug = true) + bool isDebug = true, + RuntimeMode runtimeMode = RuntimeMode.BackofficeDevelopment) { var localizationService = CreateILocalizationService(culture); @@ -138,7 +153,8 @@ public class UserDataServiceTests Mock.Of>(x => x.CurrentValue == new HostingSettings { Debug = isDebug }), Mock.Of(), Mock.Of(x => x.CreateDatabase() == Mock.Of(y => y.DatabaseType == DatabaseType.SQLite)), - Mock.Of()); + Mock.Of(), + Mock.Of>(x => x.CurrentValue == new RuntimeSettings { Mode = runtimeMode })); } private ILocalizationService CreateILocalizationService(string culture) diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Telemetry/SystemInformationTelemetryProviderTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Telemetry/SystemInformationTelemetryProviderTests.cs index fbad15e560..63c7f6a1df 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Telemetry/SystemInformationTelemetryProviderTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Telemetry/SystemInformationTelemetryProviderTests.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.Linq; using System.Threading; using Microsoft.Extensions.Hosting; @@ -34,6 +34,21 @@ public class SystemInformationTelemetryProviderTests Assert.AreEqual(modelsMode.ToString(), actual.Data); } + [Test] + [TestCase(RuntimeMode.BackofficeDevelopment)] + [TestCase(RuntimeMode.BackofficeDevelopment)] + [TestCase(RuntimeMode.BackofficeDevelopment)] + + public void ReportsRuntimeModeCorrectly(RuntimeMode runtimeMode) + { + var telemetryProvider = CreateProvider(runtimeMode: runtimeMode); + var usageInformation = telemetryProvider.GetInformation().ToArray(); + + var actual = usageInformation.FirstOrDefault(x => x.Name == Constants.Telemetry.RuntimeMode); + Assert.IsNotNull(actual?.Data); + Assert.AreEqual(runtimeMode.ToString(), actual.Data); + } + [Test] [TestCase(true)] [TestCase(false)] @@ -82,7 +97,8 @@ public class SystemInformationTelemetryProviderTests private SystemInformationTelemetryProvider CreateProvider( ModelsMode modelsMode = ModelsMode.InMemoryAuto, bool isDebug = true, - string environment = "") + string environment = "", + RuntimeMode runtimeMode = RuntimeMode.BackofficeDevelopment) { var hostEnvironment = new Mock(); hostEnvironment.Setup(x => x.EnvironmentName).Returns(environment); @@ -93,10 +109,11 @@ public class SystemInformationTelemetryProviderTests return new SystemInformationTelemetryProvider( Mock.Of(), Mock.Of(), - Mock.Of>(x => x.CurrentValue == new ModelsBuilderSettings{ ModelsMode = modelsMode }), + Mock.Of>(x => x.CurrentValue == new ModelsBuilderSettings { ModelsMode = modelsMode }), Mock.Of>(x => x.CurrentValue == new HostingSettings { Debug = isDebug }), hostEnvironment.Object, Mock.Of(x => x.CreateDatabase() == Mock.Of(y => y.DatabaseType == DatabaseType.SQLite)), - Mock.Of()); + Mock.Of(), + Mock.Of>(x => x.CurrentValue == new RuntimeSettings { Mode = runtimeMode })); } } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Media/ImageSharpImageUrlGeneratorTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Media/ImageSharpImageUrlGeneratorTests.cs index 3a882d8b91..ca3b388e44 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Media/ImageSharpImageUrlGeneratorTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Media/ImageSharpImageUrlGeneratorTests.cs @@ -63,6 +63,33 @@ public class ImageSharpImageUrlGeneratorTests urlString); } + [Test] + public void GetImageUrlFurtherOptionsModeAndQualityTest() + { + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) + { + Quality = 10, + FurtherOptions = "format=webp", + }); + Assert.AreEqual( + MediaPath + + "?format=webp&quality=10", + urlString); + } + + [Test] + public void GetImageUrlFurtherOptionsWithModeAndQualityTest() + { + var urlString = s_generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) + { + FurtherOptions = "quality=10&format=webp", + }); + Assert.AreEqual( + MediaPath + + "?format=webp&quality=10", + urlString); + } + /// /// Test that if options is null, the generated image URL is also null. /// diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/InstallAreaRoutesTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/InstallAreaRoutesTests.cs index 48e9f4f904..8e8c07da8c 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/InstallAreaRoutesTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/InstallAreaRoutesTests.cs @@ -38,7 +38,7 @@ public class InstallAreaRoutesTests var endpoints = new TestRouteBuilder(); routes.CreateRoutes(endpoints); - Assert.AreEqual(2, endpoints.DataSources.Count); + Assert.AreEqual(1, endpoints.DataSources.Count); var route = endpoints.DataSources.First(); Assert.AreEqual(2, route.Endpoints.Count); @@ -64,10 +64,11 @@ public class InstallAreaRoutesTests endpoint2.RoutePattern.Defaults[AreaToken], typeof(InstallController).GetCustomAttribute(false).RouteValue); - var fallbackRoute = endpoints.DataSources.Last(); - Assert.AreEqual(1, fallbackRoute.Endpoints.Count); + var dataSource = endpoints.DataSources.Last(); + Assert.AreEqual(2, dataSource.Endpoints.Count); - Assert.AreEqual("Fallback {*path:nonfile}", fallbackRoute.Endpoints[0].ToString()); + Assert.AreEqual("Route: install/api/{action}/{id?}", dataSource.Endpoints[0].ToString()); + Assert.AreEqual("Route: install/{action}/{id?}", dataSource.Endpoints[1].ToString()); } [Test] @@ -79,10 +80,13 @@ public class InstallAreaRoutesTests Assert.AreEqual(1, endpoints.DataSources.Count); var route = endpoints.DataSources.First(); - Assert.AreEqual(1, route.Endpoints.Count); + Assert.AreEqual(2, route.Endpoints.Count); var endpoint = (RouteEndpoint)route.Endpoints[0]; - Assert.AreEqual("install/{controller?}/{action?}", endpoint.RoutePattern.RawText); + Assert.AreEqual("install/api/{action}/{id?}", endpoint.RoutePattern.RawText); + + endpoint = (RouteEndpoint)route.Endpoints[1]; + Assert.AreEqual("install/{action}/{id?}", endpoint.RoutePattern.RawText); } private InstallAreaRoutes GetInstallAreaRoutes(RuntimeLevel level) => diff --git a/umbraco.sln b/umbraco.sln index e6a1876c79..7cbd12cee6 100644 --- a/umbraco.sln +++ b/umbraco.sln @@ -14,7 +14,7 @@ EndProject Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Umbraco.Web.UI.Client", "http://localhost:3961", "{3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}" ProjectSection(WebsiteProperties) = preProject UseIISExpress = "true" - TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.5.2" + TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.8" Debug.AspNetCompiler.VirtualPath = "/localhost_3961" Debug.AspNetCompiler.PhysicalPath = "src\Umbraco.Web.UI.Client\" Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_3961\" @@ -37,7 +37,7 @@ EndProject Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Umbraco.Tests.AcceptanceTest", "http://localhost:58896", "{9E4C8A12-FBE0-4673-8CE2-DF99D5D57817}" ProjectSection(WebsiteProperties) = preProject UseIISExpress = "true" - TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.5.2" + TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.8" Debug.AspNetCompiler.VirtualPath = "/localhost_62926" Debug.AspNetCompiler.PhysicalPath = "tests\Umbraco.Tests.AcceptanceTest\" Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_62926\"
     Content In Index
    {{key}} {{val}}