├── .github ├── vale-linter.yml └── valeStyle │ ├── HeadingsPunctuation.yml │ ├── Hyperbolic.yml │ ├── ListStart.yml │ ├── SentenceLength.yml │ ├── Spacing.yml │ └── Terms.yml ├── 0000-rfc-template.md ├── CODE_OF_CONDUCT.md ├── LICENSE.md ├── README.md ├── RFC_CREATION.md ├── RFC_PROCESS.md ├── _vale.ini ├── cms ├── 0000-project-unicore-structure.md ├── 0001-project-unicore-intro.md ├── 0011-block-data-structure.md ├── 0012-rfc-block editor.md ├── 0016-TinyMCE-RTE-Improvements.md ├── 0017-media-tracking.md ├── 0020-install-process-under-net-core.md ├── 0021-future-proofing-the-umbraco-backoffice.md ├── 0022-ui-library.md ├── 0023-define-the-backoffice-extension-api.md ├── 0024-implement-the-new-backoffice.md ├── 0025-reusable-content-with-global-blocks.md ├── 0026-blocks-in-the-rte.md ├── 0027-the-future-of-search.md └── assets │ ├── GridStyleexamples1.jpg │ ├── GridStyleexamples2.jpg │ ├── GridStyleexamples3.jpg │ ├── GridStyleexamples4.jpg │ ├── GridStyleexamples5.jpg │ ├── blocks-in-the-rte │ ├── Content-in-the-rte.png │ ├── Edit-content.png │ ├── Insert.png │ ├── RTE.png │ ├── Settings-block-config.png │ └── Settings.png │ ├── diagram.png │ ├── global-blocks │ ├── Content - Add block.jpg │ ├── Content - Edit block.jpg │ ├── Content - Make local.jpg │ ├── Content - block grid.jpg │ ├── Content - clean.jpg │ ├── Content - make global.jpg │ ├── Content - publish.jpg │ ├── Content - splitview.jpg │ ├── Library - Preview.jpg │ ├── Library - clean.jpg │ ├── Library - info.jpg │ └── Library - language.jpg │ ├── project-structure-Current.png │ └── project-structure-Proposed.png └── docs └── 0009-rfc-styleguide.md /.github/vale-linter.yml: -------------------------------------------------------------------------------- 1 | # Configuration of the Vale Linter ProBot tool 2 | # github.com/warrenbuckley/vale-linter 3 | 4 | Vale: 5 | 6 | # If this feature is enabled or disabled 7 | Enabled: true 8 | 9 | Paths: 10 | # Path to the vale configuration file 11 | Configuration: "_vale.ini" 12 | 13 | # Path to the folder of Vale docstyles to use/copy 14 | # NOTE: If you update the styles path in _vale.ini remember to update this path too 15 | Styles: ".github/valeStyle/" 16 | 17 | Success: 18 | Header: "All checks passed 🎉" 19 | Message: "All changes you made follow our style guide rules! #h5yr" 20 | ShowImage: true 21 | ImageUrl: "https://media.giphy.com/media/6nuiJjOOQBBn2/giphy.gif" 22 | 23 | Warning: 24 | Header: "It passes but with warnings" 25 | Message: "Our style checker noticed a few potential issues. Please check the annotations for suggestions." 26 | ShowImage: false 27 | ImageUrl: "https://media.giphy.com/media/xUOxfh6ZM75efM3Bqo/giphy.gif" 28 | 29 | Error: 30 | Header: "Errors found" 31 | Message: "Our style checker found a few errors. Please check the annotations for suggestions." 32 | ShowImage: false 33 | ImageUrl: "https://media.giphy.com/media/r00LEeXVOt0xG/giphy.gif" 34 | -------------------------------------------------------------------------------- /.github/valeStyle/HeadingsPunctuation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | extends: existence 3 | message: Do not use '%s' at the end of headings 4 | link: https://github.com/cockroachdb/docs/blob/master/STYLE.md#capitalization-and-punctuation 5 | scope: heading 6 | level: warning 7 | raw: 8 | - '(?:\:|\.)$' -------------------------------------------------------------------------------- /.github/valeStyle/Hyperbolic.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: Consider removing '%s' 3 | link: https://github.com/cockroachdb/docs/blob/master/STYLE.md#language-and-tone 4 | ignorecase: true 5 | level: warning 6 | tokens: 7 | - simple 8 | - just 9 | - easily 10 | - actually 11 | - simply -------------------------------------------------------------------------------- /.github/valeStyle/ListStart.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Start each option with a capital letter." 3 | link: https://github.com/testthedocs/vale-styles/blob/master/OpenStack/ListStart.yml 4 | level: error 5 | scope: list 6 | nonword: true 7 | tokens: 8 | - '^[a-z].+' -------------------------------------------------------------------------------- /.github/valeStyle/SentenceLength.yml: -------------------------------------------------------------------------------- 1 | message: "Write shorter sentences (less than 40 words)." 2 | extends: occurrence 3 | scope: sentence 4 | level: warning 5 | max: 40 6 | token: \b(\w+)\b 7 | -------------------------------------------------------------------------------- /.github/valeStyle/Spacing.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "'%s' should have one space." 3 | level: error 4 | tokens: 5 | - '[.?!] {2,}[A-Z]' -------------------------------------------------------------------------------- /.github/valeStyle/Terms.yml: -------------------------------------------------------------------------------- 1 | --- 2 | extends: substitution 3 | message: Prefer %s over '%s.' 4 | level: warning 5 | ignorecase: true 6 | swap: 7 | back office: "'backoffice'" 8 | back-office: "'backoffice'" -------------------------------------------------------------------------------- /0000-rfc-template.md: -------------------------------------------------------------------------------- 1 | # RFC Name 2 | 3 | Request for Contribution (RFC) 0000 : _{RFC Name}_ 4 | 5 | ## Code of conduct 6 | 7 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 8 | 9 | ## Intended Audience 10 | 11 | The intended audience for this RFC is: {list recommeneded audience groups} 12 | 13 | ## Summary 14 | 15 | Give an intoduction summary to your RFC. 16 | 17 | ## Motivation 18 | 19 | Why are we doing this? What is the expected outcome? 20 | 21 | Please explain the motivation & advantages to this RFC. 22 | 23 | ## Detailed Design 24 | 25 | This is the main part of the RFC. How do you see this being implemented in Umbraco? 26 | 27 | ## Drawbacks 28 | 29 | Discuss any disadvantages or sideeffects of this RFC. 30 | 31 | ## Alternatives 32 | 33 | Are there any alternatives in approach that could be taken? 34 | 35 | ## Out of Scope 36 | 37 | List any items out of scope for this RFC. Use this to try to steer the discussion to be as specific as possible to the RFC details. 38 | 39 | ## Unresolved Issues 40 | 41 | The answers that we are hoping to get from the community & Umbraco HQ is: 42 | 43 | ## Related RFCs 44 | 45 | List any other related RFCs. Provide links where you can. 46 | 47 | ## Contributors 48 | 49 | This RFC was compiled by: 50 | 51 | * Person 1 52 | * Person 2 53 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Umbraco RFC Code of conduct 2 | 3 | 1. We respect the [”Our” code of conduct](https://our.umbraco.com/code-of-conduct) 4 | 2. Participants extend respect and courtesy to their community peers at all times. Treat others as you would like to be treated. This also goes for treating the Umbraco HQ with respect. 5 | 3. English is the primary language of the Umbraco community. However, it is not the native language of many community members. All participants, particularly those with English as a first language, attempt to accommodate the needs of other participants by communicating clearly, including speaking slowly and limiting the use of slang. 6 | 4. We dispute ideas by using reasoned argument rather than through intimidation or personal attack. Try to provide data and facts for your standpoints so the rest of the participants who are sitting on the sidelines watching the discussion can form an opinion. The discussion is easier when the response to a question is a polite answer. 7 | 5. Participants use their best engineering judgment to find the best solution for the whole community: project owners, engineers and end users; not the best solution for any particular technology, developer, partner or user. 8 | 6. Individuals are prepared to contribute to the ongoing work of the group. 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) # 2 | 3 | 4 | 5 | Copyright (c) 2013-present Umbraco 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > A journey of a thousand miles begins with a single step 2 | 3 | # Umbraco RFCs 4 | 5 | The Umbraco RFC (request for comments) process is intended to provide a consistent way for Umbraco HQ to facilitate the transparency of decisions made for features and changes in Umbraco products. 6 | 7 | An Umbraco RFC is a proposal for a significant change or a new feature. 8 | 9 | The RFC process will: 10 | 11 | * Facilitate the transparency of decision making by Umbraco HQ to Umbraco end-users. 12 | * Enable individual contributors to help make decisions. 13 | * Allow domain experts to have input in decisions. 14 | * Manage the risk of decisions made. 15 | * Have a snapshot of context for the future. 16 | 17 | Please read and respect the __[RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md)__ 18 | 19 | ### [See Active RFCs](https://github.com/umbraco/rfcs/pulls) 20 | 21 | ## The Umbraco RFC process 22 | 23 | This repository is intended to be used for reviewing submitted RFCs. 24 | 25 | ### Process outline 26 | 27 | * An RFC [pull request is made](RFC_CREATION.md) by Umbraco HQ and thereby [open for comments](RFC_PROCESS.md#Reviewing). 28 | * The RFC may may be [updated, closed or restarted if necessary](RFC_PROCESS.md#Updating) by the Author if they choose to. 29 | * When Umbraco HQ decides to finalize the RFC, it will be tagged for final comments and a deadline will be provided. 30 | * At the provided deadline the [RFC will be accepted or closed](RFC_PROCESS.md#Acceptance) by Umbraco HQ. 31 | * [Implementation](RFC_PROCESS.md#Implementation) may begin. 32 | 33 | _For more info follow the links in the bullet points above or [click here](RFC_PROCESS.md) to see the full process document_ 34 | 35 | ## Credits 36 | 37 | Umbraco's RFC process is inspired in part by the [React RFC process](https://github.com/reactjs/rfcs), [Rust RFC process](https://github.com/rust-lang/rfcs), [Wagtail RFC process](https://github.com/wagtail/rfcs) and [IETF RFC](https://www.ietf.org/standards/rfcs/) documents 38 | -------------------------------------------------------------------------------- /RFC_CREATION.md: -------------------------------------------------------------------------------- 1 | # Creating an RFC 2 | 3 | When creating an RFC, ensure that it meets these criteria: 4 | 5 | * Most changes, including small features, bug fixes and documentation improvements can be implemented and reviewed via the normal GitHub pull request workflow. __Questions or discussions on more substantial changes should first be done on https://our.umbraco.com until further defined to the RFC format if one is deemed necessary.__ 6 | * The RFC should be a proposal, whether this is a technical proposal or an idea, it must propose an outcome. 7 | * All topics for the RFC based on [the template](0000-rfc-template.md) must be known in advance of creating the RFC. 8 | 9 | ## Instructions 10 | 11 | * Fork this repository 12 | * Copy {tempate-name} to /{product}/0000-my-feature.md (where 'my-feature' is descriptive) Don't assign an RFC number yet as this must match the number of the pull request that you will later submit. For example: /CMS/0000-dotnetCore.md 13 | * Fill in the RFC. Put care into the details ensuring to provide information. RFCs that do not present convincing motivation, demonstrate understanding of the impact of the design, or are disingenuous about the drawbacks or alternatives tend to be poorly-received. 14 | * Submit a pull request. As a pull request the RFC will receive design feedback from Umbraco HQ and the community, **and the author should be prepared to revise it in response**. 15 | * (optional) Now that you have submitted a pull request, you can now assign the RFC number in the filename and title. This must always match the PR number to make the PR easy to find after the RFC has been merged. It's OK to skip this as it can be done while the RFC is being merged. 16 | 17 | _**Note**: It is the responsibility of the RFC Author(s) to keep the RFC updated with any changes needed while the RFC is open so that readers of the RFC are always reading the most up-to-date version. Similarly the Author must make sure the RFC is up-to-date at the end of the RFC process when it is either accepted or closed._ -------------------------------------------------------------------------------- /RFC_PROCESS.md: -------------------------------------------------------------------------------- 1 | # The Umbraco RFC process 2 | 3 | This repository is intended to be used for reviewing submitted RFCs. 4 | 5 | ## Process outline 6 | 7 | * An RFC [pull request is made](RFC_CREATION.md) by Umbraco HQ and thereby [open for comments](#Reviewing). 8 | * The RFC may may be [updated, closed or restarted if necessary](#Updating) by the Author if they choose to. 9 | * When Umbraco HQ decides to finalize the RFC, it will be tagged for final comments and a deadline will be provided. 10 | * At the provided deadline the [RFC will be accepted or closed](#Acceptance) by Umbraco HQ. 11 | 12 | ## Reviewing 13 | 14 | An RFC will be submitted in the form of a [Pull Request](https://github.com/umbraco/rfcs/pulls). Comments can be made directly on the Pull Request itself while the PR is open. 15 | 16 | ## Updating 17 | 18 | The RFC should always reflect it's current state and the Author(s) may update the RFC to reflect any decisions made while it is open. 19 | 20 | In some cases it will make more sense to close an RFC and start over again if the scope or purpose of the RFC should be radically changed. 21 | 22 | ## Acceptance 23 | 24 | When Umbraco HQ decides to finalize an RFC it will be tagged (`final-comment-period`) as having a final comment period which will generally be one or two weeks. An RFC may be accepted at the end of its final comment period and the associated pull request will be merged. When accepted, the RFC must be up to date and accurate and will represent the final intention of the RFC. 25 | 26 | An RFC may be closed (not accepted) after discussion has settled and comments have been made summarizing the rationale for being rejected. An RFC's associated PR is closed if this occurs. Other reasons an RFC may not be accepted is if it doesn't contain the appropriate information or if the RFC was submitted without previous discussion or HQ knowledge about it's intentions. In some cases once an RFC is closed, comments may be locked and if a follow up RFC is proposed, another PR will be submitted. 27 | 28 | ## Implementation 29 | 30 | When an RFC is accepted, then the process of implementing it may begin. The implementation process could be task(s) created on the project's issue tracker, or it could mean further, more detailed RFCs are created. In some cases tasks for an RFC will be created on the tracker tagged as `up-for-grabs` which means the implementation can be carried out by anyone. 31 | 32 | Being accepted does not imply anything about the priority of having it implemented and doesn't necessarily indicate that it's in active development. -------------------------------------------------------------------------------- /_vale.ini: -------------------------------------------------------------------------------- 1 | # Example Vale config file (`.vale.ini` or `_vale.ini`) 2 | 3 | # Core settings 4 | StylesPath = .github 5 | 6 | # The minimum alert level to display (suggestion, warning, or error). 7 | # 8 | # CI builds will only fail on error-level alerts. 9 | MinAlertLevel = warning 10 | 11 | # Global settings (applied to every syntax) 12 | [*] 13 | # List of styles to load 14 | BasedOnStyles = valeStyle 15 | # Style.Rule = {YES, NO} to enable or disable a specific rule 16 | 17 | # Syntax-specific settings 18 | # These overwrite any conflicting global settings 19 | [*.{md,txt}] 20 | vale.Editorializing = NO -------------------------------------------------------------------------------- /cms/0000-project-unicore-structure.md: -------------------------------------------------------------------------------- 1 | > Organize your life around your dreams and watch them come true 2 | 3 | # Project UniCore - Project Structure 🦄 4 | 5 | Request for Contribution (RFC) 2 : _Project and Solution re-structure_ 6 | 7 | ## Code of conduct 8 | 9 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 10 | 11 | ## Intended Audience 12 | 13 | The intended audience for this RFC is technical users and developers. 14 | 15 | ## Summary 16 | 17 | This RFC is a child of [Project UniCore - Introduction & Strategy](https://github.com/umbraco/rfcs/blob/master/cms/0001-project-unicore-intro.md) 18 | 19 | We plan to re-organize the .Net solution/project structure and the resulting Nuget packages for the Umbraco CMS. This is a __Phase 1__ requirement of moving to .NET Core. The task of changing the project structure is only a stepping stone to migrating to .NET Core. We do not plan on releasing an Umbraco version purely based on this restructure. Ensure to see the RFC for [Project UniCore - Introduction & Strategy](https://github.com/umbraco/rfcs/blob/master/cms/0001-project-unicore-intro.md), this RFC is referring to the first phase of that strategy (Project Structure) in the [Critical path diagram](https://github.com/umbraco/rfcs/blob/master/cms/0001-project-unicore-intro.md#critical-path-diagram). 20 | 21 | ## Motivation 22 | 23 | The main reasons for this are: 24 | 25 | * Allows for easier transitioning from .Net Framework to .Net Core - without splitting the projects out into their logical parts, it will be near impossible to abstract out the implementation logic that requires full .NET Framework vs .NET Standard packages. 26 | * Allows for a better developer experience by being able to import only the Nuget packages required for your project. 27 | * Allows for a cleaner architecture for the Umbraco codebase. 28 | * Better naming conventions for projects, packages and namespaces. 29 | * Easier to develop against and contribute to - it was necessary to move from a lot of smaller projects from v7 into 2 large projects (Umbraco.Core and Umbraco.Web) in v8 because it was much easier/faster to consolidate everything that wasn't legacy into fewer projects and then to trim off the legacy parts. Now that we have a project and code structure that makes sense and we no longer have a lot of smaller legacy projects, we can take the next step of re-splitting out the logical parts into separate projects. Developing against smaller separate projects means it is much easier to find and test aspects of the code. 30 | 31 | ## Detailed Design 32 | 33 | We plan to do this Phase 1 project split but making the least amount of changes possible with the actual Umbraco code. Of course some changes will be required since we will need to create new abstractions and implementations for those as we split out the projects but we don't plan on making any larger architectural changes during this split. 34 | 35 | We also are going to ensure that all changes along the way mean the solution always builds and that the application always works and tests are passing. We don't want to get into a state where we've moved a ton of code around and the solution doesn't compile while we spend significant amounts of time working towards getting it built and working again. This means each change will be small iterations. 36 | 37 | ### Legend 38 | 39 | * ![#CC0000](https://placehold.it/15/CC0000/000000?text=+) Red: It is a .Net Framework project 40 | * ![#C9d7f1](https://placehold.it/15/C9d7f1/000000?text=+) Blue: It is a project containing static files only 41 | * ![#cccccc](https://placehold.it/15/cccccc/000000?text=+) Grey: Projects that don't affect any HQ build outputs 42 | * ![#FFC300](https://placehold.it/15/FFC300/000000?text=+) Yellow: it is a candidate .Net Standard project 43 | * ![#DAF7A6](https://placehold.it/15/DAF7A6/000000?text=+) Green: External dependencies that are primary features of the CMS 44 | * --Dashed--: Candidate projects that produce an interchangable and/or environment specific implementation of a dependency (OS, .Net platform) 45 | 46 | ### Current structure 47 | 48 | ![current project structure](assets/project-structure-Current.png) 49 | 50 | #### Umbraco.Core 51 | 52 | A large project containing many abstractions along with the entire data access layer including all dependencies for all supported database providers. This project has several external 3rd party dependencies. 53 | 54 | Produces Nuget package `UmbracoCms.Core` 55 | 56 | We would like to split this project out into several smaller projects and packages. (See below) 57 | 58 | #### Umbraco.Web 59 | 60 | A large project containing some abstractions for both "Web" and "Core", meaning that many of the abstractions listed in this project should exist higher up in the dependency graph (i.e. in Umbraco.Core). This projects also contains several implementations for items that should exist higher up in the dependency graph (i.e. Property editor configuration classes) 61 | 62 | Produces Nuget package `UmbracoCms.Web` 63 | 64 | We would like to split this project out into several smaller projects and packages. (See below) 65 | 66 | #### Umbraco.Web.UI 67 | 68 | A web application project that contains some razor files, folders and configuration files. Currently we also have one very old webforms file here too. This project produces a DLL however there is no real compilable code in the project therefore producing an unecessary DLL. This is the project that imports the ModelsBuilder reference. 69 | 70 | Produces Nuget package `UmbracoCms` 71 | 72 | We would like to remove the remaining webforms, and resulting DLL thus resulting in a non-building project (i.e. folder project) 73 | 74 | ### Proposed structure 75 | 76 | ![proposed project structure](assets/project-structure-Proposed.png) 77 | 78 | #### Umbraco.Core 79 | 80 | * This project will have no external 3rd party dependencies. 81 | * Provides all of the abstractions and implementations (which have no dependencies) for the business logic of the Umbraco Cms 82 | * Is the implementation for the Umbraco Services (i.e. ContentService) 83 | * The namespaces in this project will be rooted to "Umbraco" (i.e. will not be prefixed with the project name) 84 | 85 | Produces Nuget package `UmbracoCms.Core` 86 | 87 | #### Umbraco.Infrastructure 88 | 89 | * This project is the implementation details for the persistence layer (i.e. umbraco repositories, npoco) therefore it has dependencies 90 | * Contains all of the Property Editor implementations and property value converters (that are not needed in a web context) 91 | * Logging implementations 92 | * Dependency Injection implementation 93 | * The namespaces in this project will be rooted to "Umbraco" (i.e. will not be prefixed with the project name) 94 | 95 | _NOTE: The name of this project, assembly and Nuget package is not absolute - meaning we may determine a better name in the future but for now this naming convention follows the [Clean Architecture](https://dotnet.microsoft.com/download/thank-you/aspnet-ebook) conventions_ 96 | 97 | Produces Nuget package `UmbracoCms.Infrastructure` 98 | 99 | #### Umbraco.Configuration 100 | 101 | * Will contain the configuration implementation 102 | * Currently flagged as .Net Framework for the initial phase of splitting out projects. In the 2nd phase of porting to .Net Core we will migrate this project to use the .Net Standard style configuration implementation which will be a future RFC. 103 | 104 | Produces Nuget package `UmbracoCms.Configuration` 105 | 106 | #### Umbraco.Members 107 | 108 | * Will contain all of the logic for dealing with Umbraco members 109 | * For the initial phase of splitting out projects all membership logic will be removed from the solution because members are based on the legacy membershipprovider technology which cannot be used in .Net Standard. During this phase this project will remain empty (not included in the solution). 110 | * Membership needs to be rewritten in ASP.Net Identity and this project will contain all of that logic (that is not part of this RFC, it will be a future project). 111 | 112 | Produces Nuget package `UmbracoCms.Members` 113 | 114 | #### Umbraco.BackOffice 115 | 116 | * Will contain all of the web based implementation for running the Umbraco backoffice such as MVC Controllers, ASP.Net Identity implementation for Users and Authentication/Authorization policies for the backoffice 117 | * Contains the models to support the backoffice and controllers 118 | 119 | Produces Nuget package `UmbracoCms.BackOffice` 120 | 121 | #### Umbraco.BackOffice.UI 122 | 123 | * Contains the client files used to build/run the backoffice 124 | 125 | Produces Nuget package `UmbracoCms.BackOffice.UI` 126 | 127 | #### Umbraco.Web 128 | 129 | * Contains the routing logic for front-end pages 130 | * Web implementation for running the front-end including some MVC controllers, filters, etc... 131 | * Helper & extension classes used for rendering front end templates 132 | * Contains some property value converters that are web specific (i.e. may return IHtmlString which is a web structure) 133 | 134 | Produces Nuget package `UmbracoCms.Web` 135 | 136 | #### Umbraco.Web.UI 137 | 138 | * Contains the configuration files that are shipped with the main Nuget project 139 | * Contains some razor views that are shipped with the front end (i.e. grid views) 140 | 141 | Produces Nuget package `UmbracoCms.Web.UI` 142 | 143 | #### Umbraco.Publishing 144 | 145 | * Contains the implementation for storing and querying published content 146 | 147 | Produces Nuget package `UmbracoCms.Publishing` 148 | 149 | #### Umbraco.Examine 150 | 151 | * Contains the implementation of Examine indexing for Umbraco 152 | * Contains all of the event handling to populate indexes 153 | 154 | Produces Nuget package `UmbracoCms.Examine` 155 | 156 | #### Umbraco.Persistence.SqlCe 157 | 158 | * Contains the implementation of the database dialect and provider for SqlCe 159 | * This will remain a .Net Framework assembly since it will only work on Windows 160 | 161 | Produces Nuget package `UmbracoCms.Persistence.SqlCe` 162 | 163 | #### Umbraco.Persistence.SqlServer 164 | 165 | * Contains the implementation of the database dialect and provider for Sql server 166 | 167 | Produces Nuget package `UmbracoCms.Persistence.SqlServer` 168 | 169 | #### Umbraco.Imaging.ImageProcessor 170 | 171 | * Contains the implementation of the imaging requirements for umbraco using Image Processor 172 | * This will remain a .Net Framework assembly since it will only work on Windows 173 | 174 | Produces Nuget package `UmbracoCms.Imaging.ImageProcessor` 175 | 176 | ## Drawbacks 177 | 178 | * Breaking changes due to different Nuget packages made available, but as this is Phase 1 to migrating to .NET Core and we don't plan on releasing a version purely based on a project restructure we shouldn't be concerned about breaking changes since there will be plenty with the release of Umbraco running on .NET Core anyways. 179 | * Namespace changes in the Umbraco solution will be made. Although this is a breaking change we feel that this is overcome by a textual find + replace. 180 | 181 | ## Alternatives 182 | 183 | It may be possible to move from .Net Framework to .Net Core with the current solution/project structure, however this would result in: 184 | 185 | * Since some dependencies are only .Net Framework (such as SQLCE) it would require multiple pre-processor directives throughout the codebase and cross compilation which makes the codebase more difficult to support, manage and contribute to. 186 | * Much lengthier time frames to reach .Net Core due to the complexity involved in migrating very large projects at one time instead of multiple smaller projects over time. 187 | * Lessens community involvement because without proper project separation the community would need to wait until large parts of the codebase are fully ported over instead of only waiting for smaller portions to be ported over. 188 | 189 | ## Out of Scope 190 | 191 | The change from .Net Framework to .Net Core is out of scope of this discussion, 192 | that RFC is found in the parent RFC [Project UniCore - Introduction & Strategy](). 193 | 194 | Any codebase design changes is out of the scope of this discussion. This RFC is only about solution, project, namespace and output Nuget package restructure. 195 | 196 | ## Related RFCs (where are we in roadmap?) 197 | 198 | * [RFC - Introduction & Strategy](https://github.com/umbraco/rfcs/blob/master/cms/0001-project-unicore-intro.md) 199 | * __RFC - Project/solution restructure__ 200 | * RFC - Database abstraction 201 | * RFC - Imaging abstraction 202 | * RFC - Configuration 203 | * RFC - .Net Core Version choice 204 | * RFC - Microsoft DI transition 205 | * RFC - Linux / Docker 206 | 207 | ## Contributors 208 | 209 | This RFC was compiled by: 210 | 211 | * Shannon Deminick (Umbraco HQ) 212 | * Carole Logan (Umbraco Community) 213 | * Lars-Erik Aabech (Umbraco Community) 214 | * Stéphane Gay (Umbraco HQ) 215 | * Bjarke Berg (Umbraco HQ) 216 | * Umbraco 2019 Retreat members -------------------------------------------------------------------------------- /cms/0001-project-unicore-intro.md: -------------------------------------------------------------------------------- 1 | # Project UniCore 🦄 2 | 3 | Request for Contribution (RFC) 1 : _Introduction & Strategy_ 4 | 5 | ## Code of conduct 6 | 7 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 8 | 9 | ## Intended Audience 10 | 11 | The intended audience for this RFC is technical users and developers. 12 | 13 | ## Summary 14 | 15 | Title: Project UniCore 16 | 17 | We would like to proceed with moving the current Umbraco codebase from .Net Framework to be based on .Net Core. 18 | 19 | 20 | 21 | We would like to make the porting of this code as simple as possible, both from the point of view of the engineers 22 | but more importantly the point of view of Umbraco end-users/developers. 23 | 24 | 25 | 26 | Where possible, we hope to create a .Net Core build of Umbraco while keeping as many of the same 27 | existing APIs and paradigms that developers are currently used to. 28 | 29 | We are calling this the “Minimal disruption” approach. 30 | 31 | ## Motivation 32 | 33 | Currently Umbraco runs on ASP.Net Framework which is a technology that is not in actively enhanced by 34 | Microsoft. .Net Core is the default platform recommended by Microsoft and is the platform that Microsoft 35 | will continue to evolve into the future, therefore, it is the obvious platform for Umbraco to move to. 36 | 37 | The motivation for the “Minimal disruption” approach is: 38 | 39 | 40 | 41 | For the benefit of Umbraco end-users, developers, contributors and Umbraco HQ, we want to make 42 | the development process for this transition as simple and short as possible. This means we would 43 | like to keep any changes to the current concepts in Umbraco to a minimum. We want to make the 44 | transition from the current .Net Framework version of Umbraco to a .Net Core version of Umbraco 45 | as frictionless as possible. 46 | 47 | 48 | 49 | ## Detailed Design 50 | 51 | The “Project UniCore” title is a code name for this project since we do not want to explicitly affiliate 52 | this project with an Umbraco numbered release. 53 | 54 | There will be future RFCs ready when certain milestones are ready. See the “Related RFCs” section at 55 | the end of this document. 56 | 57 | ### Critical Path diagram 58 | 59 | --- 60 | ![Project Unicore Diagram](assets/diagram.png) 61 | --- 62 | 63 | * The diagonal (top left to bottom right) is the “Critical Path” that will be taken to get to a .Net Core build. 64 | * ![#a998ba](https://placehold.it/15/a998ba/000000?text=+) Purple: Main components of the “Critical Path” 65 | * ![#cccccc](https://placehold.it/15/cccccc/000000?text=+) Grey: Sub modules of the main components (subject to change) 66 | * ![#CC0000](https://placehold.it/15/CC0000/000000?text=+) Red text: means that those will be RFCs that will be released when those milestones are ready 67 | * ![#CC0000](https://placehold.it/15/CC0000/000000?text=+) Red box: Areas of risk that may affect the timeline 68 | * ![#FFC300](https://placehold.it/15/FFC300/000000?text=+) Yellow: Areas that will be abstracted initially during the main phase of porting the project to .Net Core. 69 | Once the .Net Core switch milestone is ready to start, these areas will need to be developed in parallel with 70 | the “Critical Path”. The development of these areas should only be commenced with the 71 | consultation of Umbraco core development team. 72 | * ![#C9d7f1](https://placehold.it/15/C9d7f1/000000?text=+) Blue: Out of scope for “Project UniCore”. Candidates for successive projects.flag 73 | * ![#DAF7A6](https://placehold.it/15/DAF7A6/000000?text=+) Green: Considerations for pre-launch of the Umbraco .Net Core build (i.e. ecosystem) 74 | 75 | 76 | ### Other 77 | 78 | * The next RFC is the “Project structure design” which will contain the details about how we plan 79 | to get to the “.Net Core Switch” milestone 80 | * The final result of the “Minimal disruption” approach with regards to moving from the current .Net 81 | Framework version of Umbraco to a .Net Core version of Umbraco is that developers will be able to migrate 82 | their projects. The database will be able to be upgraded the same way as it is today. The solution 83 | will need to be migrated from .Net Framework projects to .Net Core projects and the existing code 84 | will need to be updated to support any breaking changes. Breaking changes will exist due to the ASP.Net 85 | change from .Net Framework to .Net Core and also for any necessary changes needed by the 86 | Umbraco .Net Core transition. 87 | * Namespace changes in the Umbraco solution will be made. Although this is a breaking change we feel 88 | that this is overcome by a textual find + replace. 89 | * Documentation will be provided on how to transition to the Umbraco .Net Core version including 90 | what breaking changes exist and how to overcome the common changes. 91 | 92 | ## Drawbacks 93 | 94 | Breaking changes are unavoidable when moving from the current .Net Framework of Umbraco to the .Net 95 | Core version of Umbraco. The primary purpose of this RFC is to show that we want to minimize these 96 | breaking changes where possible. 97 | 98 | 99 | ## Alternatives 100 | 101 | 102 | 103 | 1. The alternative to “Minimal disruption” approach is that we re-architect the majority of the 104 | Umbraco solution which would yield very large breaking changes and make the transition to this 105 | new version much more difficult and time consuming. There would be benefits of re-architecting 106 | large parts of the solution which would mean a cleaner Umbraco solution but we feel it’s more 107 | important to get to a .Net Core build faster and then make further architectural changes and 108 | enhancements in later versions. 109 | 2. Not changing namespaces at all. This will make the development flow more difficult. We also feel 110 | that it’s a necessary stepping stone with minimal impact to move towards a cleaner solution in the future. 111 | 3. Don’t move to .Net Core. We don’t feel that this is a viable option for a sustainable future of the Umbraco CMS. 112 | 113 | 114 | ## Out of Scope 115 | 116 | 117 | 118 | * Architectural changes and features that are not part of the “Critical Path” (including but not limited to Blue items) 119 | 120 | 121 | ## Unresolved Issues 122 | 123 | The answers that we are hoping to get from the community is: 124 | 125 | 126 | 127 | * Is this approach understandable? 128 | * Are there aspects of this approach missing? 129 | * Do you agree with the “Minimal disruption” approach? If not, why? 130 | 131 | 132 | ## Related RFCs (where are we in roadmap?) 133 | 134 | 135 | * RFC - Introduction & Strategy 136 | * RFC - Project/solution restructure 137 | * RFC - Database abstraction 138 | * RFC - Imaging abstraction 139 | * RFC - Configuration 140 | * RFC - .Net Core Version choice 141 | * RFC - Microsoft DI transition 142 | * RFC - Linux / Docker 143 | 144 | 145 | ## Contributors 146 | 147 | This RFC was compiled by: 148 | 149 | * Shannon Deminick (Umbraco HQ) 150 | * Carole Logan (Umbraco Community) 151 | * Lars-Erik Aabech (Umbraco Community) 152 | * Stéphane Gay (Umbraco HQ) 153 | * Bjarke Berg (Umbraco HQ) 154 | * Umbraco 2019 Retreat members 155 | -------------------------------------------------------------------------------- /cms/0011-block-data-structure.md: -------------------------------------------------------------------------------- 1 | # RFC Name 2 | 3 | Request for Contribution (RFC) 0019 : Block-based data structure interoperability (Project Proteus, version 2) 4 | 5 | ## Code of conduct 6 | 7 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 8 | 9 | ## Intended Audience 10 | 11 | The intended audience for this RFC is: 12 | * Technical users 13 | * Developers 14 | * Package Developers 15 | 16 | ## Summary 17 | 18 | We would like to define a standard for storing structured data as a foundation for complex Umbraco editors, such as Grid Layouts / DocType Grid Editor (DTGE) / LeBlender Editor, Nested / Stacked / Inner Content editors, etc. 19 | 20 | This project has the codename [Proteus](https://en.wikipedia.org/wiki/Proteus), named after the Greek god who was "capable to assume many forms"; and that is exactly what we want to achieve with this RFC. 21 | 22 | **The short term goals are:** 23 | - Standardise the way we utilise Umbraco elements (ElementTypes) 24 | - Provide a standard for separating content from presentation data within complex editors 25 | - Having a core framework for block manipulation to eventually implement packages like Grid Layouts, Nested Content or other `PublishedElement` oriented Property Editors (out-of-scope for this RFC) 26 | - Make sure that all the content is structured, easy to manipulate, predictable and indexed properly. 27 | 28 | **The long term goals are:** 29 | - Make the content of elements shareable, stored directly in the database as opposed to in JSON blobs. (out-of-scope for this RFC) 30 | - Use variants and segmentation (out-of-scope for this RFC) 31 | 32 | ## Motivation 33 | 34 | Currently, there are many complex editors, both in Core and as community packages, that store complex data structures in their different ways. This makes the data more difficult to consume and re-use. Furthermore, design or implementation specific configuration is often mixed with the data, which restricts the flexibility and reusability of some editors (e.g. Grid Layouts). 35 | 36 | The varying implementations result in equally varying developer experiences when utilising these editors. Having a common foundation for data storage means we can share common functionality across many parts of the CMS, and secure a more uniform developer experience. 37 | 38 | The lack of consistency makes it challenging or impossible for data manipulation, including: 39 | 40 | - Indexing the information 41 | - No way to reuse the data 42 | 43 | ## General Design 44 | 45 | The available "content blocks" on a complex editor is configured in a Prevalue Editor specific to the Property Editor. 46 | We would be using Element Types to define the structure of each "content block". 47 | 48 | ## Detailed Design 49 | 50 | We propose creating a uniform way to store the data of a complex editor. The data will consist of two main parts: 51 | 52 | **Layout:** The Layout will define Blocks that each will reference a content item located in the list of `contentData` by it's Content UDI. The Layout object will be key/value pairs where the `key` is the Property Editor alias. 53 | 54 | **ContentData:** A list of content items based on ElementTypes(`IPublishedElement`). 55 | 56 | **SettingsData:** A list of settings items based on ElementTypes(`IPublishedElement`). 57 | 58 | 59 | #### Simple example of JSON 60 | 61 | ```json 62 | { 63 | "layout": { 64 | "Umbraco.NestedContent": [ 65 | { 66 | "contentUdi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9", 67 | "settingsUdi": "umb://element/ab4ab2a76ba54761574845bc9e7db4e4" 68 | }, 69 | { 70 | "contentUdi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc1" 71 | } 72 | ] 73 | }, 74 | "contentData": [ 75 | { 76 | "udi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9", 77 | "title": "Hello" 78 | }, 79 | { 80 | "udi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc1", 81 | "title": "World", 82 | "text": "The content of a textarea" 83 | } 84 | ], 85 | "settingsData": [ 86 | { 87 | "udi": "umb://element/ab4ab2a76ba54761574845bc9e7db4e4", 88 | "color": "#c0ffe3" 89 | } 90 | ] 91 | } 92 | 93 | ``` 94 | 95 | ### The Layout 96 | The Layout will contain an object with a structure specific to the Property Editor, named by the Property Editor Alias. 97 | This is required because some editors will not store a simple one-dimensional array such as Nested Content, but rather multi-dimensional structures like Grid Layouts. By defining each layout with the alias of the Property Editor it means developers can in theory swap the underlying Property Editor without losing data and while keeping the layout preserved by the previous editor. 98 | 99 | The structure of a given layout object is defined by the Property Editor and can therefore vary depending on the Property Editor. 100 | 101 | Common for all is that the object referencing content items would implement the `IBlockElement` interface. This interface has two properties: 102 | 103 | * `contentUdi` — Used to link to the content item. 104 | * `settingsUdi` — Used to link to the content item. `settingsUdi` is not required and can therefore be left undefined. 105 | 106 | This object can be extended to contain more properties. This could be usefull for a Grid Property Editor, where each object might want to define its width in columns. 107 | 108 | ### The Data Buckets 109 | Both `contentData` and `settingsData` is a list of Element Type based content items (`IPublishedElement`) 110 | - Element Types are Document Types without any routable settings (e.g. templates, URL). 111 | - In the short term the element data will be stored as JSON and each element will have it's own UDI assigned. 112 | 113 | 114 | ### Strongly typed 115 | 116 | * The content items of `contentData` and `settingsData` are strongly typed as `IPublishedElement`. 117 | * The layout can be strongly typed too but will be up to the Property Editor to define. 118 | 119 | We do have a specific interface for the object representing a Block item, notice this can be extended by the specific Property Editor. The `IBlockElement` C# interface would look like this: 120 | 121 | ```cs 122 | 123 | public interface IBlockElement 124 | { 125 | Udi ContentUdi { get; } 126 | Udi SettingsUdi { get; } 127 | } 128 | ``` 129 | 130 | This also means these can be strongly typed and used by Models Builder to generate models. 131 | 132 | ### Future 133 | 134 | In the future `contentData` and potentially `settingsData` could be stored in the database as a document rather than embedded JSON objects. This unlocks the possibility for variant content, segmentation and scheduled publishing blocks by leveraging similar behaviour already in the Core CMS. (This part is out of the scope of this RFC). 135 | 136 | The `IBlockElement` does not have an identifier as of this proposal, but this proposal leaves room for appending a UDI to the `IBlockElement` making it posible to make future references for Blocks. 137 | Currently we do not support this and therefor its out of scope and blocks are left with no identifier. 138 | 139 | ## Drawbacks 140 | 141 | Compatibility between existing complex editors (Grid, Nested / Stacked / Inner Content, DTGE, etc) and the proposed model will unfortunately not be possible. 142 | 143 | Due to this, block based implementations of existing complex editors might need to be maintained alongside the existing editors for a while. This could cause confusion for developers about which editors to be using, however the old ones can be marked as deprecated so they no longer show up in the backoffice for new projects. 144 | 145 | An upgrade or migration path between specific editors could be defined at a later stage. 146 | 147 | ## Out of Scope 148 | 149 | - Creating new implementations of existing complex editors as block-based editors - separate RFCs will be proposed to determine the exact approaches per editor 150 | - Creating a mechanism to create and maintain PublishedElements as distinct documents in the database (Ability to share block content between editors) 151 | - Extending behaviour of `IPublishedElement`, including permissions and scheduled publishing 152 | - Use variants and segmentation at element level (out-of-scope for this RFC) 153 | - Validation of complex editors - We have the capability for this already but more prototypes and docs need to be written 154 | 155 | ## Contributors 156 | 157 | This RFC was based on previous RFC on the same topic: [RFC — 0011 — block-data-structure](https://github.com/umbraco/rfcs/pull/11/files?short_path=d8a15c1#diff-d8a15c17ff96b16ae9d652b0cbc3b6ca) compiled by: 158 | - [Callum Whyte](https://twitter.com/callumbwhyte) (community) 159 | - [Nathan Woulfe](https://twitter.com/nathanwoulfe) (community) 160 | - [Kenn Jacobsen](https://twitter.com/KennJacobsen_DK) (community) 161 | - [Jeffrey Schoemaker](https://twitter.com/jschoemaker1984) (community) 162 | - [Antoine Giraud](https://twitter.com/aaantoinee) (community) 163 | - [Niels Hartvig](https://twitter.com/thechiefunicorn) (HQ) 164 | - [Shannon Deminick](https://twitter.com/shazwazza) (HQ) 165 | 166 | This updated RFC v2 is compiled by: 167 | - [Niels Lyngsø](https://twitter.com/nielslyngsoe) (HQ) 168 | - [Claus Jensen](https://twitter.com/clausjnsn) (HQ) 169 | - [Shannon Deminick](https://twitter.com/shazwazza) (HQ) 170 | - [Rune Strand](Strand) (HQ) 171 | 172 | This updated RFC v3 is compiled by: 173 | - [Niels Lyngsø](https://twitter.com/nielslyngsoe) (HQ) 174 | - [Claus Jensen](https://twitter.com/clausjnsn) (HQ) 175 | - [Shannon Deminick](https://twitter.com/shazwazza) (HQ) 176 | 177 | -------------------------------------------------------------------------------- /cms/0012-rfc-block editor.md: -------------------------------------------------------------------------------- 1 | # RFC Name 2 | 3 | Request for Contribution (RFC): 0012-block-editor 4 | 5 | ## Code of conduct 6 | 7 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 8 | 9 | ## Intended Audience 10 | 11 | The intended audience: 12 | 13 | * Umbraco developers 14 | * Umbraco editors 15 | 16 | ## Summary 17 | 18 | A new backoffice editor that handles common page structure editing in a simpler and intuitive way. The main concept of the editor is to manage list of blocks that represents a web page's structure, where each block is both a collection of content and a way to configure that collection to be rendered. Each content block and configuration is defined by an Element Type to make administrating and editing with the new Block editor consistent. 19 | 20 | This editor aims to be an alternative to the popular editors in Umbraco version 7 such as Stacked Content and Nested Content. This editor also aims to be a foundation for other complex editors in the future. It's components will be able to be re-used to develop alternatives to other popular Umbraco 7 editors such as The Grid, LeBlender, and Doc Type Grid Editor. 21 | 22 | ![\[IMG\]](assets/GridStyleexamples1.jpg) 23 | 24 | ## Motivation 25 | 26 | * We need a good foundation for building complex editors with a strongly typed data structure. This foundation will eventually power a new grid based editor. 27 | * We need a new solution for V8 especially since the popular alternatives such as Stacked Content are not yet v8 ready and the new block editor should be a good replacement. 28 | * Umbraco currently doesn't have a 'page builder' type of editor which it needs. The current Grid implementation seems like a 'page builder' but it is not designed this way and trying to make it work as a 'page builder' is cumbersome. 29 | 30 | ## Detailed Design 31 | 32 | This editor is about managing list of blocks to build entire pages. In this example you see the backoffice on the left side, and the visual representation on the right side: 33 | 34 | ![\[IMG\]](assets/GridStyleexamples2.jpg) 35 | 36 | - The editor has the option to append or insert specific types of blocks anywhere in the editor. 37 | - Blocks can be edited, ordered or removed. 38 | - Each block consists of both content and config. The "Content" portion of a block is the normal content being edited such as: Title, Description, etc... The "Config" portion of a block is mainly used for visual styling, for example: Layout (right, left, wide, box), Background color, etc... 39 | 40 | 41 | ### Working with content 42 | 43 | Working with content for each row/cell will be done by clicking on an edit button to launch the content editor panel (using infinite editing, similar to the way LeBlender and Doc Type Grid Editor used to do in v7). Each row/cell can have it's own configuration applied to it and editing the configuration is achieved in the same way as editing content but instead by clicking on a configuration button. 44 | 45 | By editing each row/cell in the side panel it means we can render all property types for an Element Type and all Property Groups. This is unlike the editing experience with Nested Content where we can only render properties on a single group. 46 | 47 | ![\[IMG\]](assets/GridStyleexamples4.jpg) 48 | 49 | #### Default rendering 50 | 51 | There wil be a default rendering of blocks in the backoffice. Each block will be represented by a row showing the name of the block, it's icon along with the edit/config/delete buttons. The default rendering will also allow for nested blocks if the developer chooses to allow nested block element types. 52 | 53 | #### Customized rendering 54 | 55 | The block editor data type configuration will allow the developer to define a custom view for each block type. This will be based on the developer choosing a base folder location that will contain `.html` files for each block type. The name of the files are by convention and must correspond to the Element type alias. Umbraco's default rendering will render each block and if a custom view is found for the block type it will render that view for a given block. 56 | 57 | A more advanced functionality will also exists where a develoer can completely customize how an editor visualizes and works with the content blocks by specifying a custom `.html` view file for rendering the entire editor. If a custom view is specified the developer can customize how the editor visualizes and works with the content and in most cases it will look like and represent what will be rendered on the front-end. As an example, the image above is using a custom view to render out the full editor. 58 | 59 | The aim is to make implementing a custom view either per block or for the entire editor easy. The developer can re-use as many components as possible to get a customized view working quickly. This includes standardized components that allow for consistent validation practices along with consistent re-ordering (drag/drop) of blocks within the view. This will of course require documentation. 60 | 61 | #### Unsupported editors 62 | 63 | There will be some unsupported editors in the Block Editor, like there is today with Nested Content. Typically these are file based editors: Upload, Image Cropper. These will not be supported in the block editor and warnings will be shown if attempted to be used (like Nested Content). 64 | 65 | ### Setting up the block editor 66 | 67 | The way to set a new block editor is quick similar on how nested content work: 68 | 69 | 1. Create new Element Types, one for each type of "Content" block and one for each type of "Config" 70 | 1. Create a new data type using the "block editor" property editor and configure it to use the previously created Elements Types for your "Content" blocks and then choose their associated "Config" types 71 | 1. Use this new data type as property type for your document types 72 | 73 | #### Naming blocks 74 | 75 | Nested Content allows naming it's rows by using an AngularJs expression within the Data Type Configuration. The Block Editor will also support this since it provides the most flexibility however another simpler optino will be available. Block names can be generated based on the developer selecting which property type to use as the block name OR enter an AngularJs expression. Since a block stores both "content" and "configuration", it will be possible to name a block based on property data in either of these collections. 76 | 77 | By default the block name will be it's Index. 78 | 79 | ### Complex layouts? 80 | 81 | The block editor stores an array (linear list) of data. This will work for most pages structures since developers can apply any custom styling they want to render this data. However in some cases a page's structure may be more complicated and in those cases it is certainly possible to put another block editor inside of a block (nested block editors). Since each row/cell contains it's own config, this config can be used to define any number of layout options. 82 | 83 | **Example:** if a separation of blocks into columns is needed, a first level of blocks can be created as "splitters" and then "Content" block can be placed into them. 84 | 85 | ![\[IMG\]](assets/GridStyleexamples5.jpg) 86 | 87 | ### Data model 88 | 89 | The data model underpinning all of this is based on another RFC: https://github.com/umbraco/rfcs/blob/master/cms/0011-block-data-structure.md 90 | 91 | This editor will store an array of elements within it's `layout` property. 92 | 93 | Each block has it's own UDI (see [previous RFC for more info](https://github.com/umbraco/rfcs/blob/master/cms/0011-block-data-structure.md)) 94 | 95 | ## Drawbacks 96 | 97 | This editor may be competing with community built editors such as Stacked Content and Doc Type Grid Editor, however these editors are not yet v8 ready and it seems like this is a much needed feature in the CMS. 98 | 99 | ## Alternatives 100 | 101 | - Create a new Grid version V2, simpler, more usable and with structured data. However, we think the block editor would be a good start to getting everything in the core prepared for a new v2 of the grid since that will require everything (and more) than what this editor requires and we think that the block editor and a v2 grid could complement each other. 102 | - Keep the Grid as it is, but adding Doctype grid editor into the core (v8)with a visual editor into the backoffice to configure it (like Leblender). We don't feel like this is a great solution since we want to make the editor experience and this feature really shine, whereas trying to move DTGE into the core now isn't going to get us closer to this goal. 103 | 104 | ## Out of Scope 105 | 106 | * The new implementation of the grid. This RFC is not about creating a new grid v2. 107 | * Dealing with culture variance and multi-lingual implementations. The initial build of the block editor with be an MVP (Minimum viable product). In the future we will look into how this block editor can support content variance at the block level. 108 | * Sharing a block's content between different content items or editors. In the future this may be possible but is not part of the initial implementation. 109 | * Inline editing of content blocks, either on the front-end when previewing content or in the backoffice. Content blocks will only be edited by the slide out panel. 110 | * Block "security" per user group - this can be done with an event by modifying the data type configuration 111 | 112 | ## Unresolved Issues 113 | 114 | * Validation: We will need to prototype validation for block editing. We have the capability to do this in the CMS now but we will need to enhance/simplify the implementation and make sure that it's consistent. This goes for both client side and server side validation. There will be some challenges with this too since editing of blocks can be done a couple of different ways: inline vs contextual 115 | * The upload control is notorious for not working with these types of editors, it will probably remain that way but we'll need to deal with that somehow 116 | * Need to determine how a block is named, with Nested Content this is done with an angular template which is not very intuitive but it could also be an option 117 | * Need to determine the nicest way to add block data to the Examine indexes and how fields should be named. 118 | 119 | 120 | ## Related RFCs 121 | 122 | RFC 11: Block data structure 123 | - [RFC 11: Proteus](https://github.com/umbraco/rfcs/blob/master/cms/0011-block-data-structure.md) 124 | 125 | ## Contributors 126 | 127 | This RFC was compiled by: 128 | 129 | - [Callum Whyte](https://twitter.com/callumbwhyte) (community) 130 | - [Nathan Woulfe](https://twitter.com/nathanwoulfe) (community) 131 | - [Kenn Jacobsen](https://twitter.com/KennJacobsen_DK) (community) 132 | - [Jeffrey Schoemaker](https://twitter.com/jschoemaker1984) (community) 133 | - [Antoine Giraud](https://twitter.com/aaantoinee) (community) 134 | - [Niels Hartvig](https://twitter.com/thechiefunicorn) (HQ) 135 | - [Shannon Deminick](https://twitter.com/shazwazza) (HQ) 136 | 137 | -------------------------------------------------------------------------------- /cms/0016-TinyMCE-RTE-Improvements.md: -------------------------------------------------------------------------------- 1 | # RFC Name 2 | 3 | Request for Contribution (RFC) 0016 : TinyMCE RTE Improvements 4 | 5 | ## Code of conduct 6 | 7 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 8 | 9 | ## Intended Audience 10 | 11 | The intended audience for this RFC is: 12 | * Developers, implementors & editors 13 | 14 | ## Summary 15 | 16 | This RFC is to give specific details on how we plan to improve the existing implementation of the TinyMCE version 4 rich text editor. 17 | 18 | ## Motivation 19 | 20 | This has been a follow up RFC from #5 & #15. It has been discusssed that the rich text editor could be improved and enhanced to help give content editors a better experience when authoring or ammending content in the CMS. 21 | 22 | The motivation from #15 isn't really much different from this one: We would like to provide a Rich Text Editor experience that would enable content creators to work faster and simpler than our current implementation. We want the rich text editor to be fully configurable at the data type level instead of relying on a global configuration file like it currently does. The rich text editor should handle drag and drop and copy and paste of images nicely along with copy/pasting of Word documents. Common elements should be supported out of the box such as headers, quotes without having to add custom styles to a stylesheet. We also want to improve the current OEmbed functionality to include things like social media posts. 23 | 24 | ## Detailed Design 25 | 26 | The Rich Text Editor improvements will be based on the current rich text editor library that the Umbraco CMS uses which will be the latest version of TinyMCE 4.x. 27 | 28 | The following improvements to the TinyMCE editor are planned and in another round we can do further iterative improvements. 29 | 30 | **Configuration per data type** 31 | 32 | Currently there is a global tinymceconfig.config file which affects every instance of TinyMCE in the backoffice which isn't ideal. We will allow for total configuration of the rich text editor via the data type configuration. There will be some prototyping taking place on how to best present all of these configuration options to the developer since there's quite an overwhelming amount of configuration that can be done. There is an option to keep the current tinymceconfig.config file to be used as the default configuration values which get copied to new data types when they're created. 33 | 34 | **Implement pasting along with drag n drop of images** 35 | 36 | We have verified with a CodePen sample to ensure we could get TinyMCE to support this. We will allow a prevalue configuration of the editor in Umbraco to set a folder location of where to store pasted and dragged images in the media library. A future iteration could improve this further and prompt the user on where they would like to store the image/s in the media library. 37 | 38 | **Improve the HTML for images** 39 | 40 | Currently when an image is inserted by the media library a `style` attribute is applied to the image element for sizing but the native `width` and `height` element attributes should be used instead. The width/height value is also a static value determined by the data type which is probably not ideal in many circumstances. We will investigate the options on how to improve this experience. This could include anything from allowing the editor to enter a width/height, trying to auto-detect these values, looking into using the html img element's `srcset` and `sizes` attributes or even look at the experimental [intrinsicsize](https://googlechrome.github.io/samples/intrinsic-size/index.html) attribute. We also need to be aware that the images inserted into the RTE use query strings on the image source to ensure a resized image is returned. To prevent a huge hi-res image from being used, however some editors do want the hi-res image source to be used. This could be a case where we have more options for the editor to configure the image when inserting. 41 | 42 | **Reduce inital load time and file size of TinyMCE into the browser** 43 | 44 | We will prototype various ways to improve the perceived initial load time of TinyMCE. We will be looking at minification and compression techniques along with loading some of it's assets in behind the scenes before the editor is rendered. 45 | 46 | **Improve the loading experience** 47 | 48 | Use Tiny's `init_inistance_callback` property to remove Umbraco's own loader as opposed to the current implementation of checking it the TinyMCE library is loaded. 49 | 50 | **Improve the experience with pasting from Word documents** 51 | 52 | Use Tiny's event `before_paste` to notify us when content is being pasted into the editor. This event already notifies us if the content was copied from Word. We can use the pasted content to some JavaScript open source library or C# library to help clean up the HTML markup & formatting and thus remove any flicker associated with the editor loading. 53 | 54 | We would like to allow developers to enhance this themselves by replacing this functionality if they choose too with already existing plugins such as the paid plugin by [TinyMCE PowerPaste](https://apps.tiny.cloud/products/powerpaste/) 55 | 56 | **Improve moving un-editable elements** 57 | 58 | For non-editable elements inserted into the rich text editor (such as macros, or OEmbed content) we want to allow for moving these elements in a nicer way by allowing copy/pasting or moving of these elements. 59 | 60 | **Improve common and custom styles/formatting** 61 | 62 | By default the toolbar will have common styles and formatting options such as headers, quotes and code references (blocks and inline). Creating these custom buttons/styles in TinyMCE is trivial and we will investigate how these things could be extended and configured in the datatype editor if developers wanted to add their own buttons. A great example of how this is possible today can be found [on this blog post](https://www.justnik.me/blog/umbraco-rte-styles-another-way). For the improved editor, we want to allow configuration of these things at the datatype level with a bit of UI jazz to make customization nicer than editing JSON text. 63 | 64 | ## Drawbacks 65 | 66 | There should be no drawbacks to this, as this project can be iterative and add improvements and enhancements to the existing editor that we all currently use. 67 | 68 | ## Alternatives 69 | 70 | We did consider Trix from the previous user testing results from content editors that we recieved, however after comparing speed, extensibility, documentation of the editors. We found that it would be more beneficial to improve and enhance what we already have as opposed to re-implementing everything again in Trix and having to maintain two editors side by side. In part because removing TinyMCE would be considered a breaking change. Below are notes on some of the findings & comparissons. 71 | 72 | **Cleaner HTML output**
73 | 74 | Trix was proposed it had a cleaner HTML output, however from testing the editor side by side with our TinyMCE implementation when using the `Enter` key, Trix would generate markup as a `
` as opposed to TinyMCE's more semantically correct `

` paragraph. 75 | 76 | **Loading and Rendering**
77 | Trix is a more leightweight library and is able to load very quickly, however when considering the functionality and additions that the TinyMCE editor can currently do. It is an unfair comparisson. 78 | 79 | We are aware that TinyMCE takes longer to do its initial load into the backoffice for the first request due to the size of the library. Subsequent requests - regardless if TinyMCE uses an IFrame or not - are fractionaly slower when rendering the editor and its contents than Trix. As mentioned above we aim to reduce the initial file size to help with the first render of a TinyMCE editor. 80 | 81 | One thing from our testing we noticed that the current implementation of TinyMCE when testing with a slow/throttled network connection will load several times. This is due to an implemntation flaw where we currently check that the TinyMCE library is loaded. Due to the way TinyMCE has been developed checking the presence of the main library is loaded is not the best way to know if an editor is ready. We plan to fix this as part of our improvements as TinyMCE gives us a callback function to notify us when it has fully loaded and initilased the editor to help the jarring experience of several loading phases. 82 | 83 | 84 | ## Out of Scope 85 | 86 | **Upgrading to TinyMCE 5**
87 | 88 | After some initital research & findings, we found that it would cause breaking changes for any Umbraco sites who have written their own TinyMCE plugins/buttons. We also found that upgrading to TinyMCE version 5 would give us little benefit, apart from the underlying APIs that it uses has been made neater. 89 | 90 | 91 | ## Unresolved Issues 92 | 93 | * Finding an OpenSource library to help cleanup pasted Word HTML, either JavaScript or C# that does the best job 94 | 95 | 96 | ## Related RFCs 97 | 98 | 99 | 100 | * https://github.com/umbraco/rfcs/pull/15#issuecomment-514550647 101 | * https://github.com/umbraco/rfcs/pull/5 102 | 103 | 104 | 105 | ## Contributors 106 | 107 | This RFC was compiled by: 108 | 109 | * Warren Buckley (Umbraco HQ) 110 | -------------------------------------------------------------------------------- /cms/0017-media-tracking.md: -------------------------------------------------------------------------------- 1 | # RFC Name 2 | 3 | Request for Contribution (RFC) 0017: _Umbraco media item tracking_ 4 | 5 | ## Code of conduct 6 | 7 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 8 | 9 | ## Intended Audience 10 | 11 | The intended audience for this RFC is: 12 | 13 | * Umbraco developers 14 | * Umbraco users 15 | 16 | ## Summary 17 | 18 | We would like to enable Umbraco to natively track references between items so that users can visually see how items are interlinked and where they are used. For example, we want to allow users to be able to see where a particular media item is being referenced, or for a developer to see what content is using a particular Macro. 19 | 20 | For this RFC we will focus on Media tracking. 21 | 22 | The goal of this RFC is to detail the MVP (Minimum Viable Product) for an initial release of Media tracking in the CMS and shed light on any issues or pitfalls with the approach described below. In the future, we will add further support for tracking Umbraco item relations. 23 | 24 | ## Motivation 25 | 26 | There is currently no way to tell if an Umbraco item is being referenced. This makes cleanup a difficult process since deleting an item that is referenced can have an unintentional impact on content and potentially break functionality on a site. Adding tracking and overview of Umbraco item usage would help increase confidence when working in the backoffice as users have a chance to either avoid deleting an item or remove/change referenced items before deleting, mitigating unexpected outcomes. It will enable users and developers to be proactive instead of reactive when working with Umbraco items. 27 | 28 | ## Detailed Design 29 | 30 | ### Property Editors 31 | 32 | The fundamental change in Umbraco to support this is to update the Property Editor APIs so that a Property Editor itself returns the UDIs that it is referencing. This will occur whenever an Umbraco content item (Content, Media, Member) is saved that uses Property Editors. When Umbraco saves the data, it will iterate over all of its property types and ask the corresponding Property Editor to return a list of UDIs. 33 | 34 | The method could be something along the lines of: 35 | 36 | ```cs 37 | IEnumerable GetReferences(TContent content, Property property); 38 | ``` 39 | 40 | This means the power of resolving related items is in the hands of the Property Editor since it knows exactly what data it is storing and how to process it. 41 | 42 | The property editors that will need to be updated to use this method are: 43 | 44 | * Content Picker 45 | * Media Picker 46 | * Member Picker 47 | * MNTP 48 | * Rich Text Editor 49 | * Grid 50 | * Multi URL Picker 51 | * Nested Content 52 | * Markdown editor 53 | 54 | ### Relations 55 | 56 | When an Umbraco content item (Content, Media, Member) is saved and all of the UDI references have been resolved from the Property Editors, we will store these relations in the Umbraco Relations database table using the Umbraco Relations Service APIs. For content, we will be tracking relations for "Published" and "Pending" content. 57 | 58 | The relations Service APIs may need to be enhanced to properly support Umbraco media item tracking and reporting detailed in this RFC. 59 | 60 | _NOTE:_ We need to investigate how Umbraco Deploy is handling relations since we don't want to reinvent anything. We will either leverage what Umbraco Deploy is doing or Umbraco Deploy will leverage this implementation. 61 | 62 | ### Media reporting 63 | 64 | We intend on adding a report to the "Info" tab of a media item to show it's relations. The "Info" tab on a media item currently has quite a lot of available real estate so we plan on using that instead of creating another content app for this. 65 | 66 | This report will be a list showing which content, media and member items the media item is being used in. We will also indicate if these references are in the recycle bin. Each item will have a link to navigate to the related item and ideally, this will be in infinite editing but as an MVP this may mean linking to the item directly. 67 | 68 | ## Drawbacks 69 | 70 | * Potential performance implications 71 | * Tracked relations between Umbraco items might potentially become out of sync which can add more confusion 72 | 73 | ## Alternatives 74 | 75 | Let users choose community packages to achieve this functionality such as Nexu. However, we want to be able to enable more than media tracking. We want to ensure that the functionality for reporting dependencies is baked into the Umbraco core editors instead of relying on external logic trying to manage these relations. We hope to borrow some inspiration from community packages and their users to achieve the best results. 76 | 77 | ## Out of Scope 78 | 79 | * Although the design of this implementation will support tracking other Umbraco items other than media, the implementation of this RFC will focus solely on Media which means any reporting and functionality relating to other Umbraco items: Macros, Content, Templates, Members, Forms will not be part of the MVP. 80 | * Users, Languages, Views, Partial Views, Stylesheets, Scripts will not be part of the relationship tracking APIs developed. 81 | * For this MVP, reporting of media relations will be limited to the Info app on Media items only. Any additional reporting is outside of the scope of this RFC and may be included in future RFCs. 82 | * For this MVP we do not plan on warning the user upon deletion of a media item if it is actively being used, in the future this will be a feature. 83 | * For this MVP we do not plan on making it possible to create connectors/resolvers (similar to [Property Value Converters](https://our.umbraco.com/documentation/Extending/Property-Editors/value-converters)) for getting references from a property editor. We plan to add this functionality in the future. 84 | * It will not be possible register a property editor for tracking via package.manifest in the MVP. We hope to add this functionality in the future. 85 | 86 | ## Unresolved Issues 87 | 88 | * How do we handle variants? The plan is to use the relations APIs and tables to do the tracking but they don't support "Culture" which would be required to link (for example) and media item to an English content variant. Currently, we can only link a media item to an entire Content item. To support this we would either need to: Change the relation table to have an additional language column - but this will mean that this table becomes less generic - and also change the relations APIs to support language, or we create a brand new tracking data set and services APIs. Still needs investigating. 89 | 90 | ## Related RFCs 91 | 92 | _No related RFCs_ 93 | 94 | ## Contributors 95 | 96 | This RFC was compiled by: 97 | 98 | * Shannon Deminick (https://twitter.com/shazwazza) 99 | * Rune Strand (https://twitter.com/hemraker) 100 | 101 | Feedback, suggestions and comments contributed by: 102 | 103 | * Nathan Woulfe 104 | * Carole Rennie Logan 105 | * Bjarne Fyrstenborg 106 | * Kenn Jacobsen 107 | * Claus Jensen 108 | * Dave Woestenborghs 109 | 110 | Thanks for participating 🙌 -------------------------------------------------------------------------------- /cms/0020-install-process-under-net-core.md: -------------------------------------------------------------------------------- 1 | # RFC Name 2 | 3 | Request for Contribution (RFC) 0020 : _Install Process under .NET Core_ 4 | 5 | ## Code of conduct 6 | 7 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 8 | 9 | ## Intended Audience 10 | 11 | The intended audience for this RFC is technical users and developers. 12 | 13 | ## Summary 14 | 15 | This RFC is a child of [Project UniCore - Introduction & Strategy](https://github.com/umbraco/rfcs/blob/master/cms/0001-project-unicore-intro.md) 16 | 17 | In moving the Umbraco project to .NET Core, there will be changes needed in how a new Umbraco project is started. Existing methods for starting a new project won’t work with changes that have been made to NuGet. This RFC focuses on what those changes are, how they affect the Umbraco install process, and how we can continue to make the install process easy for installers. 18 | 19 | 20 | 21 | ## Motivation 22 | 23 | The change from .NET Framework to .NET Core as the targeted framework means that we will need to reference NuGet packages using the `PackageReference` syntax instead of the legacy `packages.config` file. This change brings with it certain restrictions that Microsoft has imposed on the `PackageReference` dependencies. In particular, scripts are not supported cross-platform and install scripts and config file transformations are no longer executed at all. 24 | 25 | Not being able to transform configuration files and not being able to run install scripts means that Umbraco does not have a simple way to set up all the deep interactions it needs with the ASP.NET Core website. 26 | 27 | ## Detailed Design 28 | 29 | We suggest introducing a `dotnet new` template. These templates are used by Visual Studio, other IDEs, and the `dotnet` CLI to create new projects for .NET Core applications. Custom templates are supported, and allow for completely customizing the initial project structure and configuration. 30 | 31 | The template would include the `UmbracoCMS` NuGet package and configure the project settings and initial files to allow for a user to start developing. 32 | 33 | The templates allow for parameters to be provided to customize the installation process. For the initial implementation, we will support a project name as the only available parameter. Other parameters can be added in the future to further customize the Umbraco project. 34 | 35 | ### Installing Umbraco from the .NET Core CLI would then be: 36 | One time install of the template: `dotnet new -i UmbracoCms` and then `dotnet new UmbracoCms -n MyProjectName` when you want to create a new project. 37 | 38 | ## Drawbacks 39 | The primary drawback is that the template needs to be installed before it can be used for the first time. This is an additional step before users can get started. 40 | 41 | Another drawback is that configuration changes needed during upgrades would have to be handled in a different manner, since the `PackageReference` syntax no longer allows for install scripts, and .the `dotnet new` templates would only apply to new projects. 42 | 43 | ## Alternatives 44 | 45 | The only alternative we can come up with is to include a script that will do the configuration transformation and other needed things when executed. If we were to provide a script, it would need to be run manually after installing the NuGet package. 46 | 47 | ## Out of Scope 48 | 49 | * The advanced configuration of the project template is out for the scope of the first edition. 50 | 51 | ## Unresolved Issues 52 | 53 | The answers that we are hoping to get from the community are: 54 | 55 | 1. Are you aware of any better alternatives? 56 | 1. Are you aware of any possible way to achieve the existing workflow? 57 | 58 | ## Related RFCs 59 | 60 | * [RFC - Introduction & Strategy](https://github.com/umbraco/rfcs/blob/master/cms/0001-project-unicore-intro.md) 61 | 62 | ## Contributors 63 | 64 | This RFC was compiled by: 65 | 66 | * Benjamin Carleski (Umbraco Community) 67 | * Bjarke Berg (Umbraco HQ) 68 | * Emma Garland (Umbraco Community) 69 | * Steve Temple (Umbraco Community) 70 | * Andy Butland (Umbraco Community) 71 | * Yvo Linssen (Umbraco Community) 72 | * The Umbraco Unicore Team 73 | -------------------------------------------------------------------------------- /cms/0021-future-proofing-the-umbraco-backoffice.md: -------------------------------------------------------------------------------- 1 | # Future-proofing the Umbraco backoffice 2 | Request for Contribution (RFC) 0021 : Future-proofing the Umbraco backoffice 3 | 4 | ## Code of conduct 5 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 6 | 7 | ## Intended Audience 8 | The intended audience for this RFC is: technical users, developers and package authors 9 | 10 | ## Summary 11 | To future-proof Umbraco’s backoffice, we intend to run a three-part process - each with their own RFC. 12 | 1. Standalone UI Component library (RFC soon - January 2021) 13 | 2. Defining backoffice extension API (RFC spring 2021) 14 | 3. Implement backoffice (RFC summer 2021) 15 | 16 | It can be helpful to watch [this umbracoCoffee](https://youtu.be/i0QfgRYj0zQ?t=1681) episode where Filip Bech, CMS Program Manager for Umbraco, introduces the RFC and the thoughts behind it. 17 | 18 | ## Motivation 19 | Umbraco’s backoffice is a big reason editors AND developers choose Umbraco. It is easy to use and flexible to customize to specific needs for a project/client 20 | 21 | The current (second) generation back-office is built using AngularJS. It was a great choice in 2013, and has served us well, but has long been considered outdated. From December 2021 it will no longer receive updates/patches (RIP). 22 | 23 | Since 2012 we have learnt a lot about building a complex Single Page Application (SPA). The current situation doesn’t allow us (or makes it really hard) to fix things we have done inherently wrong. The current state is holding development - and excitement - back. 24 | 25 | There are 4 challenges of the current backoffice, that motivates us for this project: 26 | 1. Product-specific UI makes the Umbraco journey (CMS, 1st- and 3rd party packages, Cloud, etc.) inconsistent and development inefficient. 27 | 2. Unclear extension API surface makes developers reach for undocumented hacks, resulting in an unofficial API layer that we still try to maintain. 28 | 3. The current architecture and framework is holding back and/or slowing down development. 29 | 4. AngularJS enters EOL in ~12 months. 30 | 31 | With the next generation of Umbraco’s backoffice, we want to bring a number of benefits to Umbraco, namely: 32 | - Speed up maintenance and future development of BackOffice for Umbraco HQ and community 33 | - Make integrations to 3rd parties more straightforward 34 | - Make Umbraco more attractive for newcomers, by using modern technology and methodology - thereby also making it easier to contribute 35 | - Simplify and speed up work for developers and package-authors, by enhancing the ability to create great UI/UX 36 | - Streamline the experience throughout the entire journey incl. 1st- and 3rd party packages, Cloud etc. 37 | - Reuse work across our products for less development but also for improvements to be distributed. 38 | - Maintain market leadership in customizable editing experience (tailored to clients) 39 | - Improve the upgrade experience 40 | 41 | ## Detailed Design 42 | To tackle the issues and achieve the benefits described above, we intend to split the project into 3 parts/major milestones. 43 | 44 | We do this in order to get real user feedback through an exploratory and agile process, and to make a difference for developers and editors in increments. 45 | 46 | The three milestones will have individual RFCs and are as follows: 47 | 1. Build a UI Library 48 | 2. Define backoffice extension API 49 | 3. Implement backoffice 50 | 51 | The parts are not entirely sequential and can run in parallel to a certain extent. 52 | 53 | ### Timing 54 | RFC for part 1 will be published in January and we expect work to start shortly thereafter. 55 | 56 | We feel this is important and that we risk halting further development if we don't act now and with sufficient team-size. 57 | 58 | We expect part 2 to start in the spring. Part 1 does not need to be done before this can start 59 | 60 | Part 3 will start when part 2 is ready. 61 | 62 | Read on to learn more about the different parts, and, as mentioned, there will be separate RFCs for each part (we will make sure to update this with links as they are published). We also intend to create a new community team around these efforts. 63 | 64 | ### 1. Build a UI Component Library 65 | We want to create a library of new UI components that are thoughtfully built with reuse and accessibility in mind. 66 | The UI library will be its own separate Open Source project with source code on GitHub and distributed for use oustside the Umbraco backoffice via NPM (packages that are not exclusive to Umbraco, other Umbraco HQ products etc.). 67 | 68 | The goal of part 1 is to create a consistent set of components covering our needs for the CMS. Additionally these should make it easy for developers and package-authors to make something that "feels like Umbraco". 69 | 70 | We want documentation to be built in, so it won't become outdated or left out. 71 | 72 | We want the components to work with any framework so it is not tied to Umbraco’s backoffice only. 73 | 74 | We intend to start releasing public builds when we have sufficient components to get an understanding of how the UI Library will work and in order to get feedback and collaboration as soon as possible. 75 | 76 | **A UI Component Library will make the Umbraco experience more beautiful, accessible and consistent, while also making it easier and less work for developers and maintainers.** 77 | 78 | ### 2. Define BackOffice Extension API 79 | In the second part, the goal is to define a public API for the backoffice. The official/documented API for the current backoffice implementation is too limited, which has led developers to rely on undocumented hacks, that the backoffice now unofficially supports. 80 | 81 | The current API is not easy for newcomers to understand, and it makes it hard to know what can be safely used/changed. 82 | 83 | Furthermore, the current API is tightly coupled to AngularJS, which means developers have to learn an additional (outdated) framework to extend/customize Umbraco and also means that changes to the framework can break the API. 84 | 85 | The goal of part 2 is to define an API that is based on Web Standards and best practices, without any ties to a specific framework. 86 | 87 | This second part will define what extending Umbraco will look like. We want to keep our options open and not decide anything just yet. This will be discussed and decided in the RFC for part 2 and there will be examples to start the discussion. Further prototyping will also be done in part 2. 88 | _An example of how this could work_, as opposed to today where you define an angular-template and a .js-resource for a dashboard or property editor, you would instead define a tagName and a .js-resource. This will give developers the flexibility to decide on their own implementation of choice. 89 | 90 | We want to support all the current documented/official use cases, and a subset of the undocumented use cases. This is crucial to help lighten the burden on package developers in terms of migrating to the new API. 91 | 92 | It should be easy and intuitive to extend and customize Umbraco’s backoffice - familiar for experienced Umbraco developers and recognizable for frontend developers. 93 | 94 | The API-implementation will have TypeScript definitions, enabling IDEs and tooling to help developers as much as possible, but TypeScript will not be forced on developers. 95 | 96 | **A clearly defined API will make it easier to develop and extend Umbraco’s backoffice, provide better tooling and make it safer to upgrade Umbraco.** 97 | 98 | ### 3. Rebuild BackOffice 99 | We need to rebuild the existing Umbraco backoffice, with the new API defined in part 2. This will be a complete rewrite, not a migration, and can only be released after it is completely done! 100 | 101 | The goal of part 3 is to have a modern and maintainable platform, where the technology doesn't complicate or slow down further development. Umbraco’s backoffice should be flexible enough to allow for new ideas and should be testable. The rebuild will use TypeScript (mandatory for Core developers). 102 | 103 | When rebuilding backoffice a choice of a framework can become relevant. No matter the choice of framework, this won’t make any difference for third party extensions/packages as backoffice APIs have no framework coupling. 104 | 105 | In order to mitigate the impact of releasing part 3 for developers and package authors, we will ensure that documentation and training are updated in due time, and that a Release Candidate will be available for an extended period of time before the final release. 106 | 107 | This will be done in collaboration with the various community teams, such as the documentation curators and the package team. 108 | 109 | Furthermore we will aim to have the changes running on the existing backend codebase allowing for "the old" and new backoffice to run simultaneously during development. This means that alpha/beta/release candidates will include both "the old" and new backoffice, whereas final release will be the new backoffice codebase. 110 | 111 | 112 | **A new implementation of Umbraco’s backoffice will give us a better platform to build on and allow us to remove AngularJS. Furthermore, allowing us to evolve the backoffice without breaking the API.** 113 | 114 | ## Drawbacks 115 | Part 3 will be a big-bang release (everything released at once) and will effectively break all existing packages. 116 | 117 | We have considered alternative approaches such as a more incremental approach using adapter/API-bridge/compatibilty layer. We chose to move on with the proposed solution, to allow the flexibility we want in a new architecture, to "cut the strings" and not have legacy-code to support. 118 | 119 | It will require a major version release of Umbraco CMS. 120 | 121 | ## Alternatives 122 | **We could just pick a framework and build everything in that** 123 | While this might initially make it easier for everyone, it would likely put us in the same place in the future. Also, this would mean we have to do all the work up front, with no clear benefit for other products. 124 | 125 | **We could do a more incremental upgrade and have adapters/bridges providing some backwards compatibility** 126 | This would result in a larger project scope and we would eventually either be stuck maintaining the bridge/adapter or having to break everything later. This won’t allow us to get the cleanup or architectural freedom we want. 127 | 128 | **We could stick with AngularJS - it works and won’t stop working. Or just wait some more...** 129 | It’s not really a solution. We get further and further away from the “hype-train” and new developers will have to learn something “only” for Umbraco. It is already an argument against Umbraco. This compares to staying on the ASP .NET framework. The longer we wait, the longer we have to maintain potential issues in angularJS ourselves (after December, 2021). 130 | 131 | ## Out of Scope 132 | This RFC describes the project structure/process and that’s what we would like to discuss. There will be detailed RFCs for each part of the process. 133 | 134 | Any discussion about specific technologies is out of scope for this RFC. That will be appropriate in the individual RFCs, as they are specific to each part. Use of TypeScript can be debated here, as it spans all three parts! 135 | 136 | No new features will be added when rebuilding backoffice, as we aim to keep the same feature set as latest v8. This can be discussed but not any specific new features. 137 | 138 | ## Unresolved Issues 139 | The answers that we are hoping to get from the community & Umbraco HQ is: 140 | 141 | - Validating the overall approach for future-proofing Umbraco’s backoffice 142 | - Any obstacles/issues that need to be taken into account either for the overall process or for RFCs for the individual parts. 143 | - How to approach migration of packages. What can be done to ease the process while maintaining the ability to define a new API and rebuild the backoffice. 144 | 145 | ## Related RFCs 146 | - Previous RFC about [Future of the Back-Office Front-End](https://github.com/umbraco/rfcs/pull/8). Many ideas from the current RFC surfaced in this previous RFC, especially the description of motivation and benefits/opportunities have been influential. 147 | - The main differences are around the proposed process and approach. 148 | 149 | ## Contributors 150 | This RFC was compiled by: 151 | 152 | * Filip Bech-Larsen (Umbraco HQ) 153 | * Niels Lyngsø (Umbraco HQ) 154 | * Rune Strand (Umbraco HQ) 155 | -------------------------------------------------------------------------------- /cms/0022-ui-library.md: -------------------------------------------------------------------------------- 1 | # UI Component Library 2 | Request for Contribution (RFC) 0022 : UI Component Library 3 | 4 | ## Code of conduct 5 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 6 | 7 | ## Intended Audience 8 | The intended audience for this RFC is: technical users, developers and package authors 9 | 10 | ## Summary 11 | We want to ensure a coherent experience for both Content Editors and Developers across products and extensions of these. By separating the essential user interface components from any specific project we ensure usage and maintenance of these will stay as straightforward as possible, making the life of maintainers, contributors, and package developers easier. 12 | 13 | The UI Library is a central source of visual building blocks for Umbraco applications and extensions of such. 14 | 15 | Sharing improvements and ensuring the functionality for a component fits in the bigger perspective and not just solving an immediate need. 16 | 17 | The UI Library will serve as a component guide and come with a browser application (Storybook) in which developers can view, try out and learn about the available components. 18 | 19 | The UI Component library will be a separate Open Source Project with source code on Github and distributed via NPM. 20 | 21 | 22 | ## Motivation 23 | We want to ease the development process of the Umbraco backoffice and packages for it. A UI component library will lower the learning curve and make it easy for developers to get an overview of components and their purposes. 24 | 25 | This overview will also help to design a consistent product experience. By easing the process of identifying components, their role, and their relationships. 26 | 27 | The UI Library is a standalone project, which can be used in multiple projects, including third-party. 28 | The components of the UI Library will be based on web standards and will work in any project. 29 | 30 | The library provides a workspace for developing UI components, enabling us to work on UI without being bound to a specific technology. Initially, we will use this to create components for the future backoffice without relying on any framework decisions. 31 | 32 | We want to ensure that our core UI Components serve a general-purpose. Having them developed separately from any specific project will help ensure the scope of the components keep the right level of abstraction for reusability across projects, extensions, and packages. 33 | 34 | The workspace will enable us to ensure a set of requirements of each component, for example making accessibility a first-class citizen. 35 | 36 | ## Out of Scope 37 | - **Technology/framework** for Umbraco’s backoffice 38 | - **How components are used in the backoffice**: The usage examples in this RFC are examples of how this could be done but not settled. 39 | - **Umbraco Design System** It's our intention to provide the parts necessary for package developers to follow the Umbraco style, but this will not be part of this project. 40 | - **No specific purpose** We want to ensure any product can use this Library, therefore we do not want this to be specific towards the backoffice or any other usages. 41 | 42 | 43 | ## Detailed Design 44 | 45 | For the choice of technology for our UI components, we want to stay as close to native browser technologies as possible. Therefore Web Components is our choice. The components should work in any other tech stack to achieve this it must not have any external technology requirements. 46 | 47 | The components should only contain presentational logic, not any application logic, this architectural choice ensures that the components will never mess up the logic of a project. The only purpose they serve is as visual building blocks. This ensures a clear boundary between the responsibilities of the UI Library and the project using this. Making project code much simpler as the interface code is sealed within the UI Library components. 48 | 49 | We do not want to reinvent the wheel and therefore we have settled for using Google’s LitElement to handle the common needs for building Web Components. It is extremely lightweight and broadly used in design-systems at companies like IBM, Adobe, and others. 50 | 51 | To ensure high-quality code we use TypeScript. This will help ensure consistent and solid code for developers of components. It's optional to use TypeScript as an implementer (i.e. when using components in a project). For those that do use TypeScript, there will be definitions to enable intellisense in IDEs, making it easier to discover and implement the components correctly. 52 | 53 | The project will be published on NPM, to enable ease of use and developers without .Net knowledge. The library will ship with the backoffice, meaning that backoffice packages will not require the use of NPM. 54 | 55 | For the presentation of the components, we will use [Storybook](https://storybook.js.org/) as it’s used widely and supports Web Components. Storybook enables use to document and demonstrate each component, with the ability to interact with the component and explore the configuration options. 56 | 57 | Storybook also enables us to write a story for a component before it has been developed, in this way it becomes a communication tool that enables us to share the ideas and scopes of components before development has started. 58 | We intend to have the parts specific for Storybook as automated as possible to keep maintenance of Storybook as little as possible. Configuration options for components should propagate from Type definitions, code comments etc. 59 | 60 | 61 | ### Lit-element 62 | We want to use Lit-Element to provide helpers for managing the basics of Web Components. 63 | 64 | [![Screenshot 2021-03-05 115426](https://user-images.githubusercontent.com/3663619/110106176-a3717980-7da9-11eb-8ead-f0ef36ac33b0.jpg)](https://www.youtube.com/watch?v=ADgo_JVK02A) 65 | *To suit you with the base knowledge of what Web Components and Lit-Element does, we had Filip make an [introduction video](https://www.youtube.com/watch?v=ADgo_JVK02A). We recommend you to watch this if you are interested in the code behind the components.* 66 | 67 | We have highlighted the two most impactful parts of Lit-Element here: 68 | 69 | #### HTML and CSS Template Literals 70 | Lit-Element provides HTML and CSS Template Literal Tags which smoothens the experience when writing web component templates. This enables us to set component properties, add event listeners, and much more. 71 | 72 | ``` 73 | html` 74 | 75 | ` 76 | ``` 77 | 78 | Notice how properties are bound by inserting a dot in front of the property name. Similarly, we can listen for events by using the @ symbol in front of any event name. 79 | 80 | #### Property-Decorators 81 | Property-Decorators simplifies the initialization of web-component properties. 82 | Most commonly used is @property(), which will make a property reactive, meaning that the element will rerender when the value is changed. 83 | 84 | @property() also enables us to turn a property into an element attribute, by turning on reflection the value of the attribute will be synchronized. Which is a great way to make styling based on the state of a property. 85 | 86 | [Read more about Lit-Element property decorators here](https://lit-element.polymer-project.org/guide/properties#declare-with-decorators) 87 | 88 | ### Styling 89 | 90 | As the web components will be using Shadow DOM, the styling of these can stay fairly simple as they are fully isolated from each other. We don't intend to use any preprocessor framework for this at the current state. 91 | The UI Library will host a set of CSS custom properties, which will be used for styling its components. These properties will also be available for any project implementing the UI Library. 92 | 93 | Additionally, we will use custom properties for the style-values of a component that we want to enable developers to change. Custom Properties inherits through the DOM and ShadowDOMs which enables a property to be overridden for a certain part of the application without affecting other parts. 94 | 95 | This means it would be possible to overwrite the background-color of `` by defining the custom property “--uui-button-background”, like this “--uui-button-background: red;” 96 | 97 | Common styling cases should be available through attributes of components. To exemplify this, let's have a look at the UUI-Button component: 98 | 99 | `Click me` 100 | 101 | This component will in many cases need to be styled to stand out visually or communicate its effect. 102 | For a delete button we would apply the danger-style through the `look` attribute: 103 | 104 | `Delete` 105 | 106 | 107 | #### Theming 108 | 109 | We will enable a limited set of color and sizing customization options, based on CSS Custom Properties. This is mainly to enable a high-contrast mode for accessibility purposes. 110 | 111 | 112 | #### Parts 113 | 114 | CSS-parts is also one of the features of Web Components that can be used to overwrite certain styling of a Web Component. Currently, we do not have any case where this provides any reasonable value. But we will consider enabling this when it makes sense. 115 | 116 | ### A few notes on architecture 117 | 118 | #### Tag-Names 119 | All elements of this library should be prefixed with “UUI-”. This prefix will ensure that Elements from the UI Component Library will differ from specific project Elements and be different from the umb-directives from current backoffice. See the following example of an element from the CMS and two from the library: 120 | 121 | ``` 122 | 123 | 124 | 125 | 126 | 127 | ``` 128 | 129 | To enable component versioning at a later stage: No code should depend on TagNames of library elements, neither their own nor any of its children. This means when querying or writing CSS selectors we must use `:host`, `this` or use classes/IDs. The reason for this is to enable component versioning at one point. 130 | 131 | #### Use attributes for styling 132 | 133 | When styles are derived from the state of a property, they should be turned into an attribute with reflection. 134 | In this way, we can use CSS Selectors for the attribute rather than mapping values to CSS classes. Example: 135 | 136 | Component CSS: 137 | 138 | ``` 139 | :host([disabled]) { 140 | /* styling specific to the disabled state */ 141 | } 142 | ``` 143 | 144 | Component usage via attribute: 145 | `````` 146 | 147 | Component usage via property: 148 | `````` 149 | 150 | 151 | #### Slots 152 | 153 | Web Components allows the use of Slots, which enables implementers to inject markup into one or more selected slots. This enables us to make compositions of components, simplifying each component as they can stay true to their own responsibility. 154 | 155 | Enabling us to make very simple base components and extend those for specific needs. 156 | 157 | This can be exemplified by the dialog component. It will just serve as a visual frame for any dialog-content. The dialog will provide the base for specific usages of the dialog. This could be the confirm-dialog component which will accept a few properties: headline, description, confirm-label. When a different case is needed this can be built upon the dialog-component, helping us avoid bloated components. 158 | 159 | #### Events 160 | 161 | To make Events propagate outside the scope of a Web Component we have created a base Event class, called UUIEvent. For any custom events, we recommend extending this class to make a proper typed Event for the given Component. 162 | 163 | Events should only hold data if there is specific data for the event. If developers need data of the state of the component they should retrieve this from the element, eventually through `event.target`. 164 | 165 | ### Workflow 166 | 167 | #### Contribution process 168 | 169 | When contributing to the library it should be submitted as a PR to the library. 170 | PR specific for adding a new Element will first be accepted(merged) when it lives up to these criteria: 171 | 172 | - Element name must be prefixed with “UUI-” 173 | - Elements must have tests and pass those 174 | - Elements must pass the basic accessibility test 175 | - Elements must be represented through a story in Storybook 176 | - Elements must follow the Umbraco look and feel 177 | - Source-code must follow the ES-lint rules 178 | 179 | #### Publishing and versioning 180 | We intend for the UI Library to have independent semantic versioning and rapid releases through CI/CD. Releases will automatically be available on NPM. 181 | 182 | ### Documentation 183 | We intend to make documentation auto-generated from component source code. Via TypeScript and JS-docs. 184 | 185 | ### Usage 186 | Any project can implement and use components of the UI Library. A project can combine this with their own components. 187 | 188 | ###Demo 189 | 190 | To get some context to this concept we have already implemented a prototype, which you can try out today. 191 | 192 | [Find the repository here](https://github.com/umbraco/Umbraco.UI.RFCDemo) 193 | 194 | Read `readme.md` for a guide on how to get the project up and running. 195 | 196 | If you like to view the solution without building it by yourself, [we hosted the demo here.](https://umbraco.github.io/Umbraco.UI.RFCDemoStatic) 197 | 198 | [![Screenshot 2021-03-05 114326](https://user-images.githubusercontent.com/3663619/110105188-5f31a980-7da8-11eb-9063-c358d4a381ac.jpg)](https://www.youtube.com/watch?v=yb41HCdvjFE) 199 | *If you like a brief introduction, please watch this video where Niels Lyngsø shows the solution and presents some of the thoughts behind the code. [Available on YouTube here](https://www.youtube.com/watch?v=yb41HCdvjFE)* 200 | 201 | ### Contributions 202 | 203 | After the RFC is accepted we would love code contributions to the repository. For now, we would love to focus on the RFC. 204 | 205 | 206 | ## Drawbacks 207 | There is an added complexity as a result of separating the UI Components from the CMS Project. 208 | 209 | ## Alternatives 210 | ***We could build our UI Library in VueJS or any other framework.*** 211 | 212 | Developing the UI components without a framework enables us to incorporate them in any other project, and it enables projects to evolve without changing the UI Library, as the UI Library does not rely on any specifics regarding project implementations. 213 | 214 | ***VueJS*** 215 | 216 | We know VueJS is popular among many of our community members, but we do not see any benefits in using a specific framework for the scope of the Component Library. Staying with native technology will enable the library to be used in multiple contexts. 217 | 218 | ***Use Tailwind for styling UI Components in the UI Library*** 219 | 220 | We do not see any gains by enforcing contributors to learn Tailwind, the benefits of Tailwind are strongest when styles are applied for one DOM with no style encapsulations, in this project we do not have any shared classes across components. If so they will be purposely imported for the given cases. 221 | 222 | ***Use an existing UI Library*** 223 | 224 | There are many libraries out there that can solve our needs for basic UI components. There are none that deal with Umbraco-specific use cases. In order for us to have, as simple as possible, native Umbraco UI that deals with Nodes, Media, Trees, etc. We need to own the code ourselves. We expect to use parts from existing libraries in cases where it makes sense. (i.e. incorporating a third party DatePicker) 225 | 226 | ***Element name prefix*** 227 | 228 | In regards to choosing the prefix for element names ("") 229 | We have considered other and shorter prefixes (u-, ui-, umb-) but uui- still looks like the best option in order to avoid potential collisions. We see many other UI Libraries using a single letter or a very short prefix and we want enable usage of such libraries. The use of "umb-" would collide with existing backOffice elements. 230 | 231 | 232 | ## Unresolved Issues 233 | - Is this approach understandable? 234 | - Are there aspects of this approach missing? 235 | - Where is the line drawn between specific project components and UI Library components? 236 | 237 | 238 | ## Related RFCs 239 | - Overall process RFC about [Future-proofing the Umbraco backoffice](https://github.com/umbraco/rfcs/blob/main/cms/0021-future-proofing-the-umbraco-backoffice.md). 240 | 241 | ## Contributors 242 | This RFC was compiled by: 243 | 244 | * Niels Lyngsø (Umbraco HQ) 245 | * Filip Bech-Larsen (Umbraco HQ) 246 | * Mads Rasmussen (Umbraco HQ) 247 | * Julia Gruszczynska (Umbraco HQ) 248 | * Rune Strand (Umbraco HQ) 249 | 250 | 251 | -------------------------------------------------------------------------------- /cms/0024-implement-the-new-backoffice.md: -------------------------------------------------------------------------------- 1 | # Implement The New Backoffice 2 | 3 | ### Request for Comments (RFC) 0024: Implement The New Backoffice 4 | 5 | ## Code of Conduct 6 | 7 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md). 8 | 9 | ## Intended Audience 10 | 11 | The intended audience for this RFC is 12 | 13 | - Technical users 14 | - Developers 15 | - Extension developers 16 | - Package authors 17 | 18 | ## Summary 19 | 20 | To future-proof Umbraco’s backoffice, we intend to run a three-part process - each with an RFC: 21 | 22 | 1. Standalone UI Component library (RFC accepted January 2021) 23 | 2. Defining backoffice extension API (RFC accepted December 2021) 24 | 3. Implement the new backoffice (This RFC) 25 | 26 | It can be helpful to watch this [umbracoCoffee episode](https://youtu.be/i0QfgRYj0zQ?t=1681) where Filip Bruun Bech-Larsen, CTO for Umbraco, introduces the concept. 27 | 28 | ## Motivation 29 | 30 | Umbraco’s backoffice is a big reason why editors AND developers choose Umbraco. It is easy to use and flexible to customize to the specific needs of a project/client 31 | 32 | The current (second) generation backoffice is built using AngularJS. It was a great choice in 2013, and has served us well, but has long been considered outdated. Since December 31, 2021, AngularJS has reached its [end-of-life state](https://blog.angular.io/discontinued-long-term-support-for-angularjs-cc066b82e65a). 33 | 34 | Since 2012 we have learned a lot about building a complex Single Page Application (SPA). The current situation does not allow us (or makes it hard) to fix things we have done inherently wrong. The current state is holding development - and excitement - back. 35 | 36 | With the next generation of Umbraco’s backoffice, we want to bring several benefits to Umbraco, namely: 37 | 38 | - Speed up the maintenance and future development of the backoffice for Umbraco HQ and community developers alike 39 | - The code will utilize TypeScript and accompanying types in the high-seat 40 | - 3rd-party integrations will be considered as first-class citizens 41 | - Make Umbraco more attractive for new contributors, by using modern technology and methodology - thereby also making it easier to contribute 42 | - Simplify and speed up work for developers and package authors, by enhancing the ability to create great UI/UX 43 | - Streamline the experience throughout the entire journey incl. 1st- and 3rd-party packages, Cloud, etc. 44 | - Reuse work across our products for less development but also for improvements to be distributed 45 | - Maintain market leadership in a customizable editing experience (tailored to clients) 46 | 47 | ## Detailed Design 48 | 49 | ### Building the application 50 | 51 | #### Single-Page Application 52 | 53 | As with the old backoffice, the new backoffice will be built as a single-page application. In addition to being served solely in the browser, the new backoffice will also be built as a true standalone application meaning that it can be hosted anywhere since it only requires a browser and a file host to run. No server-side rendering will be required to run the backoffice application. 54 | 55 | #### Routing 56 | 57 | In single-page applications routing is usually a non-trivial area. We are looking into what routers are available at the moment. We need something for the application that can handle both top-level routing and deep-level nesting so that each section, content app, infinite editor, tab, and so on, can push a state to either the URL, the browser history, or both. It should also be possible for any frontend extension to register its own set of routes enabling anyone to deep-link into an extension subarea. 58 | 59 | #### Web Components 60 | 61 | We are going to use a standards-based way to build our custom UI as close to modern browser conventions and technology as possible. We have considered many options - libraries and frameworks alike - and have concluded that we would like to avoid falling into another technical grave in the years to come when what we choose now becomes obsolete. 62 | 63 | > _When you're working with the browser rather than against it, code, skills, and knowledge remain relevant for a longer time. Development becomes faster and debugging is easier because there are fewer layers of abstractions involved._ — [modern-web.dev](https://modern-web.dev/discover/about/) 64 | 65 | We have a firm belief that sticking with the browser standards will continue to evolve and benefit us in the years to come. Therefore we have chosen to build the new backoffice UI with [Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components). 66 | 67 | JavaScript frameworks are all doing essentially the same thing: Producing custom elements with syntactic sugar, and also added benefits of having built-in routers, state machines, and stores. The concept of Web Components is created such that the browsers natively support all the things we love from libraries such as React and Vue including having custom elements, reactivity, and state. It allows us to create the most optimal setup and environment for the backoffice to ship modern, slim, chunked modules for the UI. It also allows us to choose whatever libraries we like for state management, routing, and observability. 68 | 69 | Building our software with Web Components - a native web standard - ensures that our software works and will keep working for at least a longer period than any external library will. The APIs will keep getting updated along with the browser itself, patching any security vulnerability along the way. 70 | 71 | ##### Boilerplating 72 | 73 | Web Components require a lot of boilerplate in their current state, so to speed up development, we are going to work with a very efficient, [tiny library called Lit](https://lit.dev/). This library has helped us tremendously in building the [Umbraco UI Library](https://github.com/umbraco/Umbraco.UI) and is also now serving parts of the [Umbraco Cloud portal](https://umbraco.com/products/umbraco-cloud/). Choosing Lit also has the added benefit of being able to share tech and collaborate throughout Umbraco HQ. 74 | 75 | A component for the new backoffice can be built with only a few lines of code: 76 | 77 | ```ts 78 | import { html, css, LitElement } from "lit"; 79 | import { customElement, property } from "lit/decorators.js"; 80 | 81 | @customElement("my-simple-greeting") 82 | export class SimpleGreeting extends LitElement { 83 | static styles = css` 84 | p { 85 | color: blue; 86 | } 87 | `; 88 | 89 | @property() 90 | name = "Somebody"; 91 | 92 | render() { 93 | return html`

Hello, ${this.name}!

`; 94 | } 95 | } 96 | ``` 97 | 98 | Incidentally, Web Components and Lit take care of most of the stuff we know from AngularJS, such as the concept of "components" and data binding. Running through a data set is fairly easy with Lit's template interpolation with native JavaScript, we can accomplish this in a much cleaner way than AngularJS ever did, where you had two-way data binding. Two-way data binding is, however, something that only AngularJS supported and is not something you would use today. Instead, the flow would be: input = data, output = events. 99 | 100 | ```mermaid 101 | flowchart 102 | ParentComponent -- data in through attributes --> ChildComponent 103 | ChildComponent -- events out through an emitter --> ParentComponent 104 | ``` 105 | 106 | Although we have chosen Lit and TypeScript to build the new backoffice, developers are free to use any framework and libraries of their choice to implement backoffice extensions. We will be building an extension API that is framework agnostic as stated in an [earlier RFC](https://github.com/umbraco/rfcs/blob/main/cms/0023-define-the-backoffice-extension-api.md#detailed-design). 107 | 108 | Please have a look at [Lit’s excellent playground](https://lit.dev/playground/) to learn more about it. 109 | 110 | #### Umbraco UI Library 111 | 112 | We have built a UI Library that will serve as a great base for the backoffice (and some of our other products). Using the Umbraco UI Library provides us with custom-made components needed for the backoffice UI. This means the code for composing UI will be as little as possible. Additionally, we can extend components of the UI Library to make special parts for the backoffice or extensions. 113 | 114 | #### Build setup 115 | 116 | A lot of tools come with the territory when building a modern web application. With the choice of Lit and TypeScript, we need something to help us compile/transpile TypeScript code, bundle everything together in small chunks, and remove any code that is not in use from libraries, etc. 117 | 118 | Many setups exist today with support for Lit and TypeScript. We especially like the premise of [esbuild](https://esbuild.github.io/) to transpile the code due to its swiftness and lightness. For tree shaking and splitting, we like what [Rollup](https://rollupjs.org/) has done in terms of supporting esbuild. However, managing the configuration of these and keeping them up-to-date is not a task that we want to spend too much time on. Therefore we have chosen to use [Vite.js](https://vitejs.dev/) to handle everything related to the development and build processes, including running the entire application in a development mode when building it as well as creating the production build. Vite uses Rollup underneath the surface and it also exposes the underlying configuration if we need to change something, but all-in-all it abstracts the whole process away to ensure that we are always running the most optimal setup. 119 | 120 | The development flow of the new backoffice will simply consist of cloning down the repository, installing the npm dependencies, running Vite, and a browser will launch immediately supporting live reload and debugging: 121 | 122 | ```bash 123 | git clone ​​git@github.com:umbraco/Umbraco.CMS.Backoffice.git 124 | cd Umbraco.CMS.Backoffice 125 | npm install 126 | npm run dev 127 | ``` 128 | 129 | ### Extension API 130 | 131 | With the old backoffice, it was possible to expose the entire AngularJS API globally enabling extension developers to not only use built-in components but also create their own on the same runtime as the backoffice. In addition to AngularJS, we also ship the old backoffice with other globals such as Underscore, jQuery, SignalR, and many more. 132 | 133 | With modern web development, it is customary to run the code through both a minification and a tree-shaking process and even split the code into chunks to avoid loading the entire application initially. This process also puts all dependencies into their own scope, preventing them from leaking and/or being used outside by other bundles such as extensions loaded dynamically unless the dependencies are specifically exposed. 134 | 135 | Initially, we will not expose anything, because the combined bundled versions of our tools like Lit and others are rather large and do not necessarily support being exposed at all. This means that extensions will not be able to hook onto most of the underlying libraries of the backoffice. Instead, extensions will have to provide their dependencies and run them through a tree-shaking process with tools like Rollup. However, we are looking to see if some tools could benefit from being provided globally - provided that they come with a universal module that runs in the browser. We expect that the overhead of overlapping dependencies between the backoffice and extensions will be very small, but a lot of upcoming features such as [import maps](https://github.com/WICG/import-maps) will be interesting to look into to solve that particular drawback. 136 | 137 | The recommendation to extension developers is that they also choose Lit and TypeScript. To help them do all of that, we are planning to release a helper tool that will allow developers to start building extensions against the new extension API. The tool will bootstrap their development in such a way that they get up and running very quickly and can start writing code. 138 | 139 | There are several ways to go about building extensions for the new backoffice and this tool will cover a few ways of doing so, both for developers wanting to start with TypeScript and Lit, and for those wanting to start with HTML and vanilla JavaScript. The tool could come in the form of either a dotnet template (adding to [the existing templates](https://www.nuget.org/packages/Umbraco.Templates)) or an npm package, and could be invoked like this: 140 | 141 | **Dotnet:** 142 | 143 | ```bash 144 | dotnet new --install Umbraco.Templates 145 | dotnet new umbracopackage --name MyPropertyEditor --type propertyeditor 146 | ``` 147 | 148 | **NPM:** 149 | 150 | ```bash 151 | npm create @umbraco/package --name MyPropertyEditor --type propertyeditor 152 | ``` 153 | 154 | #### Typings 155 | 156 | The new backoffice will ship with [TypeScript declaration files](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html), either physically or in a [Definitely Typed](https://github.com/DefinitelyTyped/DefinitelyTyped) package, for all relevant components enabling TypeScript as a first-class citizen for Web API interaction with both request and response types, JavaScript runtime services through the Context API, Umbraco backoffice components and UI Library components. 157 | 158 | #### Context API 159 | 160 | To provide contextual shared logic we have established a system called Context API. This is an event-based protocol that components can use to retrieve context from any location in the DOM. A context is an instance of a class that is provided to a certain scope of the DOM. 161 | 162 | The Context API consists of two parts: A Context Provider and a Context Consumer. 163 | 164 | The following example shows how to provide context (in this instance it is a service) for other components to consume: 165 | 166 | ```ts 167 | import { UmbContextProviderMixin } from "@umbraco/context"; 168 | 169 | // Create a class that extends from the context PROVIDER mixin, which gives you access to the provideContext method 170 | class UmbAppElement extends UmbContextProviderMixin(HTMLElement) { 171 | constructor() { 172 | super(); 173 | 174 | // Provide anything you like here and send it downstream in the DOM tree 175 | this.provideContext("myContextAPIService", new MyContextAPIService()); 176 | } 177 | } 178 | ``` 179 | 180 | And the context service is then requested through the consumer, which has a handy mixin to extend the component from: 181 | 182 | ```ts 183 | import { UmbContextConsumerMixin } from "@umbraco/context"; 184 | 185 | // Create a class that extends from the context CONSUMER mixin, which gives you the consumeContext method 186 | class UmbMyElement extends UmbContextConsumerMixin(HTMLElement) { 187 | constructor() { 188 | super(); 189 | 190 | // Request anything you like here such as the myContextAPIService that was provided above 191 | this.consumeContext("myContextAPIService", (api) => { 192 | const myContextApi = api; 193 | 194 | // Invoke a method on the provided service 195 | myContextApi.fooBar(); 196 | }); 197 | } 198 | } 199 | ``` 200 | 201 | #### Styling 202 | 203 | We recommend initiating Web Components with ShadowDOM, and this is always the case when using Lit. 204 | 205 | ShadowDOM encapsulates the insides of a Web Component which means no CSS classes will be available nor will any of the styling interfere with the backoffice. 206 | 207 | Style selectors can be much simpler and separated for each component. The styling (CSS) of a Web Component is provided inline in the JavaScript code by a static `styles` property: 208 | 209 | ```ts 210 | import { LitElement, css, html } from "lit"; 211 | 212 | export class MyStylingExampleElement extends LitElement { 213 | static styles = css` 214 | p { 215 | color: darkgrey; 216 | } 217 | div { 218 | border: 1px solid green; 219 | color: green; 220 | padding: 6px; 221 | } 222 | `; 223 | 224 | render() { 225 | return html` 226 |

Hello world

227 |
My styles are just for my template
228 | This component contains its own styling 231 | `; 232 | } 233 | } 234 | ``` 235 | 236 | The Umbraco UI Library will be available for extensions and this lays the foundation for the UI of extensions. If the available UI components do not cover the specific needs on their own, then styling can be based on the CSS Custom Properties provided by the UI Library (example: `--uui-color-text`) 237 | 238 | Read more about the currently available custom properties here: [Sizing Custom-Properties](https://uui.umbraco.com/?path=/story/design-custom-properties--sizing) and [Color Custom-Properties](https://uui.umbraco.com/?path=/story/design-custom-properties--interface-colors) 239 | 240 | Using the provided CSS Custom Properties will ensure that the UI looks right cascading down in the DOM without affecting any backoffice UI: 241 | 242 | ```ts 243 | import { LitElement, css, html } from "lit"; 244 | 245 | export class MyStylingExampleElement extends LitElement { 246 | static styles = css` 247 | p { 248 | color: var(--uui-color-text-alt); 249 | } 250 | div { 251 | border: 1px solid var(--uui-color-positive-standalone); 252 | color: var(--uui-color-positive-standalone); 253 | padding: var(--uui-size-space-2); 254 | } 255 | `; 256 | 257 | render() { 258 | return html` 259 |

Hello world

260 |
My styles are just for my template
261 | This component contains its own styling 264 | `; 265 | } 266 | } 267 | ``` 268 | 269 | We recommend using Web Components with ShadowDOM for each component of your extension. Extension developers are free to structure their extensions as desired, and as long as the root element uses a ShadowDOM you can use any tech of choice. 270 | 271 | ### Backoffice Web API 272 | 273 | We are taking the opportunity to create new controllers for the web API during this project. In recent years, a lot of business logic has been moved to a service layer in the backend of Umbraco CMS making the controllers focus only on authentication and creating models around the data. 274 | 275 | #### Authentication 276 | 277 | The controllers for the old backoffice relied on cookie authentication, but this is quickly becoming outdated and can be problematic in a multi-tenancy setup where the backoffice frontend and server do not use the same hostname. We want to adopt the OAuth 2.0 protocol with OpenID Connect for authentication and authorization beginning with the new backoffice. This approach will also allow server-to-server authentication down the road using app tokens and/or having a concept of authorized apps. 278 | 279 | #### Taking a schema-first approach 280 | 281 | When rewriting all the controllers, it is also the perfect time to adopt another paradigm: Schema-first. For each endpoint and model, we are going to describe it in an OpenAPI 3.0 schema (sometimes also known as Swagger) first before implementing it using commonly available tools for the .NET backend and the TypeScript frontend. 282 | 283 | This becomes especially handy for TypeScript, where it will allow us to swiftly convert the schema to several interfaces and then using something like [openapi-typescript-fetch](https://github.com/ajaishankar/openapi-typescript-fetch#readme), we can quickly set up fetchers for getting the data in a type-safe way: 284 | 285 | ```ts 286 | import { paths } from "./schema"; 287 | import { Fetcher } from "openapi-typescript-fetch"; 288 | 289 | // First we generate a HTTP fetcher (using Fetch) from the generated schema 290 | const fetcher = Fetcher.for(); 291 | 292 | // We assign one of the paths (content-by-id) to a constant which makes it type-strong 293 | const getContentById = fetcher.path("/content/{id}").method("get").create(); 294 | 295 | // Try and get the data (error codes are not thrown as exceptions but will have to be read from the response 296 | try { 297 | const { data } = await getContentById({ id: 1 }); 298 | 299 | // If the data is truthy we know we got the content 300 | if (data) { 301 | console.log("node", data); 302 | 303 | // If the data is not truthy perhaps the data did not exist 304 | } else { 305 | console.log("node does not exist"); 306 | } 307 | 308 | // If we land in the catcher, something went wrong with the connection or perhaps the endpoint did not exist 309 | } catch (e) { 310 | console.log("error", e); 311 | } 312 | ``` 313 | 314 | ### Documentation 315 | 316 | Documentation for the new backoffice should be explorative, interactive, and as much as possible auto-generated. We want to provide a combined backoffice and UI Library documentation to enable developers to find the relevant details of interest with ease. Therefore we will use Storybook just as the UI Library does, enabling us to merge the two and present combined documentation for the backoffice. 317 | 318 | The documentation should be versioned so users can get the documentation for the specific version of interest. This will replace what we today know as [ApiDocs](https://apidocs.umbraco.com/v9/ui#/api). 319 | 320 | All frontend-related documentation on [our.umbraco.com](https://our.umbraco.com/documentation/) will have to be rewritten. Ideally, code examples will originate from backoffice documentation and thereby be auto-generated. 321 | 322 | ### Testing 323 | 324 | It should be as simple as issuing the command `npm test` to run all tests, and there is going to be a way to get test coverage reports in various formats. 325 | 326 | The old backoffice has a set of unit tests using Karma and a set of acceptance tests using Cypress for the UI. The acceptance tests for the old backoffice will be converted to [Playwright](https://playwright.dev/) in the future and we will try to transfer that work to the new backoffice project, and use it for both unit and end-to-end testing. 327 | 328 | Traditional tools are not designed for piercing the Shadow DOM of Web Components, but this is where Playwright becomes especially handy since it by default looks through an arbitrary number of open shadow roots when selecting elements. 329 | 330 | ### Security & Updates 331 | 332 | Security is an ever present thing to consider: Any external library that we install must be maintained and updated regularly whenever a security patch is released following a CVE or otherwise. This is more easily done on an auto-updated product such as a SaaS product, but with Umbraco CMS being an installed product, we do not have that luxury. As an example, Umbraco 7 was released in 2013 using the new-at-the-time AngularJS framework. This framework is now considered end-of-life as of January 2022 and will no longer receive updates. 333 | 334 | We will strive to maintain the security of the backoffice and the UI Library by using tools such as GitHub's Dependabot to automatically keep the backoffice and UI Library up to date and [CodeQL](https://codeql.github.com/) to catch low-hanging fruit before any code is merged. We will also try to lock down the versions of the various third-party libraries to a specific version so that we may vet any updates before they are applied. 335 | 336 | ## Moving forward 337 | 338 | ### What is going to happen? 339 | 340 | The new backoffice will be shipped in a major version of Umbraco CMS as yet to be determined and the old backoffice will be marked as deprecated in the major version leading up to that one. 341 | 342 | ### GitHub 343 | 344 | The development of the new backoffice will happen in its own GitHub repository to not pollute the main repository of the CMS. This allows us to make sure that we separate all concerns from the backend/C# code. The repository will be made open to the public allowing everyone to follow the project from infancy to completion. When it is finished, we will include it in Umbraco CMS either as seen today, where it is simply included as a web project, or it will be installed during the build step as a submodule or downloaded from somewhere like NuGet. 345 | 346 | ### Property editors and data types 347 | 348 | There are a lot of Property Editors and Data Types built into the old backoffice. Most of these will be migrated to the new backoffice using the same aliases. 349 | 350 | #### Media Picker (Legacy) 351 | 352 | The Media Picker Property Editor has been marked as legacy/deprecated for some time and this editor will not be migrated to the new backoffice. Instead, the new Media Picker, [introduced in Umbraco 8.14](https://umbraco.com/blog/umbraco-814-release/#mediapicker), will be the only one available. 353 | 354 | #### Nested Content 355 | 356 | We do not plan to migrate the Nested Content Property Editor to the new backoffice because the Block List editor supports similar data structures and editing experience. We expect that Nested Content will be marked as a legacy in one of the upcoming major versions of the CMS. Instead, we will see if and how the Block List type can be improved going forward. 357 | 358 | #### Grid Layout 359 | 360 | We do not plan to migrate the Grid Layout Property Editor. The future of Umbraco points towards using Element Types (just like the Block List Property Editor) and the Grid Layout editor does not support this natively. We are currently investigating what a new block-based grid editor will look like. 361 | 362 | #### Rich Text Editor 363 | 364 | We do not plan to keep on using the current version of [TinyMCE](https://github.com/tinymce/tinymce) in the new backoffice. Instead, we will see how the Rich Text Editor can be improved going forward using either the newest version of TinyMCE or something else entirely. 365 | 366 | #### Pre-Configured Data Types 367 | 368 | There are a lot of different Data Types in the old backoffice, and frankly, some of them have been unused for a long time. We are going to comb through the existing ones during this project to see what makes sense to have in the new backoffice. 369 | 370 | ## Drawbacks 371 | 372 | This will be a complete breaking change of the backoffice as a piece of software. It will also disrupt all existing packages that add backoffice elements. They will need to update to the new extension API as discussed with the [RFC #0023](https://github.com/umbraco/rfcs/blob/main/cms/0023-define-the-backoffice-extension-api.md), and they will have to update the UI to use the Umbraco UI Library. 373 | 374 | ## Alternatives 375 | 376 | The main problem to solve is to remove AngularJS. Angular provides something called [Angular Upgrade](https://angular.io/guide/upgrade) which is very extensive. However, upgrading to modern Angular will still give us all of the drawbacks and will not satisfy the wish to become independent of any framework. 377 | 378 | Being independent of any one framework leaves out the possibility of choosing one of the major players in the market such as React or Vue. However, extension developers are free to choose whatever they feel comfortable with for adding functionality to the backoffice. 379 | 380 | A big part of this project is also to reduce and minimize technical debt; a lot of the existing functionality is either duplicated multiple times or written into a service loop where some of the existing AngularJS services do not make sense to have anymore. There is also a varying degree of quality to the existing components in terms of documentation, usability, and accessibility. 381 | 382 | Other alternatives were discussed in [the original RFC for future-proofing the backoffice](https://github.com/umbraco/rfcs/blob/main/cms/0021-future-proofing-the-umbraco-backoffice.md#alternatives). 383 | 384 | ## Out of Scope 385 | 386 | ### Web API 387 | 388 | New Web API controllers will be made available for the new backoffice, however, any technological change on how to build a Web API will be considered out of scope for this RFC and in general, any backend changes to facilitate the new backoffice are out of scope. 389 | 390 | ### Caching 391 | 392 | To have good caching requires a good foundation. We will try to see how we can implement such a foundation that we might support even better caching in the future. We will also try to see how to make user actions such a Save & Publish asynchronous to allow a quicker workflow for editors. To do so, we will implement a series of stores or repositories to manage the data. However, a complete caching solution is considered out-of-scope for this RFC. 393 | 394 | ## Proof of Concept 395 | 396 | We have built a proof-of-concept application along with this RFC. The application can be installed and run on your machine, and you can read the source code freely. The application demonstrates a few things on how to implement the backoffice, namely: 397 | 398 | - How we expect to build the web application 399 | - How we expect to run a test suite 400 | - What is the structure of the application like 401 | - How we expect to handle contexts inside the application 402 | - How we expect extensions to interact with the backoffice and its contexts 403 | 404 | [Check out the dedicated repository right away to get started](https://github.com/umbraco/Umbraco.Backoffice.POC). 405 | 406 | ## Related RFCs 407 | 408 | [#0021 - Future-proofing the backoffice](https://github.com/umbraco/rfcs/blob/main/cms/0021-future-proofing-the-umbraco-backoffice.md) 409 | 410 | [#0022 - UI library](https://github.com/umbraco/rfcs/blob/main/cms/0022-ui-library.md) 411 | 412 | [#0023 - Defining the backoffice extension API ](https://github.com/umbraco/rfcs/blob/main/cms/0023-define-the-backoffice-extension-api.md) 413 | 414 | ## Contributors 415 | 416 | This RFC was compiled by: 417 | 418 | - Jacob Overgaard (Umbraco HQ) 419 | - Mads Rasmussen (Umbraco HQ) 420 | - Niels Lyngsø (Umbraco HQ) 421 | - Jesper Møller Jensen (Umbraco HQ) 422 | - Filip Bruun Bech-Larsen (Umbraco HQ) 423 | - Kenn Jacobsen (Backoffice Community Team) 424 | - Laura Weatherhead (Backoffice Community Team) 425 | - Lee Kelleher (Backoffice Community Team) 426 | - Maud Langaskens (Backoffice Community Team) 427 | - Matt Sutherland (Backoffice Community Team) 428 | - Blake Watt (Backoffice Community Team) 429 | - Paul Sterling (Community) 430 | - Kyle Weems (Community) 431 | - Mark Drake (Community) 432 | - Michael Argentini (Community) 433 | - Dan Diplo (Community) 434 | - Biagio Paruolo (Community) 435 | - Tiffany Prosser (Community) 436 | - PascalIcatt (Community) 437 | -------------------------------------------------------------------------------- /cms/0025-reusable-content-with-global-blocks.md: -------------------------------------------------------------------------------- 1 | # Reusable Content with Global Blocks 2 | 3 | ### Request for Contribution (RFC) 0025 : Reusable Content with Global Blocks 4 | 5 | **Please comment on this RFC in this [RFC Discussion](https://github.com/umbraco/rfcs/discussions/35)** 6 | 7 | ## Code of Conduct 8 | 9 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md). 10 | 11 | ## Intended Audience 12 | 13 | The intended audience for this RFC is 14 | 15 | - Technical users 16 | - Developers 17 | - Package authors 18 | - Editors 19 | 20 | 21 | ## Summary 22 | 23 | We want to create Global Blocks that can be referenced from multiple Block Lists or Block Grids, and we want these to be editable from the Content Section as well as a Global Block tree in a dedicated section. This new section should include "global content that the editor can/should maintain". We propose naming this new section "Library" and include global Blocks, Tags, and Content Templates. Within the Library section, the Global Blocks should be maintained using the same (or similar) conventions and functionality as in the Content Section - e.g. functionality to publish, unpublish, schedule a block, and handle language variations. 24 | 25 | ## Motivation 26 | 27 | Since the very beginning of Umbraco, we have thrived to create a flexible CMS that gives both developers and content editors the freedom to be creative. The introduction of Blocks, via first the Block List editor and later the Block Grid, is one of the concepts that support this journey. As we now have multiple Property Editors using Blocks, we see an opportunity for introducing even more flexibility and making it easier to reuse and maintain Block content specifically, and content in general. 28 | 29 | We believe Global Blocks will help increase flexibility for developers by adding more options for constructing a good editing experience, and for content editors as they can now publish, unpublish and schedule the publishing of Block content. In addition, maintaining a single Global Block will be easier, as you can do it in one place while having the Blocks that are referenced in multiple places, introducing a more streamlined content model which helps the editor be more effective and consistent. 30 | 31 | ## General Design 32 | 33 | Blocks can now be made local or global. Local Blocks work in the same way as current Blocks. Global Blocks can be created and edited in the same way as Local Blocks, or via a new “Library” section. 34 | To facilitate a good experience all Block content, whether it is local or global, will be handled as standard content. This means storing it in the same way in the database, providing similar actions for managing publish state, variants, and so forth. 35 | 36 | ## Detailed Design 37 | 38 | ### Library Section 39 | 40 | We want to offer a section where Global Blocks can be maintained, however, doing this, opens up the question if other types of content are placed the right way today. Global Blocks are by nature something that is not related to a specific page. It's used on multiple pages but that's also the case for tags, and content templates. We, therefore, suggest that the new Library section also includes these types. An example of such a section could look like this: 41 | 42 | ![Library Section](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Library%20-%20clean.jpg?raw=true) 43 | 44 | As seen, we want to introduce a folder structure for the global blocks so that the editor has a way to control the structure. 45 | Also be aware, that while Blocks have both Content and Settings, we only consider the Content part to be Global as we believe the Settings part could benefit from being specific for each usage of a Global Block. We, therefore, don’t plan to show any Settings for blocks in the Library section. 46 | 47 | #### Preview 48 | 49 | As a block will always be shown and styled depending on the content wherein it exists, it will never make sense to try to preview a Block without also choosing a Content Node. The editor should therefore be asked to select the Content Node before an actual preview can be shown: 50 | 51 | ![Library Preview](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Library%20-%20Preview.jpg?raw=true) 52 | 53 | In case a Block has not yet been referenced from any Content Node, a message should be shown to the user, that a Global Block can't be previewed when it's not yet in use on any Content Items. 54 | 55 | #### Info tab 56 | 57 | Like with Content Nodes, we want to show the general status and history, and we also want to show a list of the Content Items where the Block is referenced. That list should include information about the status of the Content Nodes concerning published, unpublished, scheduled, created and latest changes so that the editor can be guided in updating the right content. 58 | 59 | ![Library Info tab](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Library%20-%20info.jpg?raw=true) 60 | 61 | #### Language 62 | 63 | In short, there should be the same opportunities for languages as with Content Nodes - e.g. with split-view and with publishing messages: 64 | 65 | ![Library Info tab](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Library%20-%20language.jpg?raw=true) 66 | 67 | ### Content Section 68 | 69 | We believe that Local Blocks still have relevance on sites, where you want to limit complexity. We, therefore, want to offer a setting on the Block List and the Block Grid to indicate if it accepts Local and/or Global Blocks. However, as we also see use cases for Block Lists/Grids with both Local and Global Blocks, we want to present this in a friendly way in the UI. This could either be through labels, icons, or both - and should of course work with both the Block List and the Block Grid: 70 | 71 | ![Content Section - block list](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Content%20-%20clean.jpg?raw=true) 72 | ![Content Section - block grid](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Content%20-%20block%20grid.jpg?raw=true) 73 | 74 | ##### Make Global 75 | 76 | We want to ensure a smooth transition between Local and Global Blocks, so that if you have a Local Block that you want to use in more than one Block List or Block Grid, - it should simply be possible to make it global. In this process, you need to give the Block a name and also place it in the correct folder - and the block will afterwards be available in the Library folder: 77 | 78 | ![Content Section - make global](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Content%20-%20make%20global.jpg?raw=true) 79 | 80 | #### Make Local 81 | 82 | While using Global Blocks there might be cases, where the Global Block is almost as you want it - but somehow not 100% the right fit. In these cases, we want to offer an opportunity to make a Block local. By doing this we'll create a new local instance while still keeping the Global Block: 83 | 84 | ![Content Section - make local](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Content%20-%20Make%20local.jpg?raw=true) 85 | 86 | #### Publish content 87 | 88 | With Global Blocks that can have various states and e.g. be unpublished or scheduled for publishing, we want to make it visible for the editor during the publishing of a content node if there are Global Blocks that are either unpublished or scheduled for publishing. As the Global Blocks are published, unpublished, and scheduled individually they will not affect the publishing of a Content Node, but we see the information about these states as important for the editor: 89 | 90 | ![Content Section - publish](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Content%20-%20publish.jpg?raw=true) 91 | 92 | #### Edit block 93 | 94 | The experience of editing a Block in the context of a Content Node should be the same as with Local Blocks today, however, instead of a submit button we want to provide the editor with the option to save, unpublish, schedule, and publish. 95 | 96 | ![Content Section - edit block](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Content%20-%20Edit%20block.jpg?raw=true) 97 | 98 | #### Add block 99 | 100 | We want the editor to be able to decide up-front if she would like to create a new Local/Global Block or add an existing Global Block to the currently selected Block List or Block Grid. If creating a new Global Block, we want that to be done within the Block tree: 101 | 102 | ![Content Section - add block](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Content%20-%20Add%20block.jpg?raw=true) 103 | 104 | #### Language 105 | 106 | As mentioned above, we want to provide the same language opportunities for Global Blocks as for Content Nodes. A Global Block should therefore always be visible in all languages, although its content might fall back to the default language. Contrary, a Local Block - just as it is today - is considered unique for a specific language. 107 | 108 | ![Content Section - add block](https://github.com/umbraco/rfcs/blob/0025-reusable-content-with-global-blocks/cms/assets/global-blocks/Content%20-%20splitview.jpg?raw=true) 109 | 110 | 111 | ### Permissions 112 | 113 | In short, we want to offer the same permissions as exist today on Content Nodes, - meaning that there should be permissions for browse, delete, create, notifications, publish, permission changes, send to publish, unpublish, update, etc. - and that these permissions should be available to set both as default permissions and as specific granular permissions for a node. Also, like with content and media, we want to offer opportunities for limiting the Block Library Tree to a specific start node. 114 | 115 | ## Technical considerations 116 | 117 | We propose creating a similar data structure for Global Blocks as we have it for regular Content Nodes and thereby adding all the same options as with Content Nodes, except for routing. That also means that it should e.g. be possible to find deleted Global Blocks in the recycle bin. 118 | As we think it makes sense to have the Block Settings as something that relates to the specific usage of a Global Block Content, we only consider the Content part to be stored in this “new” structure, whereas we suggest storing the Settings part within the Content Node - as we do it today. 119 | 120 | ## Out of Scope 121 | 122 | Although we mention Tags as part of the new Library section, it's not in the scope of this RFC to discuss moving and updating Tags. 123 | 124 | ### Unresolved issues 125 | 126 | Some of the answers that we hope to get out of this are: 127 | - Related to the technical considerations, if we are right, that it makes most sense to have Block Settings stored within the Content Node or if there are more/better use cases for storing Block Settings globally too. 128 | - In case you work with segments, if you can see any implications in this proposal. 129 | - More perspectives on the proposed new section called “Library”. If it should be there at all and if so what it should include. 130 | - The naming. Should we call it Global Blocks, reusable content or something else. 131 | 132 | ## Contributors 133 | 134 | This RFC was compiled by: 135 | 136 | - Bjarke Berg (Umbrac HQ) 137 | - Jacob Overgaard (Umbraco HQ) 138 | - Filip Bech-Larsen (Umbraco HQ) 139 | - Rune Strand (Umbraco HQ) 140 | - Lasse Fredslund (Umbraco HQ) 141 | 142 | - The CMS Group 143 | - The CMS Community Team 144 | 145 | -------------------------------------------------------------------------------- /cms/0026-blocks-in-the-rte.md: -------------------------------------------------------------------------------- 1 | # Blocks in the RTE 2 | 3 | ### Request for Contribution (RFC) 0026 : Blocks in the Rich Text Editor (RTE) 4 | 5 | **Please comment on this RFC in this [RFC Discussion](https://github.com/umbraco/rfcs/discussions/42)** 6 | 7 | ## Code of Conduct 8 | 9 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md). 10 | 11 | ## Intended Audience 12 | 13 | The intended audience for this RFC is 14 | 15 | - Technical users 16 | - Developers 17 | - Extension developers 18 | - Package authors 19 | 20 | ## Summary 21 | With the new backoffice (Bellissima) currently targeted for Umbraco 14, we want to remove macros and, consequently, with the release of Umbraco 13m deprecate macros and introduce an alternative. 22 | 23 | We have good alternatives to macros in most use cases, but we are still missing the use case where the editor can insert complex content in the Rich Text Editor (RTE) that is styled and controlled by the developer - e.g. inserting a call to action button within the RTE. 24 | 25 | In this RFC we propose a solution for inserting complex content into the RTE based on Blocks. 26 | 27 | ## Motivation 28 | We have for some time wanted to avoid implementing Macros for the New Backoffice, as the approach is a bit misaligned with the current state of Umbraco. We know, that for some developers it has worked fine and used frequently, but for many developers, it has been an approach “a bit out of context” and not as intuitive as we would like it to be. 29 | 30 | We have investigated the usage of macros and identified a few use cases where there currently lacks an alternative to the functionality provided by Macros. 31 | 32 | We believe these remaining use cases are solved by introducing blocks in the RTE. 33 | As we see more and more usage of blocks and e.g. are looking into [Reusable Content with Global Blocks], it makes sense to build this functionality based on blocks so that we can benefit from future improvements and functionality related to blocks. 34 | 35 | ## Detailed Design 36 | We suggest introducing Blocks in the RTE by offering functionality similar to the Block List and the Block Grid editors. 37 | 38 | #### Editor Settings 39 | Like inserting a macro today, we propose an additional button in the RTE toolbar. As with other buttons in the RTE, this should be enabled in the toolbar configuration together with a block configuration where you can choose the block types that should be allowed for this specific instance of the RTE. It could then look something like this: 40 | 41 | ![Editor Settings](assets/blocks-in-the-rte/Settings.png?raw=true) 42 | 43 | #### Configuration of the block 44 | For each block configured to work in the RTE, there should be additional configuration on the block level to choose block appearance, data models (both content- and settings models), and catalog appearance - just like we know it from the block list and the block grid. 45 | 46 | For the first implementation of this feature, we propose not to include custom backoffice views, as it - compared to the expected usage - will be time-consuming to implement. This could be something to consider for later. 47 | 48 | ![Configuration of the block](assets/blocks-in-the-rte/Settings-block-config.png?raw=true) 49 | 50 | #### Button in the RTE toolbar 51 | When the Blocks button is enabled in the RTE toolbar configuration, we suggest a button like the one to the right in the mockup below will be available. 52 | 53 | ![Button in the RTE toolbar](assets/blocks-in-the-rte/RTE.png?raw=true) 54 | 55 | #### Insert block 56 | When clicking on this button, the configured blocks for this instance of the RTE should be selectable in a way similar to the one known from the block list and the block grid. 57 | 58 | ![Insert block](assets/blocks-in-the-rte/Insert.png?raw=true) 59 | 60 | #### Edit block 61 | When inserting the block (or clicking on it later) we should show an edit panel to the right where both content and settings can be edited. 62 | 63 | ![Edit block](assets/blocks-in-the-rte/Edit-content.png?raw=true) 64 | 65 | #### Show the block in the RTE 66 | When inserted, we propose to show the block as a bar/box similar to how we show blocks in the block list and the block grid when they have no custom view. Unlike the macros where you can choose to insert it as inline or not, the block will always be shown inline but can of course be controlled simply by adding paragraphs like shown below. 67 | 68 | ![Show the block in the RTE](assets/blocks-in-the-rte/Content-in-the-rte.png?raw=true) 69 | 70 | ## Technical considerations 71 | We could extend the RTE in other ways than with blocks but believe that by building this on top of the block technology, we open up for benefiting from future block improvements while at the same time ensuring a more aligned developer- and editor experience. 72 | For the Content Delivery API, we propose that blocks should be listed in an array in the Json output and then referenced from within the RTE HTML element. While not used in a headless context, a partial view is needed, just like with blocks for the block list and the block grid. 73 | 74 | ## Out of Scope 75 | We hope to introduce global blocks (as described in the RFC for [Reusable Content with Global Blocks]) but that is not part of this RFC, although we believe that blocks in the RTE should also work with global blocks when these are implemented. 76 | 77 | ### Unresolved issues 78 | The primary purpose of this RFC is to ensure that we with this - and other already existing functionality - have covered all use cases that are today handled by macros. Please let us know if you see use cases for macros that are still not solved. 79 | Also, as described above, we propose blocks without custom views as a starting point but let us know if you see that as a problem. 80 | 81 | ## Contributors 82 | This RFC was compiled by: 83 | 84 | - Bjarke Berg (Umbraco HQ) 85 | - Jacob Overgaard (Umbraco HQ) 86 | - Filip Bech-Larsen (Umbraco HQ) 87 | - Rune Strand (Umbraco HQ) 88 | - Lasse Fredslund (Umbraco HQ) 89 | - The CMS Group 90 | - The CMS Community Team 91 | -------------------------------------------------------------------------------- /cms/0027-the-future-of-search.md: -------------------------------------------------------------------------------- 1 | # The Future of Search 2 | 3 | ### Request for Contribution (RFC) 0027 : The Future of Search 4 | 5 | **Please comment on this RFC in this [RFC Discussion](https://github.com/umbraco/rfcs/discussions/43)** 6 | 7 | ## Code of Conduct 8 | 9 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md). 10 | 11 | ## Intended Audience 12 | 13 | The intended audience for this RFC is 14 | 15 | - Technical users 16 | - Developers 17 | - Extension developers 18 | - Package authors 19 | 20 | ## Summary 21 | 22 | This RFC proposes a new search and indexing abstraction for Umbraco. 23 | This new architecture aims to address limitations with network drive hosting, simplify integrations with advanced search providers, and optimize the index rebuilding process for increased performance. 24 | The proposed abstraction will allow for the use of different search providers, offering greater flexibility and scalability. 25 | It outlines details for both indexing and searching, covering aspects like content variance, protected content, full-text search, filtering, faceting, and an extensible architecture. 26 | This change aims to provide a more robust and performant search experience within Umbraco. 27 | 28 | ## Terminology 29 | 30 | - **Content**: Common denominator for Documents, Media and Members. 31 | - **Search implementation**: An implementation of the search and indexing abstraction for a specific search provider. 32 | - **Search provider**: The underlying search technology for a search implementation (e.g. Elasticsearch). 33 | - **Field**: A container of data in the search index. 34 | 35 | ## Motivation 36 | 37 | For many years, search functionality in Umbraco has relied on Examine, utilizing a standard implementation of Lucene.NET. However, Lucene.NET is known for its issues with hosting on network drives, making deployments on platforms like Azure Web Services particularly challenging. This has required extensive configuration adjustments and has been a frequent source of support cases for Umbraco. 38 | 39 | Additionally, we recognize that many of our partners already use more advanced search providers. As a result, we aim to simplify integrations with these platforms, regardless of the specific technology used. 40 | 41 | Finally, we see an opportunity to optimize the index rebuilding process, enabling it to run more efficiently and faster. 42 | 43 | ## Detailed design 44 | 45 | We plan to introduce a complete new search and indexing abstraction, which will allow for different search providers to be used for searching Umbraco content. 46 | 47 | During our investigation, we have looked into Elasticsearch, Algolia, Meilisearch and Examine (Lucene.NET) as potential search providers. 48 | 49 | We plan the following design, based on the these criteria: 50 | 51 | 1. The abstraction should be easy to use. 52 | 2. It should be possible to implement with any search provider. 53 | 54 | When reading through this, it is important to keep in mind that the search abstraction will cover both backoffice and frontend search. This is the equivalent of what is currently commonly known as search in "internal" and "external" indexes. 55 | 56 | ### Indexing 57 | 58 | We will handling indexing for the search index via cache refreshers. 59 | 60 | This approach allows different search implementations to determine which server roles should perform a task. For all out-of-process search implementations, indexing would only be performed on servers with the `Publisher` role. 61 | 62 | The indexing will support both protected content (public access restrictions) and content variance (culture and segment). 63 | 64 | The indexing will explicitly exclude sensitive data - e.g. property types marked as sensitive. 65 | 66 | Umbraco will be responsible for gathering index data when content changes. This includes the gathering of index data for all relevant related content items - for example: 67 | 68 | - Documents affected by the publishing of an ancestor document. 69 | - Changes made to document protection (public access). 70 | 71 | Subsequently, the index data will be handed off to the search implementation, which is then responsible for updating the search index accordingly. 72 | 73 | #### Required indexes 74 | 75 | We plan on creating four core indexes: 76 | 77 | - **Documents** for end user document search. 78 | - Contains only published document data. 79 | - Replaces the current indexes "external index" and "Delivery API index". 80 | - **Draft Documents** to power the backoffice document search. 81 | - Includes the most recent version of the document. So for a published document with no draft, it will have the published version. For an edited document that has a draft and a published version, the draft will be the one indexed. 82 | - Replaces the current "internal index". 83 | - **Media** to power all media search. 84 | - **Members** to power all member search. 85 | 86 | Note that as of today, media are included in both the "external index" and the "internal index". We want to change this moving forward, as we perceive documents and media as two different things - particularly from a search perspective. 87 | 88 | #### Custom indexes 89 | 90 | It should be possible to define and maintain custom indexes from any Umbraco extension (for example Umbraco Forms). 91 | 92 | #### Storing master data in indexes 93 | 94 | We will _not_ storing master data (commonly known as "stored fields" or "raw fields") within the indexes. 95 | 96 | An index is only meant to be an instrument for querying and resolving IDs for master data records. The actual master data records can subsequently be retrieved from their concrete storage. 97 | 98 | #### Index data per property value 99 | 100 | We will create new property index value factories to generate the property level index data for property editors. This replaces the `IPropertyIndexValueFactory` implementations in the current codebase. 101 | 102 | There will be different property index value factory implementations for different property editors, and they will return a common data format for indexing property data. 103 | 104 | The index data format will include the following: 105 | 106 | - `Texts` (`string[]`) 107 | - `TextsH1` (`string[]`) 108 | - `TextsH2` (`string[]`) 109 | - `TextsH3` (`string[]`) 110 | - `TextsH4` (`string[]`) 111 | - `TextsH5` (`string[]`) 112 | - `TextsH6` (`string[]`) 113 | - `Keywords` (`string[]`) 114 | - `Decimals` (`Decimal[]`) 115 | - `Integers` (`int[]`) 116 | - `DateTimeOffsets` (`DateTimeOffset[]`) 117 | 118 | In this index data format: 119 | 120 | - All `Texts` will be used for full text search. 121 | - The granular division of text types are to be used as "buckets" of text for implementation-specific boosting with a defined order of importance. 122 | - `Keywords`, `Decimals`, `Integers` and `DateTimeOffsets` are meant for filtering and/or faceting. 123 | 124 | The property names in the index data format are likely subject to change, but they will serve as a reference point throughout this RFC. 125 | 126 | We will _not_ provide specifics on how the index data should be indexed (e.g. how to analyze for full text search). We consider this an implementation detail for the individual search implementations, as it varies greatly between providers. 127 | 128 | #### Index data per content item 129 | 130 | All relevant properties of a content item will have their values indexed as per the previous section. 131 | 132 | The property level index data will be passed to the index as individual fields by property type alias, thus allowing for filtering and faceting by property at query time. 133 | 134 | Additionally, the following content level data will be included, using the same index data format: 135 | 136 | - Name (as `TextsH1`) 137 | - Creation date (as `DateTimeOffsets`) 138 | - Update date (as `DateTimeOffsets`) 139 | - Content type alias (as `Keywords`) 140 | - ID (GUID) (as `Keywords`) 141 | - Tags (as `Keywords`) 142 | - All tags accumulated across all property values. 143 | - Ancestor IDs (GUIDs) (as `Keywords`) 144 | - Included to facilitate structural search queries. 145 | 146 | #### Persisting index data in the database 147 | 148 | We propose storing index data in the database, as calculating it can be highly CPU-intensive — particularly for content with deeply nested types, such as block lists within block lists. 149 | 150 | The index data stored in the database is not to be confused with the data stored in the search indexes by the search implementations. Instead, the index data in the database should be considered as the "raw" input for the search implementations. 151 | 152 | By persisting the index data, it only needs to be calculated once per change, even for search implementations that require a search index per machine, such as Examine (Lucene.NET). 153 | 154 | The primary benefit of persisting index data in the database is significantly faster indexing during cold-boot scenarios, where the entire index needs to be rebuilt. 155 | 156 | For regular indexing of individual content items, we anticipate no noticeable difference. 157 | 158 | The only drawback we foresee is an increase in database size by approximately 5-10%, due to this new data. 159 | 160 | ##### Persisted index data format 161 | 162 | The persisted index data will be stored in a new table, similarly to how we store published content today. 163 | 164 | The table will be named `umbracoIndexData` and contain the following columns: 165 | 166 | - `Key`: GUID (primary key) 167 | - `Published`: Bit 168 | - `DataRaw`: Binary (same binary serialization as the published content) 169 | 170 | The `DataRaw` column will contain the serialized index data for all variants of an entire content item. 171 | 172 | #### Indexing protected documents 173 | 174 | _This section applies only to indexing of published documents._ 175 | 176 | Protected documents are configured in Umbraco by specifying the concrete members and/or member groups that should have access to the documents. 177 | 178 | When Umbraco hands off protected documents to be indexed by the search implementation, the configured member and member group IDs (GUIDs) will be passed to the search implementation. The search implementation must either: 179 | 180 | - Index the documents accordingly, so they can be made available for the relevant members at query time, or 181 | - Discard the documents, thus not indexing it at all (effectively not supporting protected documents). 182 | 183 | #### Indexing variants of content 184 | 185 | For variant content, Umbraco will append the relevant variance qualifiers (culture and/or segment) to the index data at property level. The search implementation must either: 186 | 187 | - Index the variance qualifiers, so variant content can be found at query time (given a concrete variant context), or 188 | - Discard (parts of) the variance qualifiers and the corresponding property data (e.g. discard segmented property data if not supporting segmented querying). 189 | 190 | #### Full re-indexing versus partial index updates 191 | 192 | Some search providers support zero downtime for full re-indexing - for example by means of "index swapping". 193 | 194 | Umbraco will be handing off either individual content items or collections of content for indexing, but for large sites it will eventually not be possible to hand off _all_ content in a single operation. However, we still want to support zero downtime re-indexing if at all possible. 195 | 196 | This requires us to introduce an instruction protocol for communicating re-indexing start and end. The specifics are yet to be defined, but it will require some queueing mechanism to ensure atomic operations ("transactions") across multiple batches of content indexing. 197 | 198 | #### Extensibility 199 | 200 | We envision an extension model for indexing, which will allow for changing the default behavior (altering, adding and removing index data before it is sent to the search implementation). 201 | 202 | Part of this extension model will be the property index value factories themselves. They will be interchangeable, so custom indexing can be performed for _all_ properties of a given property editor. 203 | 204 | However, this will not cover all cases, so additional extension points will be called for. These are yet to be defined, but _could_ include: 205 | 206 | - An "also index these items" option to include additional content items for re-indexing when changes are made to specific content. 207 | - A "last minute" option to manipulate all index data for a single content item before it is passed to the search implementation for indexing. 208 | 209 | #### Examples of index data 210 | 211 | See [Appendix A](#appendix-a-example-of-index-data-being-gathered-for-indexing) for a detailed example of index data being gathered for indexing. 212 | 213 | ### Searching 214 | 215 | We are going to defining a search abstraction that covers: 216 | 217 | - Full text search 218 | - Filtering 219 | - Faceting (including range facets) 220 | - Autocomplete/suggestions 221 | - Variance (as defined by Umbraco, by culture and/or segment) 222 | - Protected content (as defined by Umbraco, by concrete principal or group membership) 223 | - Sorting and pagination 224 | 225 | Full text search, filtering and faceting can be used in conjunction with one another. 226 | 227 | The goal is to cover the most common use cases, not to define an exhaustive search abstraction for all search providers. For concrete search provider features outside the scope of the search abstraction, implementors are expected to utilize the search provider directly instead of going through this abstraction. 228 | 229 | #### Example of the search abstraction 230 | 231 | See [Appendix B](#appendix-b-code-example-for-the-search-abstraction) for a code example of what the search abstraction signature _could_ look like. 232 | 233 | #### Full text search 234 | 235 | Full text search will be defined as: 236 | 237 | - A query (`string`) containing one or more words to search for. 238 | - An operator (`enum`) specifying if the words in the query should be matched as `OR` or `AND`. 239 | 240 | The search should be performed across the `Texts` from the property level index data. 241 | 242 | Relevant boosting should be applied for the individual `Texts` data, e.g. ensuring higher search result relevance for data from `TextsH1` than `TextsH4` (where `Texts` is considered of the least relevance value). 243 | 244 | We do _not_ plan to include detailed boosting levels as part of the search abstraction. We consider this an implementation detail for the individual search implementations. 245 | 246 | #### Filtering 247 | 248 | Filtering allows for narrowing down the search results by exact matching against the following from the property level index data: 249 | 250 | - `Keywords`: For exact matches on text. 251 | - `Decimals`: For exact matches on decimal values. 252 | - `Integers`: For exact matches on integer values. 253 | - `DateTimeOffsets`: For exact matches on date and time. 254 | 255 | The abstraction will support: 256 | - Filtering against specific fields, thus narrowing down by content property value. 257 | - For example: The "color" property should have the value "Red". 258 | - Chaining filters in a single query. Filters will be combined with an AND. 259 | - For example: ("color" must be "Red") AND ("price" must be less than 100). 260 | - Providing multiple values per filter. Filter values will be combined with an OR. 261 | - For example: ("color" must be "Red" OR "Blue") AND ("size" must be "M" OR "L"). 262 | 263 | We propose splitting filtering into two parts: 264 | 265 | - **Exact filtering** for concrete filter values. 266 | - For example: "color" is "Red" OR "Blue". 267 | - **Range filtering** for range bound filter values. 268 | - For example: "price" is between 100 AND 200. 269 | 270 | #### Faceting 271 | 272 | From a search abstraction point of view, faceting works in much the same way as filtering; faceting can be performed against the same fields as filtering, and follows the same combination rules. 273 | 274 | Faceting yields the same content results as filtering, but adds facet values to the search result. 275 | 276 | From a search implementation perspective, faceting likely works very differently from filtering, and might incur a performance penalty over filtering. 277 | 278 | We propose splitting faceting into two parts: 279 | 280 | - **Exact faceting** for concrete facet values. 281 | - For example: "color" is "Red" OR "Blue". 282 | - **Range faceting** for range bound facet values. 283 | - For example: "price" is between 100 AND 200. 284 | 285 | #### Autocomplete/suggestions 286 | 287 | We plan to include an optional "suggested next query" in the search results. This can be used by the search implementation to supply options for autocompletion or query suggestions for a given query. 288 | 289 | The "suggested next query" will be a collection of strings, meant to replace or complement the active full text search query (if any). 290 | 291 | #### Variance 292 | 293 | Given a concrete variation context (culture and/or segment), the search implementation should be able to yield content results relevant to this context. 294 | 295 | See the indexing section for more details. 296 | 297 | #### Protected content 298 | 299 | Given the context of a "current principal" (by means of a concrete principal identifier and/or group memberships), the search implementation should be able to include relevant protected content in search results. 300 | 301 | See the indexing section for more details. 302 | 303 | #### Search result 304 | 305 | The search implementation should produce search results that contain: 306 | 307 | - The total number of results. 308 | - The IDs (GUIDs) of the content items within the current result page. 309 | - Matching facets, if any have been requested. 310 | - A collection of "suggested next queries", if any have been requested. 311 | 312 | The search abstraction will resolve the actual content items for results generated by the search implementation - for example, retrieve matching published documents from the cache. 313 | 314 | #### Extensibility 315 | 316 | We also envision an extension model for searching. The details are yet to be defined, but _will likely_ as a minimum include a means to intercept and perform custom handling for all search results. 317 | 318 | ### Graceful degradation 319 | 320 | We expect the search and indexing abstraction to be able to support graceful degradation for unsupported features of a particular search implementation. 321 | 322 | For example, the search implementation might not support: 323 | 324 | - Protected content. 325 | - Segmented content. 326 | - Faceting. 327 | - Autocomplete. 328 | - ... 329 | 330 | It is yet to be determined if this can be covered by search implementation documentation alone, or if we need to include code level support for graceful degradation as well (e.g. marker interfaces like `ISupportFaceting`). 331 | 332 | ### Configuration 333 | 334 | We have not identified any candidates for configuration of the search and indexing abstraction. 335 | 336 | The individual search implementations may allow for search provider specific configuration, but this is considered an implementation detail for this RFC. 337 | 338 | ## Out of Scope 339 | 340 | We plan to ship a single implementation of the search abstraction, which will be based on Examine to be backward compatible. We will not implement other search providers for the initial release. 341 | 342 | The following index values have been identified as potential candidates for future extension, but will not be included in the initial release: 343 | 344 | - `GeoPoints` (`GeoPoint[]`) 345 | - `Dates` (`DateOnly[]`) 346 | - `Times` (`TimeOnly[]`) 347 | - `Booleans` (`bool[]` or maybe `string[]`) 348 | ## Contributors 349 | 350 | This RFC was compiled by: 351 | 352 | - Bjarke Berg (Umbraco HQ) 353 | - Kenn Jacobsen (Umbraco HQ) 354 | 355 | ## Appendix A: Example of index data being gathered for indexing. 356 | 357 | As mentioned, a property editor defines its own property index value factory for generating values for indexing. The following exemplifies how this will work. 358 | 359 | In this example, we are indexing a document with: 360 | 361 | - Name: Hitchhiker's Guide 362 | - Document type alias: bookPage 363 | - Created at: 2024-11-27 12:00:00 364 | - Last updated at: 2024-11-27 14:30:00 365 | - ID: 0e88ec21-dc56-4f8c-8247-40f72b2fd676 366 | - Ancestor IDs: [33d41c8b-f541-4237-96ed-c5c85d4c3edd, 5ce303c9-8e0f-41cd-80d8-3f7906604e6a] 367 | 368 | ...and the following properties: 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 462 | 463 | 464 | 465 | 466 | 519 | 520 |
AliasTypeValue
titleUmbraco.TextBoxThe Hitchhiker's Guide to the Galaxy
featuredUmbraco.Toggletrue
pagesUmbraco.Integer255
publishedUmbraco.DateTime1979-10-12
isbn13Umbraco.TextBox9780330258647
genreUmbraco.Tags[Science Fiction, Comedy]
subjectsUmbraco.MultipleTextstring[Travel, Philosophy, Towels]
priceUmbraco.Decimal119.95
scoreUmbraco.Slider[7.8, 9.3]
abstractUmbraco.RichText 425 |
426 | <h1>A brilliant read</h1>
427 | <p>This is the first book.</p>
428 | <umb-rte-block (RTE block 1)/>
429 | <h2>Science Fiction</h2>
430 | <p>A trilogy of five books.</p>
431 | 
432 |
433 | RTE block 1 (element type alias: relatedBook) 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 |
AliasTypeValue
headingUmbraco.TextBoxFancy a bite?
textUmbraco.TextAreaCheck The Restaurant at the End of the Universe
tagsUmbraco.Tags[Related, Sequel]
subjectsUmbraco.MultipleTextstring[Food, Restaurant, Universe]
461 |
blocksUmbraco.BlockList 467 | Block 1 (element type alias: characterBlock) 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 |
AliasTypeValue
titleUmbraco.TextBoxArthur Dent
textUmbraco.RichText 483 |
484 | <h1>Earthman and Englishman</h1>
485 | <p>Arthur is mostly harmless.</p>
486 | 
487 |
imageUmbraco.MediaPicker34414b7e4-7d41-45b2-9e41-d2085ed995bf
characterUmbraco.DropDown.FlexibleMain
500 | Block 2 (element type alias: teaserBlock) 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 |
AliasTypeValue
headingUmbraco.TextBoxLike poems?
textUmbraco.TextAreaBe careful with Vogon poetry!
518 |
521 | 522 | The resulting index data is listed in the table below. 523 | 524 | Note that "system fields" (like document name and creation date) are included here with an "umb_" prefix. The final prefix is yet to be decided, but there _will_ be a prefix to tell system fields apart from regular document properties. 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 617 | 624 | 625 | 626 | 627 | 634 | 640 | 641 |
NameValueRemarks
umb_typeKeywords: ["bookPage"]The document type alias is indexed as a keyword.
umb_nameTextsH1: ["Hitchhiker's Guide"]The document name is indexed as the most significant headline.
umb_createDateDateTimesOffsets: ["2024-11-27 12:00:00"]
umb_updateDateDateTimeOffsets: ["2024-11-27 14:30:00"]
umb_tagsKeywords: ["Related", "Sequel", "Science Fiction", "Comedy"]All tags on the page (including those in nested property editors) are indexed as individual keywords.
umb_idKeywords: ["0e88ec21-dc56-4f8c-8247-40f72b2fd676"]
umb_ancestorsKeywords: ["33d41c8b-f541-4237-96ed-c5c85d4c3edd", "5ce303c9-8e0f-41cd-80d8-3f7906604e6a"]
titleTexts: ["The Hitchhiker's Guide to the Galaxy"]Raw text inputs are indexed as lowest value text.
pagesIntegers: [255]
publishedDateTimeOffsets: ["1979-10-12"]
isbn13Texts: ["9780330258647"]
genreKeywords: ["Science Fiction", "Comedy"]Tags are indexed as keywords.
subjectsTexts: ["Travel", "Philosophy", "Towels"]Multiple textstrings are indexed as individual items (lowest value text).
priceDecimals: [119.95]
scoreDecimals: [7.8, 9.3]
abstract 610 |
    611 |
  • TextsH1: ["A brilliant read"]
  • 612 |
  • TextsH2: ["Science Fiction"]
  • 613 |
  • Texts: ["This is the first book.", "A trilogy of five books.", "Fancy a bite?", "Check The Restaurant at the End of the Universe", "Food", "Restaurant", "Universe"]
  • 614 |
  • Keywords: ["Related", "Sequel"]
  • 615 |
616 |
618 |
    619 |
  • The RTE takes headings into account, e.g. indexing H1 tags highest value texts.
  • 620 |
  • Block properties are indexed as part of the RTE, adhering to their own indexing rules (i.e. tags become keywords).
  • 621 |
  • Block document type aliases are not indexed.
  • 622 |
623 |
blocks 628 |
    629 |
  • TextsH1: ["Earthman and Englishman"]
  • 630 |
  • Texts: ["Arthur Dent", "Arthur is mostly harmless.", "Like poems?", "Be careful with Vogon poetry!"]
  • 631 |
  • Keywords: ["Main"]
  • 632 |
633 |
635 |
    636 |
  • The media picker is not indexed.
  • 637 |
  • Fixed value selectors (dropdowns, radiobutton groups etc.) are indexed as keywords.
  • 638 |
639 |
642 | 643 | The following table shows an example of how the default index data could be altered by means of extension points. 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 741 | 742 | 743 | 744 | 745 | 753 | 759 | 760 |
NameValueChanges from default
umb_typeKeywords: ["bookPage"]
umb_nameTextsH3: ["Hitchhiker's Guide"]The document name has been given lesser text value (from TextsH1 to TextsH3).
umb_createDateDateTimesOffsets: ["2024-11-27 12:00:00"]
umb_updateDateDateTimeOffsets: ["2024-11-27 14:30:00"]
umb_tagsKeywords: ["Related", "Sequel", "Science Fiction", "Comedy", "Robots"]An extra tag ("Robots") has been added to the collection of page tags.
umb_idKeywords: ["0e88ec21-dc56-4f8c-8247-40f72b2fd676"]
umb_ancestorsKeywords: ["33d41c8b-f541-4237-96ed-c5c85d4c3edd", "5ce303c9-8e0f-41cd-80d8-3f7906604e6a"]
titleTextsH4: ["The Hitchhiker's Guide to the Galaxy"]The property value has been moved to a higher value text (from Texts to TextsH4).
featuredKeywords: ["featured"]The toggle (boolean) is omitted by default, but has been included as a keyword here.
pagesIntegers: [255]
publishedDateTimeOffsets: ["1979-10-12"]
isbn13Keywords: ["9780330258647", "0330258648"]The ISBN 13 has been turned into a keyword, and the corresponding ISBN 10 has been added.
genreKeywords: ["Science Fiction", "Comedy"]
subjectsTexts: ["Travel", "Philosophy", "Towels"]
priceDecimals: [119.95]
scoreDecimals: [7.8, 9.3]
abstract 734 |
    735 |
  • TextsH1: ["A brilliant read", "Fancy a bite?"]
  • 736 |
  • TextsH2: ["Science Fiction"]
  • 737 |
  • Texts: ["This is the first book.", "A trilogy of five books.", "Check The Restaurant at the End of the Universe", "Food", "Restaurant", "Universe"]
  • 738 |
  • Keywords: ["Related", "Sequel"]
  • 739 |
740 |
The "heading" property value from the block has been moved to higher value text (from Texts to TextsH1).
blocks 746 |
    747 |
  • TextsH1: ["Earthman and Englishman"]
  • 748 |
  • TextsH4: ["Arthur Dent"]
  • 749 |
  • Texts: ["Arthur is mostly harmless.", "Like poems?", "Be careful with Vogon poetry!", "Portrait of Author Dent in front of a spaceship"]
  • 750 |
  • Keywords: ["Main"]
  • 751 |
752 |
754 |
    755 |
  • The "title" property value from the block has been moved to higher value text (from Texts to TextsH4).
  • 756 |
  • The media picker ALT text (a property value from the picked media) has been added to Texts ("Portrait of...").
  • 757 |
758 |
761 | 762 | ## Appendix B: Code example for the search abstraction 763 | 764 | The following is an example of what the search abstraction signature _could_ look like. 765 | 766 | This is not necessarily how the final version will be implemented. It is meant as a supplement to illustrate the points made in this RFC. 767 | 768 | ```csharp 769 | public PagedSearchResult Search( 770 | VariantFilter variantFilter, 771 | FullTextFilter? fullTextFilter = null, 772 | IEnumerable? filters = null, 773 | IEnumerable? facets = null, 774 | PrincipalFilter? principalFilter = null, 775 | Suggest? suggest = null, 776 | Sort? sort = null, 777 | int skip = 0, 778 | int take = 10 779 | ) 780 | { 781 | // ... 782 | } 783 | 784 | public class VariantFilter 785 | { 786 | // nulls means invariant 787 | public string? Culture { get; set; } // null = invariant 788 | 789 | // null means default (no) segment 790 | public string? Segment { get; set; } 791 | } 792 | 793 | public enum FullTextFilterQueryOperator 794 | { 795 | Or, 796 | And 797 | } 798 | 799 | public class FullTextFilter 800 | { 801 | // query to be analyzed 802 | public required string Query { get; set; } 803 | 804 | // operator to use between the words in the query 805 | public FullTextFilterQueryOperator Operator { get; set; } = FullTextFilterQueryOperator.Or; 806 | } 807 | 808 | public static class SystemFields 809 | { 810 | public const string Name = "umb_name"; 811 | public const string Id = "umb_id"; 812 | public const string CreateDate = "umb_created"; 813 | public const string UpdateDate = "umb_updated"; 814 | public const string ContentType = "umb_type"; 815 | public const string Ancestors = "umb_ancestors"; 816 | } 817 | 818 | public enum FilterOperator 819 | { 820 | Is, 821 | IsNot 822 | } 823 | 824 | public abstract class Filter 825 | { 826 | // the index field name (system field or property alias) 827 | public required string Field { get; set; } 828 | } 829 | 830 | public abstract class ExactFilter : Filter 831 | { 832 | // operator to use against the filter values 833 | public FilterOperator Operator { get; set; } = FilterOperator.Is; 834 | 835 | // the filter values (OR filtering applies if multiple values are specified) 836 | public required IEnumerable Values { get; set; } 837 | } 838 | 839 | public class StringExactFilter : ExactFilter {} 840 | 841 | public class IntegerExactFilter : ExactFilter {} 842 | 843 | public class DecimalExactFilter : ExactFilter {} 844 | 845 | public class DateTimeOffsetExactFilter : ExactFilter {} 846 | 847 | public class GuidExactFilter : ExactFilter {} 848 | 849 | public abstract class RangeFilter : Filter 850 | { 851 | // null means "no lower bounds" 852 | public T? MinValue { get; set; } 853 | 854 | // null means "no upper bounds" 855 | public T? MaxValue { get; set; } 856 | } 857 | 858 | public class IntegerRangeFilter : RangeFilter {} 859 | 860 | public class DecimalRangeFilter : RangeFilter {} 861 | 862 | public class DateTimeOffsetRangeFilter : RangeFilter {} 863 | 864 | public abstract class Facet 865 | { 866 | // the index field name (system field or property alias) 867 | public required string Field { get; set; } 868 | } 869 | 870 | public abstract class ExactFacet : Facet 871 | { 872 | // the facet values to filter by (OR filtering applies if multiple values are specified) 873 | public required IEnumerable Values { get; set; } 874 | } 875 | 876 | public class StringExactFacet : ExactFacet {} 877 | 878 | public class IntegerExactFacet : ExactFacet {} 879 | 880 | public class DecimalExactFacet : ExactFacet {} 881 | 882 | public class DateTimeOffsetExactFacet : ExactFacet {} 883 | 884 | public abstract class RangeFacet : Facet 885 | { 886 | // null means "no lower bounds" 887 | public T? MinValue { get; set; } 888 | 889 | // null means "no upper bounds" 890 | public T? MaxValue { get; set; } 891 | } 892 | 893 | public class IntegerRangeFacet : RangeFacet {} 894 | 895 | public class DecimalRangeFacet : RangeFacet {} 896 | 897 | public class DateTimeOffsetRangeFacet : RangeFacet {} 898 | 899 | public class PrincipalFilter 900 | { 901 | // the principal identifier 902 | public required Guid Id { get; set; } 903 | 904 | // the group memberships of the principal 905 | public required IEnumerable Groups { get; set; } 906 | } 907 | 908 | public enum SortDirection 909 | { 910 | Ascending = 0, 911 | Descending = 1, 912 | } 913 | 914 | public class Suggest 915 | { 916 | // whether to include "suggested next queries" in the search result 917 | public bool SuggestNextQuery { get; set; } = false; 918 | } 919 | 920 | public class Sort 921 | { 922 | public SortDirection Direction { get; set; } = SortDirection.Descending; 923 | 924 | // the index field name (system field or property alias) - null means default (relevance) 925 | public string? Key { get; set; } = null; 926 | } 927 | 928 | public class PagedSearchResult 929 | { 930 | public int TotalCount { get; set; } 931 | 932 | public required IEnumerable Results { get; set; } 933 | 934 | public IEnumerable? FacetResults { get; set; } 935 | 936 | public IEnumerable? SuggestedNextQuery { get; set; } 937 | } 938 | 939 | public class SearchResult 940 | { 941 | public required Guid Id { get; set; } 942 | } 943 | 944 | public abstract class FacetResult 945 | { 946 | // the index field name (system field or property alias) - null means default (relevance) 947 | public required string Field { get; set; } 948 | } 949 | 950 | public abstract class ExactFacetResult : FacetResult 951 | { 952 | // the available facet values for the query results 953 | public required IEnumerable> Values { get; set; } 954 | } 955 | 956 | public abstract class ExactFacetResultValue 957 | { 958 | // the value in the index 959 | public required T Value { get; set; } 960 | 961 | // number of hits for this facet value 962 | public required int Count { get; set; } 963 | } 964 | 965 | public class StringExactFacetResult : ExactFacetResult {} 966 | 967 | public class IntegerExactFacetResult : ExactFacetResultValue {} 968 | 969 | public class DecimalExactFacetResult : ExactFacetResultValue {} 970 | 971 | public class DateTimeOffsetExactFacetResult : ExactFacetResultValue {} 972 | 973 | public abstract class RangeFacetResult : FacetResult 974 | { 975 | // the lower bounds in the index 976 | public T? MinValue { get; set; } 977 | 978 | // the upper bounds in the index 979 | public T? MaxValue { get; set; } 980 | } 981 | 982 | public class IntegerRangeFacetResult : RangeFacetResult {} 983 | 984 | public class DecimalRangeFacetResult : RangeFacetResult {} 985 | 986 | public class DateTimeOffsetRangeFacetResult : RangeFacetResult {} 987 | ``` 988 | 989 | -------------------------------------------------------------------------------- /cms/assets/GridStyleexamples1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/GridStyleexamples1.jpg -------------------------------------------------------------------------------- /cms/assets/GridStyleexamples2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/GridStyleexamples2.jpg -------------------------------------------------------------------------------- /cms/assets/GridStyleexamples3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/GridStyleexamples3.jpg -------------------------------------------------------------------------------- /cms/assets/GridStyleexamples4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/GridStyleexamples4.jpg -------------------------------------------------------------------------------- /cms/assets/GridStyleexamples5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/GridStyleexamples5.jpg -------------------------------------------------------------------------------- /cms/assets/blocks-in-the-rte/Content-in-the-rte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/blocks-in-the-rte/Content-in-the-rte.png -------------------------------------------------------------------------------- /cms/assets/blocks-in-the-rte/Edit-content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/blocks-in-the-rte/Edit-content.png -------------------------------------------------------------------------------- /cms/assets/blocks-in-the-rte/Insert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/blocks-in-the-rte/Insert.png -------------------------------------------------------------------------------- /cms/assets/blocks-in-the-rte/RTE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/blocks-in-the-rte/RTE.png -------------------------------------------------------------------------------- /cms/assets/blocks-in-the-rte/Settings-block-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/blocks-in-the-rte/Settings-block-config.png -------------------------------------------------------------------------------- /cms/assets/blocks-in-the-rte/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/blocks-in-the-rte/Settings.png -------------------------------------------------------------------------------- /cms/assets/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/diagram.png -------------------------------------------------------------------------------- /cms/assets/global-blocks/Content - Add block.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Content - Add block.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Content - Edit block.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Content - Edit block.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Content - Make local.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Content - Make local.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Content - block grid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Content - block grid.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Content - clean.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Content - clean.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Content - make global.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Content - make global.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Content - publish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Content - publish.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Content - splitview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Content - splitview.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Library - Preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Library - Preview.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Library - clean.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Library - clean.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Library - info.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Library - info.jpg -------------------------------------------------------------------------------- /cms/assets/global-blocks/Library - language.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/global-blocks/Library - language.jpg -------------------------------------------------------------------------------- /cms/assets/project-structure-Current.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/project-structure-Current.png -------------------------------------------------------------------------------- /cms/assets/project-structure-Proposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umbraco/rfcs/eb744bcd37175e51bff72a24af247300cc291925/cms/assets/project-structure-Proposed.png -------------------------------------------------------------------------------- /docs/0009-rfc-styleguide.md: -------------------------------------------------------------------------------- 1 | # RFC Style Guide for Documentation 2 | 3 | Request for Contribution (RFC) 0009 : _Style guide for documentation_ 4 | 5 | ## Code of Conduct 6 | 7 | Please read and respect the [RFC Code of Conduct](https://github.com/umbraco/rfcs/blob/master/CODE_OF_CONDUCT.md) 8 | 9 | ## Intended Audience 10 | 11 | The intended audience for this RFC is: 12 | 13 | * Documentation contributors 14 | * HQ developers 15 | 16 | ## Summary 17 | 18 | What kind of voice, language and punctuation rules should 'guide' contribution to the Umbraco documentation. 19 | 20 | ## Motivation 21 | 22 | * Provide a consistent writing style and tone of voice to improve readability and ultimately comprehension of information. 23 | * Make first-time contributors feel more confident on the approach to creating documentation. 24 | * Help curators evaluate contributions consistently. 25 | 26 | ## Detailed Design 27 | 28 | ### Usage of language 29 | 30 | 31 | 32 | The audience for Umbraco documentation includes many where English is not their native language. Therefore documentation should be written with an international audience in mind. The used language should be simple and easy to understand. 33 | 34 | 35 | 36 | If in doubt, the document [How to write plain English](http://www.plainenglish.co.uk/files/howto.pdf) from plainenglish.co.uk, gives a good idea on what we expect. 37 | 38 | In summary: 39 | 40 | * Use short words 41 | * Use everyday English 42 | * Keep sentence length down 43 | * Prefer active verbs 44 | * Use lists where appropriate 45 | * Annotate screenshots for accessibility 46 | 47 | #### Tone of voice 48 | 49 | Language should be friendly and direct. But not intimidating. 50 | You can address the reader if you are telling a story, eg as part of a Tutorial - but should avoid this in most parts of the documentation. 51 | 52 | Where possible documentation should be gender neutral. 53 | 54 | Not all humor/humour translates, not all cultures have the same sense of humor or will understand sarcasm in the same way, therefore documentation should be written neutrally. 55 | 56 | There are different types of documentation, reference, tutorial etc - leading by 'code examples' is an international approach. 57 | 58 | Unless writing a tutorial, we should try to avoid... "you then have to do this, then set this, and then you do this". Try to avoid addressing the reader as 'you' - focus the writing on the words which describe the steps or details of the documentation. 59 | Tutorials are slightly different, here the language needs to take the reader on a journey through the tutorial. 60 | 61 | #### Words to avoid 62 | 63 | Categories of words we like to avoid are: 64 | 65 | 66 | 67 | * Negative words (like swearing) or words which are known to have a negative context. 68 | * Words can make the user feel stupid, therefore try avoiding the following connecting words: simply, just, of course and obviously. 69 | 70 | 71 | 72 | ### Layout rules 73 | 74 | * Making pages follow a consistent layout will mean regular visitors to the documentation will learn the conventions, and improve the experience of interacting with the documentation. 75 | * Consider different 'journeys' to access documentation - introduction, deep dive or quick reference lookup. 76 | * Embedding of screenshots - consistent annotation approach. 77 | * Informative Tips and Warnings - styled and delivered consistently. 78 | 79 | ### Navigation 80 | 81 | * Clear language in navigation structure, leading visitors through the documentation. 82 | * Landing pages for sections and topics. 83 | 84 | #### Code examples 85 | 86 | Make sure the examples are marked appropriately in order to have correct syntax highlighting. 87 | 88 | * Examples should not contain foreign languages for variables. 89 | * Try to adhere to the [.editorconfig](https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/.editorconfig) style rules from the Umbraco-CMS repository. 90 | * Code examples should not contain any commercial references like company names other than Umbraco. 91 | 92 | #### Tutorial markup 93 | 94 | To ensure easy to follow tutorials the following styles will be required in any written text of the tutorial: 95 | 96 | - Use _**Bold Italic**_ for specific terms. Examples: Content Node; Property Editor; Document Type 97 | - Use "Exact Text" to indicate UI items for when they need to click on it or when you are referencing them 98 | - Use "Input value" for things you want readers to type into inputs 99 | - Use `Inline code` for names of properties, methods, namespaces, etc. 100 | 101 | ### Method of enforcement 102 | 103 | With the tooling like [Vale](https://errata-ai.github.io/vale/) we are able to enforce rules. Contributors should be able to checkout the documentation repository for the Our documentation and check whether or not it can pass the enforced rules. 104 | 105 | The Github repo could have (currently in development) a health check on every commit to be sure that commit adheres to the rules. 106 | 107 | In addition to automated tooling, the documentation curator team will use the style guide when reviewing documentation additions. 108 | 109 | #### Suggested Vale rules 110 | 111 | We have set up some suggested rules based on best practises and limiting the impact they will have for contributors: 112 | 113 | 114 | 115 | 116 | - **HeadingsPunctuation**: Warns you when using punctuation at the end of a heading 117 | - **Hyperbolic**: Warns you when using words such as _simple, just, easily and actually_ 118 | - **ListStart**: Warns you when starting a list option with lower case 119 | - **SentenceLength**: Warns you when writing sentences with more than 40 words in them 120 | - **Spacing**: Warns you when having more than 1 space in succession in an article 121 | - **Terms**: Warns you when using a blacklisted term and suggests a replacement - could be from _back-office_ to _backoffice_ 122 | 123 | 124 | 125 | 126 | ## Drawbacks 127 | 128 | * It might be intimidating if contributors try to submit documentation and receive errors after submitting a PR. 129 | * It might be demotivating if the errors appear to be 'trivial' to the contributor - particularly if the contributor is providing information that is completely missing from the documentation. We don't want the reputation that you have to jump through hoops to contribute - and so how the guide is applied is therefore important. 130 | * It might be off-putting for people where English is not their native language. 131 | * The rules might be too strict - and automated issues are flagged with parts of the contribution that are technical terms e.g. errors with code examples. 132 | * It might be limiting if there are too many rules to adhere to. 133 | 134 | ## Alternatives 135 | 136 | There are currently no alternatives... other than continuing without a style guide and manually reviewing submissions for perceived quality. 137 | 138 | ## Out of Scope 139 | 140 | * Discussing tooling, this is an RFC about the content of a style guide. 141 | 142 | ## Unresolved Issues 143 | 144 | The answers that we are hoping to get from the community & Umbraco HQ is: 145 | 146 | * Is a style guide a good idea? 147 | * What sort of rules should be enforced? 148 | * What rules should not be enforced? 149 | * If multi-lingual documentation is introduced how could style guides be managed per language? 150 | * Would having a style guide make a difference to whether you would be more or less likely to contribute to the community documentation? 151 | 152 | ## Related RFCs 153 | 154 | * There are no related RFCs 155 | 156 | ## Contributors 157 | 158 | This RFC was compiled by: 159 | 160 | * Jeavon Leopold 161 | * Lotte Pitcher 162 | * Jesper Mayntzhusen 163 | * Damiaan Peeters 164 | * Marc Goodson 165 | * Sofie Toft Kristensen 166 | --------------------------------------------------------------------------------